diff --git a/CHANGELOG.md b/CHANGELOG.md index 54a4ae5c926..c46edf12c61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,21 +1,54 @@ # Changelog -## 23.4.5 +## 23.7.1 ### Breaking Changes +- Add ABI-decoded revert reason to `eth_call` and `eth_estimateGas` responses [#5705](https://github.com/hyperledger/besu/issues/5705) + +### Additions and Improvements +- Added `benchmark` subcommand to `evmtool` [#5754](https://github.com/hyperledger/besu/issues/5754) +- JSON output is now compact by default. This can be overridden by the new `--json-pretty-print-enabled` CLI option. [#5766](https://github.com/hyperledger/besu/pull/5766) + +### Bug Fixes +- Make smart contract permissioning features work with london fork [#5727](https://github.com/hyperledger/besu/pull/5727) +- Add type to PendingTransactionDetail, fix eth_subscribe [#5729](https://github.com/hyperledger/besu/pull/5729) +- EvmTool "run" mode did not reflect contracts created within the transaction. [#5755](https://github.com/hyperledger/besu/pull/5755) +- Update native libraries that have JPMS friendly module names [#5749](https://github.com/hyperledger/besu/pull/5749) +- Fixing snapsync issue with forest during the heal step [#5776](https://github.com/hyperledger/besu/pull/5776) + +### Download Links + + +## 23.7.0 + +### Breaking Changes +- Removed deprecated GoQuorum permissioning interop [#5607](https://github.com/hyperledger/besu/pull/5607) +- Removed support for version 0 of the database as it is no longer used by any active node. [#5698](https://github.com/hyperledger/besu/pull/5698) + ### Additions and Improvements +- `evmtool` launcher binaries now ship as part of the standard distribution. [#5701](https://github.com/hyperledger/besu/pull/5701) - EvmTool now executes the `execution-spec-tests` via the `t8n` and `b11r`. See the [README](ethereum/evmtool/README.md) in EvmTool for more instructions. - Improve lifecycle management of the transaction pool [#5634](https://github.com/hyperledger/besu/pull/5634) +- Add extension points in AbstractCreateOperation for EVM libraries to react to contract creations [#5656](https://github.com/hyperledger/besu/pull/5656) +- Update to Tuweni 2.4.2. [#5684](https://github.com/hyperledger/besu/pull/5684) +- Decouple data field from Enum JsonRpcError by creating new enum holder RpcErrorType[#5629](https://github.com/hyperledger/besu/pull/5629) +- Update to bouncycastle 1.75 [#5675](https://github.com/hyperledger/besu/pull/5675) +- Extend OperationTracer with new methods [#5662](https://github.com/hyperledger/besu/pull/5662) +- Eip 6780 selfdestruct [#5430](https://github.com/hyperledger/besu/pull/5430) +- Add new debug_getRawTransaction to the DEBUG engine [#5635](https://github.com/hyperledger/besu/pull/5635) ### Bug Fixes - Use the node's configuration to determine if DNS enode URLs are allowed in calls to `admin_addPeer` and `admin_removePeer` [#5584](https://github.com/hyperledger/besu/pull/5584) - Align the implementation of Eth/68 `NewPooledTransactionHashes` to other clients, using unsigned int for encoding size. [#5640](https://github.com/hyperledger/besu/pull/5640) - Failure at startup when enabling layered txpool before initial sync done [#5636](https://github.com/hyperledger/besu/issues/5636) +- Remove miner-related option warnings if the change isn't using Ethash consensus algorithm [#5669](https://github.com/hyperledger/besu/pull/5669) +- Fix for pending transactions reference leak [#5693](https://github.com/hyperledger/besu/pull/5693) ### Download Links +https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/23.7.0/besu-23.7.0.tar.gz / sha256: 083efc26e22fa20bd04c9a6311e50dd93092f001e5d639d023fd7a61173616dd +https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/23.7.0/besu-23.7.0.zip / sha256: 019a5ce3b7b94e76a6bac08bc23e3fec9880e235928b3c5378541927690046d7 ---- ## 23.4.4 diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 94f3ff3da0d..e5bd1814983 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -24,14 +24,12 @@ | Joshua Fernandes | joshuafernandes | joshuafernandes | | Lucas Saldanha | lucassaldanha | lucassaldanha | | Sally MacFarlane | macfarla | macfarla | -| Mark Terry | mark-terry | m.terry | | Karim Taam | matkt | matkt | | Meredith Baxter | mbaxter | mbaxter | | Stefan Pingel | pinges | pinges | | Danno Ferrin | shemnon | shemnon | | Simon Dudley | siladu | siladu | | Usman Saleem | usmansaleem | usmansaleem | -| Zhenyang Shi | wcgcyx | wcgcyx | ## Emeritus Maintainers @@ -47,6 +45,7 @@ | Frank Li | frankisawesome | frankliawesome | | Ivaylo Kirilov | iikirilov | iikirilov | | Madeline Murray | MadelineMurray | madelinemurray | +| Mark Terry | mark-terry | m.terry | | Nicolas Massart | NicolasMassart | NicolasMassart | | Trent Mohay | rain-on | trent.mohay | | Rai Sur | RatanRSur | ratanraisur | @@ -55,6 +54,7 @@ | Taccat Isid | taccatisid | taccatisid | | Tim Beiko | timbeiko | timbeiko | | Vijay Michalik | vmichalik | VijayMichalik | +| Zhenyang Shi | wcgcyx | wcgcyx | ## Becoming a Maintainer diff --git a/acceptance-tests/dsl/build.gradle b/acceptance-tests/dsl/build.gradle index d65de08b954..7aff9aaffb5 100644 --- a/acceptance-tests/dsl/build.gradle +++ b/acceptance-tests/dsl/build.gradle @@ -36,9 +36,9 @@ dependencies { implementation 'io.vertx:vertx-core' implementation 'junit:junit' implementation 'io.opentelemetry:opentelemetry-api' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-io' - implementation 'org.apache.tuweni:tuweni-units' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-io' + implementation 'io.tmio:tuweni-units' implementation 'org.assertj:assertj-core' implementation 'org.awaitility:awaitility' implementation 'org.java-websocket:Java-WebSocket' diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/BlockUtils.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/BlockUtils.java index 6f88c3a6ead..a24280b0ed3 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/BlockUtils.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/BlockUtils.java @@ -56,6 +56,7 @@ public static BlockHeader createBlockHeader( null, null, null, + null, blockHeaderFunctions); } } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/condition/priv/ExpectJsonRpcError.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/condition/priv/ExpectJsonRpcError.java index f3309033250..a642a2731c9 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/condition/priv/ExpectJsonRpcError.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/condition/priv/ExpectJsonRpcError.java @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.tests.acceptance.dsl.condition.Condition; import org.hyperledger.besu.tests.acceptance.dsl.node.Node; import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction; @@ -34,6 +35,10 @@ public ExpectJsonRpcError(final Transaction transaction, final JsonRpcError e this.error = error; } + public ExpectJsonRpcError(final Transaction transaction, final RpcErrorType error) { + this(transaction, new JsonRpcError(error)); + } + @Override public void verify(final Node node) { try { diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/condition/priv/PrivConditions.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/condition/priv/PrivConditions.java index 72d365cfb60..a9a165c68b8 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/condition/priv/PrivConditions.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/condition/priv/PrivConditions.java @@ -16,7 +16,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.privacy.PrivateTransaction; import org.hyperledger.besu.tests.acceptance.dsl.condition.Condition; import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction; @@ -109,7 +109,7 @@ public Condition getInvalidTransactionReceipt(final Hash transactionHash) { } public Condition multiTenancyValidationFail( - final Transaction transaction, final JsonRpcError error) { + final Transaction transaction, final RpcErrorType error) { return new ExpectJsonRpcError(transaction, error); } } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java index fb6ac5f1014..e3cdaefe089 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java @@ -398,7 +398,7 @@ public BesuNode createIbft2NodeWithLocalAccountPermissioning( config.setAccountAllowlist(accountAllowList); config.setAccountPermissioningConfigFilePath(configFile.getAbsolutePath()); final PermissioningConfiguration permissioningConfiguration = - new PermissioningConfiguration(Optional.of(config), Optional.empty(), Optional.empty()); + new PermissioningConfiguration(Optional.of(config), Optional.empty()); return create( new BesuNodeConfigurationBuilder() .name(name) diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/permissioning/PermissionedNodeBuilder.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/permissioning/PermissionedNodeBuilder.java index 8dafc14d77f..ab15f63a30e 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/permissioning/PermissionedNodeBuilder.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/permissioning/PermissionedNodeBuilder.java @@ -186,7 +186,7 @@ public BesuNode build() { } final PermissioningConfiguration permissioningConfiguration = - new PermissioningConfiguration(localPermConfig, smartContractPermConfig, Optional.empty()); + new PermissioningConfiguration(localPermConfig, smartContractPermConfig); final BesuNodeConfigurationBuilder builder = new BesuNodeConfigurationBuilder(); builder diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/account/AccountTransactions.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/account/AccountTransactions.java index 070b74d637b..552251963e3 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/account/AccountTransactions.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/account/AccountTransactions.java @@ -15,7 +15,7 @@ package org.hyperledger.besu.tests.acceptance.dsl.transaction.account; import org.hyperledger.besu.crypto.SignatureAlgorithm; -import org.hyperledger.besu.plugin.data.TransactionType; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.tests.acceptance.dsl.account.Account; import org.hyperledger.besu.tests.acceptance.dsl.account.Accounts; import org.hyperledger.besu.tests.acceptance.dsl.blockchain.Amount; diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/account/TransferTransaction.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/account/TransferTransaction.java index 5a330bf27f6..5c3993b18b6 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/account/TransferTransaction.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/account/TransferTransaction.java @@ -16,7 +16,7 @@ import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.plugin.data.TransactionType; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.tests.acceptance.dsl.account.Account; import org.hyperledger.besu.tests.acceptance.dsl.blockchain.Amount; import org.hyperledger.besu.tests.acceptance.dsl.transaction.NodeRequests; diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/account/TransferTransactionBuilder.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/account/TransferTransactionBuilder.java index b1bb3a0ad12..1d859694440 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/account/TransferTransactionBuilder.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/account/TransferTransactionBuilder.java @@ -18,7 +18,7 @@ import org.hyperledger.besu.crypto.SECP256K1; import org.hyperledger.besu.crypto.SignatureAlgorithm; -import org.hyperledger.besu.plugin.data.TransactionType; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.tests.acceptance.dsl.account.Account; import org.hyperledger.besu.tests.acceptance.dsl.blockchain.Amount; diff --git a/acceptance-tests/test-plugins/src/main/java/org/hyperledger/besu/tests/acceptance/plugins/privacy/TestPrivacyPluginPayloadProvider.java b/acceptance-tests/test-plugins/src/main/java/org/hyperledger/besu/tests/acceptance/plugins/privacy/TestPrivacyPluginPayloadProvider.java index f40d71b9c57..2a26218a6b8 100644 --- a/acceptance-tests/test-plugins/src/main/java/org/hyperledger/besu/tests/acceptance/plugins/privacy/TestPrivacyPluginPayloadProvider.java +++ b/acceptance-tests/test-plugins/src/main/java/org/hyperledger/besu/tests/acceptance/plugins/privacy/TestPrivacyPluginPayloadProvider.java @@ -18,9 +18,9 @@ import static org.hyperledger.besu.ethereum.privacy.PrivateTransaction.readFrom; import static org.hyperledger.besu.ethereum.privacy.PrivateTransaction.serialize; +import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; import org.hyperledger.besu.plugin.data.PrivateTransaction; -import org.hyperledger.besu.plugin.data.Transaction; import org.hyperledger.besu.plugin.services.privacy.PrivacyPluginPayloadProvider; import java.util.Optional; diff --git a/acceptance-tests/test-plugins/src/main/java/org/hyperledger/besu/tests/acceptance/plugins/privacy/TestSigningPrivateMarkerTransactionFactory.java b/acceptance-tests/test-plugins/src/main/java/org/hyperledger/besu/tests/acceptance/plugins/privacy/TestSigningPrivateMarkerTransactionFactory.java index 3ab57a28e2c..98ad8e9cf55 100644 --- a/acceptance-tests/test-plugins/src/main/java/org/hyperledger/besu/tests/acceptance/plugins/privacy/TestSigningPrivateMarkerTransactionFactory.java +++ b/acceptance-tests/test-plugins/src/main/java/org/hyperledger/besu/tests/acceptance/plugins/privacy/TestSigningPrivateMarkerTransactionFactory.java @@ -22,11 +22,11 @@ import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.plugin.data.PrivateTransaction; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.plugin.data.UnsignedPrivateMarkerTransaction; import org.hyperledger.besu.plugin.services.privacy.PrivateMarkerTransactionFactory; diff --git a/acceptance-tests/tests/build.gradle b/acceptance-tests/tests/build.gradle index 8b23195361d..cc4a54b009b 100644 --- a/acceptance-tests/tests/build.gradle +++ b/acceptance-tests/tests/build.gradle @@ -76,7 +76,7 @@ dependencies { testImplementation 'junit:junit' testImplementation 'org.apache.commons:commons-compress' testImplementation 'org.apache.logging.log4j:log4j-core' - testImplementation 'org.apache.tuweni:tuweni-crypto' + testImplementation 'io.tmio:tuweni-crypto' testImplementation 'org.assertj:assertj-core' testImplementation 'org.awaitility:awaitility' testImplementation 'org.junit.jupiter:junit-jupiter' diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/backup/BackupRoundTripAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/backup/BackupRoundTripAcceptanceTest.java index d2afc2e6d39..5136cc64ab3 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/backup/BackupRoundTripAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/backup/BackupRoundTripAcceptanceTest.java @@ -80,16 +80,6 @@ public BackupRoundTripAcceptanceTest( public static Object[][] getParameters() { return new Object[][] { // First 10 blocks of ropsten - new Object[] { - "Before versioning was enabled", - "version0", - 0xA, - singletonList( - new AccountData( - "0xd1aeb42885a43b72b518182ef893125814811048", - BigInteger.valueOf(0xA), - Wei.fromHexString("0x2B5E3AF16B1880000"))), - }, new Object[] { "After versioning was enabled and using multiple RocksDB columns", "version1", diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/database/DatabaseMigrationAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/database/DatabaseMigrationAcceptanceTest.java index d116a5cafcf..291506498ba 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/database/DatabaseMigrationAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/database/DatabaseMigrationAcceptanceTest.java @@ -56,16 +56,6 @@ public DatabaseMigrationAcceptanceTest( public static Object[][] getParameters() { return new Object[][] { // First 10 blocks of ropsten - new Object[] { - "Before versioning was enabled", - "version0", - 0xA, - singletonList( - new AccountData( - "0xd1aeb42885a43b72b518182ef893125814811048", - BigInteger.valueOf(0xA), - Wei.fromHexString("0x2B5E3AF16B1880000"))), - }, new Object[] { "After versioning was enabled and using multiple RocksDB columns", "version1", diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEngineEip6110AcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEngineEip6110AcceptanceTest.java index d1771ac5990..fb2abde25d4 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEngineEip6110AcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEngineEip6110AcceptanceTest.java @@ -20,10 +20,12 @@ import org.junit.AfterClass; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @RunWith(Parameterized.class) +@Ignore("EIP-6110 is not yet implemented") public class ExecutionEngineEip6110AcceptanceTest extends AbstractJsonRpcTest { private static final String GENESIS_FILE = "/jsonrpc/engine/eip6110/genesis.json"; private static final String TEST_CASE_PATH = "/jsonrpc/engine/eip6110/test-cases/"; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/permissioning/NodeSmartContractPermissioningIbft2StallAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/permissioning/NodeSmartContractPermissioningIbft2StallAcceptanceTest.java index fc64ee13862..e9da331a9e3 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/permissioning/NodeSmartContractPermissioningIbft2StallAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/permissioning/NodeSmartContractPermissioningIbft2StallAcceptanceTest.java @@ -61,9 +61,7 @@ public void restartedIbftClusterShouldNotStall() throws IOException { Address.fromHexString(CONTRACT_ADDRESS)); final PermissioningConfiguration permissioningConfiguration = new PermissioningConfiguration( - Optional.empty(), - Optional.of(smartContractPermissioningConfiguration), - Optional.empty()); + Optional.empty(), Optional.of(smartContractPermissioningConfiguration)); // Set permissioning configurations on nodes bootnode.setPermissioningConfiguration(permissioningConfiguration); diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/EnclaveErrorAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/EnclaveErrorAcceptanceTest.java index 7822768f140..266284a498e 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/EnclaveErrorAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/EnclaveErrorAcceptanceTest.java @@ -20,7 +20,7 @@ import static org.hyperledger.enclave.testutil.EnclaveEncryptorType.NACL; import static org.hyperledger.enclave.testutil.EnclaveType.TESSERA; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyAcceptanceTestBase; import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode; import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver; @@ -116,7 +116,7 @@ public void aliceCannotSendTransactionFromBobNode() { assertThat(throwable) .hasMessageContaining( - JsonRpcError.PRIVATE_FROM_DOES_NOT_MATCH_ENCLAVE_PUBLIC_KEY.getMessage()); + RpcErrorType.PRIVATE_FROM_DOES_NOT_MATCH_ENCLAVE_PUBLIC_KEY.getMessage()); } @Test @@ -131,7 +131,7 @@ public void enclaveNoPeerUrlError() { alice.getEnclaveKey(), wrongPublicKey))); - final String tesseraMessage = JsonRpcError.TESSERA_NODE_MISSING_PEER_URL.getMessage(); + final String tesseraMessage = RpcErrorType.TESSERA_NODE_MISSING_PEER_URL.getMessage(); assertThat(throwable.getMessage()).has(matchTesseraEnclaveMessage(tesseraMessage)); } @@ -213,7 +213,7 @@ public void transactionFailsIfPartyIsOffline() { public void createPrivacyGroupReturnsCorrectError() { final Throwable throwable = catchThrowable(() -> alice.execute(privacyTransactions.createPrivacyGroup(null, null))); - final String tesseraMessage = JsonRpcError.TESSERA_CREATE_GROUP_INCLUDE_SELF.getMessage(); + final String tesseraMessage = RpcErrorType.TESSERA_CREATE_GROUP_INCLUDE_SELF.getMessage(); assertThat(throwable.getMessage()).has(matchTesseraEnclaveMessage(tesseraMessage)); } diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivCallAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivCallAcceptanceTest.java index c42075d48d2..bb5e829dc5a 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivCallAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivCallAcceptanceTest.java @@ -139,7 +139,7 @@ public void mustRevertWithRevertReason() throws Exception { privCall(privacyGroupId, revertReasonContract, false, false, true); EthCall resp = priv_call.send(); - assertThat(resp.getRevertReason()).isEqualTo("Execution reverted"); + assertThat(resp.getRevertReason()).isEqualTo("Execution reverted: RevertReason"); byte[] bytes = Hex.decode(resp.getError().getData().substring(3, 203)); String revertMessage = diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/MultiTenancyValidationFailAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/MultiTenancyValidationFailAcceptanceTest.java index 515248347b8..84e6fa7ea3e 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/MultiTenancyValidationFailAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/MultiTenancyValidationFailAcceptanceTest.java @@ -18,11 +18,11 @@ import static com.github.tomakehurst.wiremock.client.WireMock.post; import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.DELETE_PRIVACY_GROUP_ERROR; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.ENCLAVE_ERROR; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.FIND_PRIVACY_GROUP_ERROR; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.GET_PRIVATE_TRANSACTION_NONCE_ERROR; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.PRIVATE_FROM_DOES_NOT_MATCH_ENCLAVE_PUBLIC_KEY; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.DELETE_PRIVACY_GROUP_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.ENCLAVE_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.FIND_PRIVACY_GROUP_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.GET_PRIVATE_TRANSACTION_NONCE_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.PRIVATE_FROM_DOES_NOT_MATCH_ENCLAVE_PUBLIC_KEY; import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; @@ -30,7 +30,7 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.enclave.types.PrivacyGroup; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.privacy.PrivateTransaction; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.plugin.data.Restriction; @@ -102,7 +102,7 @@ public void sendRawTransactionShouldFailWhenPrivateFromNotMatchEnclaveKey() getRLPOutput(validSignedPrivateTransaction).encoded().toHexString()); node.verify( priv.multiTenancyValidationFail( - transaction, JsonRpcError.PRIVATE_FROM_DOES_NOT_MATCH_ENCLAVE_PUBLIC_KEY)); + transaction, RpcErrorType.PRIVATE_FROM_DOES_NOT_MATCH_ENCLAVE_PUBLIC_KEY)); } @Test diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/genesis.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/genesis.json new file mode 100644 index 00000000000..017d9f0c851 --- /dev/null +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/genesis.json @@ -0,0 +1,4078 @@ +{ + "config": { + "ethash": {}, + "chainID": 7, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "constantinopleFixBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "parisBlock": 0, + "terminalTotalDifficulty": 0, + "shanghaiTime": 0, + "cancunTime": 4662 + }, + "nonce": "0x0", + "timestamp": "0x1234", + "extraData": "0x", + "gasLimit": "0x2fefd8", + "difficulty": "0x0", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "0000000000000000000000000000000000000100": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000101": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000102": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000103": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000104": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000105": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000106": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000107": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000108": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000109": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000010a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000010b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000010c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000010d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000010e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000010f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000110": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000111": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000112": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000113": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000114": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000115": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000116": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000117": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000118": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000119": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000011a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000011b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000011c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000011d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000011e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000011f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000120": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000121": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000122": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000123": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000124": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000125": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000126": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000127": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000128": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000129": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000012a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000012b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000012c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000012d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000012e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000012f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000130": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000131": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000132": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000133": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000134": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000135": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000136": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000137": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000138": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000139": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000013a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000013b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000013c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000013d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000013e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000013f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000140": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000141": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000142": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000143": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000144": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000145": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000146": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000147": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000148": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000149": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000014a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000014b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000014c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000014d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000014e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000014f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000150": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000151": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000152": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000153": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000154": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000155": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000156": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000157": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000158": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000159": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000015a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000015b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000015c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000015d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000015e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000015f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000160": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000161": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000162": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000163": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000164": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000165": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000166": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000167": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000168": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000169": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000016a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000016b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000016c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000016d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000016e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000016f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000170": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000171": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000172": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000173": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000174": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000175": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000176": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000177": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000178": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000179": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000017a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000017b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000017c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000017d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000017e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000017f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000180": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000181": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000182": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000183": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000184": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000185": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000186": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000187": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000188": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000189": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000018a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000018b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000018c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000018d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000018e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000018f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000190": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000191": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000192": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000193": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000194": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000195": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000196": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000197": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000198": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000199": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000019a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000019b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000019c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000019d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000019e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000019f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001aa": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ab": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ac": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ad": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ae": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001af": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ba": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001bb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001bc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001bd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001be": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001bf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ca": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001cb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001cc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001cd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ce": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001cf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001da": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001db": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001dc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001dd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001de": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001df": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ea": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001eb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ec": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ed": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ee": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ef": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001fa": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001fb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001fc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001fd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001fe": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ff": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000200": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000201": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000202": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000203": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000204": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000205": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000206": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000207": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000208": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000209": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000020a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000020b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000020c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000020d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000020e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000020f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000210": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000211": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000212": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000213": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000214": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000215": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000216": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000217": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000218": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000219": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000021a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000021b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000021c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000021d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000021e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000021f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000220": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000221": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000222": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000223": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000224": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000225": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000226": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000227": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000228": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000229": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000022a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000022b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000022c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000022d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000022e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000022f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000230": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000231": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000232": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000233": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000234": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000235": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000236": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000237": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000238": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000239": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000023a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000023b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000023c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000023d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000023e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000023f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000240": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000241": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000242": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000243": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000244": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000245": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000246": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000247": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000248": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000249": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000024a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000024b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000024c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000024d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000024e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000024f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000250": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000251": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000252": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000253": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000254": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000255": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000256": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000257": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000258": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000259": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000025a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000025b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000025c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000025d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000025e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000025f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000260": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000261": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000262": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000263": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000264": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000265": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000266": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000267": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000268": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000269": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000026a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000026b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000026c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000026d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000026e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000026f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000270": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000271": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000272": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000273": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000274": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000275": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000276": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000277": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000278": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000279": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000027a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000027b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000027c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000027d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000027e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000027f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000280": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000281": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000282": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000283": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000284": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000285": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000286": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000287": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000288": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000289": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000028a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000028b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000028c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000028d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000028e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000028f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000290": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000291": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000292": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000293": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000294": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000295": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000296": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000297": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000298": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000299": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000029a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000029b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000029c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000029d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000029e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000029f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002aa": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ab": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ac": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ad": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ae": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002af": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ba": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002bb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002bc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002bd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002be": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002bf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ca": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002cb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002cc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002cd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ce": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002cf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002da": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002db": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002dc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002dd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002de": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002df": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ea": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002eb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ec": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ed": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ee": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ef": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002fa": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002fb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002fc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002fd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002fe": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ff": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000300": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000301": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000302": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000303": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000304": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000305": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000306": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000307": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000308": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000309": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000030a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000030b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000030c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000030d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000030e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000030f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000310": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000311": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000312": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000313": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000314": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000315": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000316": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000317": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000318": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000319": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000031a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000031b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000031c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000031d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000031e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000031f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000320": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000321": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000322": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000323": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000324": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000325": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000326": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000327": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000328": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000329": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000032a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000032b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000032c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000032d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000032e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000032f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000330": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000331": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000332": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000333": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000334": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000335": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000336": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000337": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000338": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000339": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000033a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000033b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000033c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000033d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000033e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000033f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000340": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000341": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000342": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000343": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000344": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000345": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000346": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000347": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000348": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000349": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000034a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000034b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000034c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000034d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000034e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000034f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000350": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000351": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000352": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000353": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000354": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000355": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000356": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000357": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000358": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000359": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000035a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000035b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000035c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000035d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000035e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000035f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000360": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000361": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000362": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000363": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000364": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000365": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000366": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000367": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000368": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000369": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000036a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000036b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000036c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000036d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000036e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000036f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000370": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000371": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000372": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000373": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000374": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000375": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000376": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000377": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000378": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000379": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000037a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000037b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000037c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000037d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000037e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000037f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000380": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000381": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000382": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000383": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000384": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000385": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000386": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000387": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000388": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000389": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000038a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000038b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000038c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000038d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000038e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000038f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000390": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000391": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000392": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000393": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000394": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000395": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000396": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000397": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000398": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000399": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000039a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000039b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000039c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000039d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000039e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000039f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003aa": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ab": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ac": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ad": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ae": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003af": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ba": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003bb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003bc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003bd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003be": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003bf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ca": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003cb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003cc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003cd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ce": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003cf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003da": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003db": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003dc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003dd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003de": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003df": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ea": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003eb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ec": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ed": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ee": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ef": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003fa": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003fb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003fc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003fd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003fe": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ff": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000400": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000401": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000402": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000403": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000404": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000405": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000406": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000407": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000408": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000409": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000040a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000040b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000040c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000040d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000040e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000040f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000410": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000411": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000412": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000413": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000414": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000415": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000416": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000417": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000418": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000419": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000041a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000041b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000041c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000041d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000041e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000041f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000420": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000421": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000422": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000423": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000424": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000425": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000426": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000427": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000428": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000429": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000042a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000042b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000042c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000042d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000042e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000042f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000430": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000431": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000432": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000433": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000434": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000435": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000436": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000437": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000438": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000439": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000043a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000043b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000043c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000043d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000043e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000043f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000440": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000441": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000442": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000443": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000444": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000445": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000446": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000447": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000448": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000449": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000044a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000044b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000044c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000044d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000044e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000044f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000450": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000451": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000452": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000453": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000454": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000455": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000456": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000457": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000458": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000459": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000045a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000045b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000045c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000045d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000045e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000045f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000460": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000461": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000462": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000463": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000464": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000465": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000466": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000467": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000468": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000469": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000046a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000046b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000046c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000046d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000046e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000046f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000470": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000471": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000472": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000473": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000474": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000475": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000476": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000477": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000478": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000479": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000047a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000047b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000047c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000047d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000047e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000047f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000480": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000481": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000482": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000483": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000484": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000485": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000486": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000487": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000488": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000489": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000048a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000048b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000048c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000048d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000048e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000048f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000490": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000491": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000492": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000493": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000494": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000495": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000496": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000497": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000498": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000499": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000049a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000049b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000049c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000049d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000049e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000049f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004aa": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004ab": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004ac": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004ad": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004ae": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004af": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004ba": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004bb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004bc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004bd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004be": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004bf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004ca": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004cb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004cc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004cd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004ce": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004cf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004da": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004db": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004dc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004dd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004de": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004df": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0161e041aad467a890839d5b08b138c1e6373072": { + "balance": "0x123450000000000000000" + }, + "0f830fc93e76c8d26ed1f65045e70f5f986da383": { + "balance": "0x123450000000000000000" + }, + "2180290b54d5d9e38f85fdaf086bfe35b610f404": { + "balance": "0x123450000000000000000" + }, + "763fc7d39ab4cfa496c39077542589819aea5c54": { + "balance": "0x123450000000000000000" + }, + "87da6a8c6e9eff15d703fc2773e32f6af8dbe301": { + "balance": "0x123450000000000000000" + }, + "9c09de85a373dc3486115cab94c72549029f1103": { + "balance": "0x123450000000000000000" + }, + "9d2f18c852eb5b37292dfc9f68ac5ecbf0d22dd2": { + "balance": "0x123450000000000000000" + }, + "a995b3ebccfb2b8e8b1db15b7ca8cf2f11ed0310": { + "balance": "0x123450000000000000000" + }, + "aa82d35d5eaec5cf87c311a3af844ed682d5a247": { + "balance": "0x123450000000000000000" + }, + "b76ae96839fe445670262bce61144e6cda9099b8": { + "balance": "0x123450000000000000000" + }, + "b97de4b8c857e4f6bc354f226dc3249aaee49209": { + "balance": "0x123450000000000000000" + }, + "c5065c9eeebe6df2c2284d046bfc906501846c51": { + "balance": "0x123450000000000000000" + }, + "cf49fda3be353c69b41ed96333cd24302da4556f": { + "balance": "0x123450000000000000000" + }, + "fb289e2b2b65fb63299a682d000744671c50417b": { + "balance": "0x123450000000000000000" + } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas": null, + "blobGasUsed": null, + "excessBlobGas": null +} \ No newline at end of file diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/01_shanghai_prepare_payload.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/01_shanghai_prepare_payload.json new file mode 100644 index 00000000000..3900ba5b481 --- /dev/null +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/01_shanghai_prepare_payload.json @@ -0,0 +1,33 @@ +{ + "request": { + "jsonrpc": "2.0", + "id": 1, + "method": "engine_forkchoiceUpdatedV2", + "params": [ + { + "headBlockHash": "0xd76266aeddab03ffe29e2cf11a808d2a86f9b8582a9f4a48372f9a7795a95ba4", + "safeBlockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "finalizedBlockHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "timestamp": "0x1235", + "prevRandao": "0x6c9619f4c25184d07b2369f87ffdf9b3786f05ed3bc12c4e086b8850cd9fd606", + "suggestedFeeRecipient": "0x0000000000000000000000000000000000000000", + "withdrawals": [] + } + ] + }, + "response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "payloadStatus": { + "status": "VALID", + "latestValidHash": "0xd76266aeddab03ffe29e2cf11a808d2a86f9b8582a9f4a48372f9a7795a95ba4", + "validationError": null + }, + "payloadId": "0x006221426d1aefcc" + } + }, + "statusCode": 200 +} \ No newline at end of file diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/02_shanghai_getPayloadV2.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/02_shanghai_getPayloadV2.json new file mode 100644 index 00000000000..1d1c88e5950 --- /dev/null +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/02_shanghai_getPayloadV2.json @@ -0,0 +1,36 @@ +{ + "request": { + "jsonrpc": "2.0", + "id": 2, + "method": "engine_getPayloadV2", + "params": [ + "0x006221426d1aefcc" + ] + }, + "response": { + "jsonrpc": "2.0", + "id": 2, + "result": { + "executionPayload": { + "parentHash": "0xd76266aeddab03ffe29e2cf11a808d2a86f9b8582a9f4a48372f9a7795a95ba4", + "feeRecipient": "0x0000000000000000000000000000000000000000", + "stateRoot": "0x7f5cfe1375a61009a22d24512d18035bc8f855129452fa9c6a6be2ef4e9da7db", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "prevRandao": "0x6c9619f4c25184d07b2369f87ffdf9b3786f05ed3bc12c4e086b8850cd9fd606", + "gasLimit": "0x2ff3d8", + "gasUsed": "0x0", + "timestamp": "0x1235", + "extraData": "0x", + "baseFeePerGas": "0x342770c0", + "transactions": [], + "withdrawals": [], + "deposits": null, + "blockNumber": "0x1", + "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "blockHash": "0x50c02dc77082fe2060b600cba0e6ce5a491af6d5323b2a90a7bc6359dd18e97b" + }, + "blockValue": "0x0" + } + }, + "statusCode": 200 +} \ No newline at end of file diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/03_shanghai_newPayloadV2.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/03_shanghai_newPayloadV2.json new file mode 100644 index 00000000000..b9496a2b286 --- /dev/null +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/03_shanghai_newPayloadV2.json @@ -0,0 +1,38 @@ +{ + "request": { + "jsonrpc": "2.0", + "id": 3, + "method": "engine_newPayloadV2", + "params": [ + { + "parentHash": "0xd76266aeddab03ffe29e2cf11a808d2a86f9b8582a9f4a48372f9a7795a95ba4", + "feeRecipient": "0x0000000000000000000000000000000000000000", + "stateRoot": "0x7f5cfe1375a61009a22d24512d18035bc8f855129452fa9c6a6be2ef4e9da7db", + "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "prevRandao": "0x6c9619f4c25184d07b2369f87ffdf9b3786f05ed3bc12c4e086b8850cd9fd606", + "blockNumber": "0x1", + "gasLimit": "0x2ff3d8", + "gasUsed": "0x0", + "timestamp": "0x1235", + "extraData": "0x", + "baseFeePerGas": "0x342770c0", + "blockHash": "0x50c02dc77082fe2060b600cba0e6ce5a491af6d5323b2a90a7bc6359dd18e97b", + "transactions": [], + "withdrawals": [], + "blobGasUsed": null, + "excessBlobGas": null + } + ] + }, + "response": { + "jsonrpc": "2.0", + "id": 3, + "result": { + "status": "VALID", + "latestValidHash": "0x50c02dc77082fe2060b600cba0e6ce5a491af6d5323b2a90a7bc6359dd18e97b", + "validationError": null + } + }, + "statusCode": 200 +} \ No newline at end of file diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/04_shanghai_newPayloadV3.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/04_shanghai_newPayloadV3.json new file mode 100644 index 00000000000..bc43c2e42a5 --- /dev/null +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/04_shanghai_newPayloadV3.json @@ -0,0 +1,39 @@ +{ + "request": { + "jsonrpc": "2.0", + "id": 4, + "method": "engine_newPayloadV3", + "params": [ + { + "parentHash": "0xd76266aeddab03ffe29e2cf11a808d2a86f9b8582a9f4a48372f9a7795a95ba4", + "feeRecipient": "0x0000000000000000000000000000000000000000", + "stateRoot": "0x7f5cfe1375a61009a22d24512d18035bc8f855129452fa9c6a6be2ef4e9da7db", + "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "prevRandao": "0x6c9619f4c25184d07b2369f87ffdf9b3786f05ed3bc12c4e086b8850cd9fd606", + "blockNumber": "0x1", + "gasLimit": "0x2ff3d8", + "gasUsed": "0x0", + "timestamp": "0x1235", + "extraData": "0x", + "baseFeePerGas": "0x342770c0", + "blockHash": "0x50c02dc77082fe2060b600cba0e6ce5a491af6d5323b2a90a7bc6359dd18e97b", + "transactions": [], + "withdrawals": [], + "blobGasUsed": null, + "excessBlobGas": null + }, + null + ] + }, + "response": { + "jsonrpc": "2.0", + "id": 4, + "result": { + "status": "VALID", + "latestValidHash": "0x50c02dc77082fe2060b600cba0e6ce5a491af6d5323b2a90a7bc6359dd18e97b", + "validationError": null + } + }, + "statusCode": 200 +} \ No newline at end of file diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/05_cancun_forkchoiceUpdatedV2.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/05_cancun_forkchoiceUpdatedV2.json new file mode 100644 index 00000000000..9320978375d --- /dev/null +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/05_cancun_forkchoiceUpdatedV2.json @@ -0,0 +1,28 @@ +{ + "request": { + "jsonrpc": "2.0", + "id": 5, + "method": "engine_forkchoiceUpdatedV2", + "params": [ + { + "headBlockHash": "0x50c02dc77082fe2060b600cba0e6ce5a491af6d5323b2a90a7bc6359dd18e97b", + "safeBlockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "finalizedBlockHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + null + ] + }, + "response": { + "jsonrpc": "2.0", + "id": 5, + "result": { + "payloadStatus": { + "status": "VALID", + "latestValidHash": "0x50c02dc77082fe2060b600cba0e6ce5a491af6d5323b2a90a7bc6359dd18e97b", + "validationError": null + }, + "payloadId": null + } + }, + "statusCode": 200 +} \ No newline at end of file diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/06_cancun_forkchoiceUpdatedV2.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/06_cancun_forkchoiceUpdatedV2.json new file mode 100644 index 00000000000..8bd8b07050d --- /dev/null +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/06_cancun_forkchoiceUpdatedV2.json @@ -0,0 +1,33 @@ +{ + "request": { + "jsonrpc": "2.0", + "id": 6, + "method": "engine_forkchoiceUpdatedV2", + "params": [ + { + "headBlockHash": "0x50c02dc77082fe2060b600cba0e6ce5a491af6d5323b2a90a7bc6359dd18e97b", + "safeBlockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "finalizedBlockHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "timestamp": "0x1236", + "prevRandao": "0x5079013331632e5f6db41eccd876e5659c014b8a0a0809794ad1bf64631e030d", + "suggestedFeeRecipient": "0x0000000000000000000000000000000000000000", + "withdrawals": [] + } + ] + }, + "response": { + "jsonrpc": "2.0", + "id": 6, + "result": { + "payloadStatus": { + "status": "VALID", + "latestValidHash": "0x50c02dc77082fe2060b600cba0e6ce5a491af6d5323b2a90a7bc6359dd18e97b", + "validationError": null + }, + "payloadId": "0x0062166c2eaa44c9" + } + }, + "statusCode": 200 +} \ No newline at end of file diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/07_cancun_getPayloadV3.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/07_cancun_getPayloadV3.json new file mode 100644 index 00000000000..921659ba549 --- /dev/null +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/07_cancun_getPayloadV3.json @@ -0,0 +1,42 @@ +{ + "request": { + "jsonrpc": "2.0", + "id": 7, + "method": "engine_getPayloadV3", + "params": [ + "0x0062166c2eaa44c9" + ] + }, + "response": { + "jsonrpc": "2.0", + "id": 7, + "result": { + "executionPayload": { + "parentHash": "0x50c02dc77082fe2060b600cba0e6ce5a491af6d5323b2a90a7bc6359dd18e97b", + "feeRecipient": "0x0000000000000000000000000000000000000000", + "stateRoot": "0x7f5cfe1375a61009a22d24512d18035bc8f855129452fa9c6a6be2ef4e9da7db", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "prevRandao": "0x5079013331632e5f6db41eccd876e5659c014b8a0a0809794ad1bf64631e030d", + "gasLimit": "0x2ff7d8", + "gasUsed": "0x0", + "timestamp": "0x1236", + "extraData": "0x", + "baseFeePerGas": "0x2da282a8", + "excessBlobGas": "0x0", + "transactions": [], + "withdrawals": [], + "blockNumber": "0x2", + "blobGasUsed": "0x0", + "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "blockHash": "0xc33d43425366d661ef70df12faf8ccd66ed7d0c6718d16d14868ba49e6786927" + }, + "blockValue": "0x0", + "blobsBundle": { + "commitments": [], + "proofs": [], + "blobs": [] + } + } + }, + "statusCode": 200 +} \ No newline at end of file diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/08_cancun_newPayloadV3.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/08_cancun_newPayloadV3.json new file mode 100644 index 00000000000..0e80c75aabf --- /dev/null +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/08_cancun_newPayloadV3.json @@ -0,0 +1,39 @@ +{ + "request": { + "jsonrpc": "2.0", + "id": 8, + "method": "engine_newPayloadV3", + "params": [ + { + "parentHash": "0x50c02dc77082fe2060b600cba0e6ce5a491af6d5323b2a90a7bc6359dd18e97b", + "feeRecipient": "0x0000000000000000000000000000000000000000", + "stateRoot": "0x7f5cfe1375a61009a22d24512d18035bc8f855129452fa9c6a6be2ef4e9da7db", + "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "prevRandao": "0x5079013331632e5f6db41eccd876e5659c014b8a0a0809794ad1bf64631e030d", + "blockNumber": "0x2", + "gasLimit": "0x2ff7d8", + "gasUsed": "0x0", + "timestamp": "0x1236", + "extraData": "0x", + "baseFeePerGas": "0x2da282a8", + "blockHash": "0xc33d43425366d661ef70df12faf8ccd66ed7d0c6718d16d14868ba49e6786927", + "transactions": [], + "withdrawals": [], + "blobGasUsed": "0x0", + "excessBlobGas": "0x0" + }, + [] + ] + }, + "response": { + "jsonrpc": "2.0", + "id": 8, + "result": { + "status": "VALID", + "latestValidHash": "0xc33d43425366d661ef70df12faf8ccd66ed7d0c6718d16d14868ba49e6786927", + "validationError": null + } + }, + "statusCode": 200 +} \ No newline at end of file diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/genesis.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/genesis.json index b6a16b71a40..12f58a81bfa 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/genesis.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/genesis.json @@ -13,7 +13,7 @@ "berlinBlock":0, "londonBlock":0, "terminalTotalDifficulty":0, - "shanghaiTime":0, + "cancunTime":0, "experimentalEipsTime":20, "clique": { "period": 5, diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/06_eip6110_get_payload.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/06_eip6110_get_payload.json index 89b7cf65b2e..8b311c2841c 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/06_eip6110_get_payload.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/06_eip6110_get_payload.json @@ -39,7 +39,7 @@ ], "deposits" : [], "blockNumber": "0x2", - "blockHash": "0x58ea3e01b03ac17c68ed3e3d724a021408273fac8a86f42cb30a26be8e93fbe9", + "blockHash": "0x4c4418c408aeadb4659d31d1c05108f26fabf713bb6f8cc487dba8424a725bf5", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" }, "blockValue": "0x0" diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/shanghai/test-cases/09_shanghai_newPayloadV2_invalid_null_withdrawals.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/shanghai/test-cases/09_shanghai_newPayloadV2_invalid_null_withdrawals.json index b682b05c369..41718648049 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/shanghai/test-cases/09_shanghai_newPayloadV2_invalid_null_withdrawals.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/shanghai/test-cases/09_shanghai_newPayloadV2_invalid_null_withdrawals.json @@ -28,7 +28,8 @@ "id": 67, "error": { "code": -32602, - "message": "Invalid params" + "message": "Invalid params", + "data": "Invalid withdrawals" } }, "statusCode": 200 diff --git a/acceptance-tests/tests/src/test/resources/org/hyperledger/besu/tests/acceptance/database/version0/besu-db-archive.tar.gz b/acceptance-tests/tests/src/test/resources/org/hyperledger/besu/tests/acceptance/database/version0/besu-db-archive.tar.gz deleted file mode 100644 index 894c8e76a69..00000000000 Binary files a/acceptance-tests/tests/src/test/resources/org/hyperledger/besu/tests/acceptance/database/version0/besu-db-archive.tar.gz and /dev/null differ diff --git a/acceptance-tests/tests/src/test/resources/permissioning/simple_permissioning_genesis.json b/acceptance-tests/tests/src/test/resources/permissioning/simple_permissioning_genesis.json index 5aee1cc13b3..04ee1a4882e 100644 --- a/acceptance-tests/tests/src/test/resources/permissioning/simple_permissioning_genesis.json +++ b/acceptance-tests/tests/src/test/resources/permissioning/simple_permissioning_genesis.json @@ -1,7 +1,8 @@ { "config": { "chainId": 999, - "petersburgBlock": 0, + "londonBlock": 0, + "zeroBaseFee": true, "ethash": { "fixeddifficulty": 100 } diff --git a/acceptance-tests/tests/src/test/resources/permissioning/simple_permissioning_ibft_genesis.json b/acceptance-tests/tests/src/test/resources/permissioning/simple_permissioning_ibft_genesis.json index 907547b0ca9..6be6cfad3fd 100644 --- a/acceptance-tests/tests/src/test/resources/permissioning/simple_permissioning_ibft_genesis.json +++ b/acceptance-tests/tests/src/test/resources/permissioning/simple_permissioning_ibft_genesis.json @@ -1,7 +1,8 @@ { "config": { "chainId": 999, - "petersburgBlock": 0, + "londonBlock": 0, + "zeroBaseFee": true, "ibft2": { "blockperiodseconds": 5, "epochlength": 30000, diff --git a/acceptance-tests/tests/src/test/resources/permissioning/simple_permissioning_v2_genesis.json b/acceptance-tests/tests/src/test/resources/permissioning/simple_permissioning_v2_genesis.json index 1802856c793..b7ec620f310 100644 --- a/acceptance-tests/tests/src/test/resources/permissioning/simple_permissioning_v2_genesis.json +++ b/acceptance-tests/tests/src/test/resources/permissioning/simple_permissioning_v2_genesis.json @@ -1,7 +1,8 @@ { "config": { "chainId": 999, - "petersburgBlock": 0, + "londonBlock": 0, + "zeroBaseFee": true, "ethash": { "fixeddifficulty": 100 } diff --git a/besu/build.gradle b/besu/build.gradle index 969571b565c..73977d81ba7 100644 --- a/besu/build.gradle +++ b/besu/build.gradle @@ -70,10 +70,10 @@ dependencies { implementation 'io.vertx:vertx-web' implementation 'org.apache.commons:commons-lang3' implementation 'org.apache.logging.log4j:log4j-core' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-config' - implementation 'org.apache.tuweni:tuweni-toml' - implementation 'org.apache.tuweni:tuweni-units' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-config' + implementation 'io.tmio:tuweni-toml' + implementation 'io.tmio:tuweni-units' implementation 'org.springframework.security:spring-security-crypto' implementation 'org.xerial.snappy:snappy-java' implementation 'tech.pegasys:jc-kzg-4844' @@ -92,8 +92,8 @@ dependencies { testImplementation 'io.opentelemetry:opentelemetry-api' testImplementation 'junit:junit' testImplementation 'org.apache.commons:commons-text' - testImplementation 'org.apache.tuweni:tuweni-bytes' - testImplementation 'org.apache.tuweni:tuweni-units' + testImplementation 'io.tmio:tuweni-bytes' + testImplementation 'io.tmio:tuweni-units' testImplementation 'org.assertj:assertj-core' testImplementation 'org.awaitility:awaitility' testImplementation 'org.junit.jupiter:junit-jupiter' diff --git a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java index d54a9149429..857fd4e093e 100644 --- a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java @@ -783,10 +783,7 @@ public Runner build() { final Optional accountPermissioningController = buildAccountPermissioningController( - permissioningConfiguration, - besuController, - transactionSimulator, - context.getBlockchain()); + permissioningConfiguration, besuController, transactionSimulator); final Optional accountLocalConfigPermissioningController = @@ -1110,8 +1107,7 @@ private Optional buildNodePermissioningController( final NodePermissioningController nodePermissioningController = new NodePermissioningControllerFactory() .create( - new PermissioningConfiguration( - Optional.empty(), Optional.empty(), Optional.empty()), + new PermissioningConfiguration(Optional.empty(), Optional.empty()), synchronizer, fixedNodes, localNodeId, @@ -1129,19 +1125,18 @@ private Optional buildNodePermissioningController( private Optional buildAccountPermissioningController( final Optional permissioningConfiguration, final BesuController besuController, - final TransactionSimulator transactionSimulator, - final Blockchain blockchain) { + final TransactionSimulator transactionSimulator) { if (permissioningConfiguration.isPresent()) { final Optional accountPermissioningController = AccountPermissioningControllerFactory.create( - permissioningConfiguration.get(), transactionSimulator, metricsSystem, blockchain); + permissioningConfiguration.get(), transactionSimulator, metricsSystem); accountPermissioningController.ifPresent( permissioningController -> besuController .getProtocolSchedule() - .setTransactionFilter(permissioningController::isPermitted)); + .setPermissionTransactionFilter(permissioningController::isPermitted)); return accountPermissioningController; } else { diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index 87fc5a545d3..e0330170b7f 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -27,11 +27,11 @@ import static org.hyperledger.besu.ethereum.api.graphql.GraphQLConfiguration.DEFAULT_GRAPHQL_HTTP_PORT; import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration.DEFAULT_ENGINE_JSON_RPC_PORT; import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration.DEFAULT_JSON_RPC_PORT; +import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration.DEFAULT_PRETTY_JSON_ENABLED; import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis.DEFAULT_RPC_APIS; import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis.VALID_APIS; import static org.hyperledger.besu.ethereum.api.jsonrpc.authentication.EngineAuthService.EPHEMERAL_JWT_FILE; import static org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration.DEFAULT_WEBSOCKET_PORT; -import static org.hyperledger.besu.ethereum.permissioning.GoQuorumPermissioningConfiguration.QIP714_DEFAULT_BLOCK; import static org.hyperledger.besu.metrics.BesuMetricCategory.DEFAULT_METRIC_CATEGORIES; import static org.hyperledger.besu.metrics.MetricsProtocol.PROMETHEUS; import static org.hyperledger.besu.metrics.prometheus.MetricsConfiguration.DEFAULT_METRICS_PORT; @@ -134,7 +134,6 @@ import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl; import org.hyperledger.besu.ethereum.p2p.peers.StaticNodesParser; import org.hyperledger.besu.ethereum.p2p.rlpx.connections.netty.TLSConfiguration; -import org.hyperledger.besu.ethereum.permissioning.GoQuorumPermissioningConfiguration; import org.hyperledger.besu.ethereum.permissioning.LocalPermissioningConfiguration; import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration; import org.hyperledger.besu.ethereum.permissioning.PermissioningConfigurationBuilder; @@ -219,7 +218,6 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.OptionalLong; import java.util.Set; import java.util.TreeMap; import java.util.function.Function; @@ -782,6 +780,11 @@ static class JsonRPCHttpOptionGroup { paramLabel = MANDATORY_LONG_FORMAT_HELP, description = "Specifies the maximum request content length. (default: ${DEFAULT-VALUE})") private final Long rpcHttpMaxRequestContentLength = DEFAULT_MAX_REQUEST_CONTENT_LENGTH; + + @Option( + names = {"--json-pretty-print-enabled"}, + description = "Enable JSON pretty print format (default: ${DEFAULT-VALUE})") + private final Boolean prettyJsonEnabled = DEFAULT_PRETTY_JSON_ENABLED; } // JSON-RPC Websocket Options @@ -1387,8 +1390,6 @@ static class TxPoolOptionGroup { private Vertx vertx; private EnodeDnsConfiguration enodeDnsConfiguration; private KeyValueStorageProvider keyValueStorageProvider; - /** Sets GoQuorum compatibility mode. */ - protected Boolean isGoQuorumCompatibilityMode = false; /** * Besu command constructor. @@ -1531,13 +1532,9 @@ public void run() { try { configureLogging(true); - // Set the goquorum compatibility mode based on the genesis file + if (genesisFile != null) { genesisConfigOptions = readGenesisConfigOptions(); - - if (genesisConfigOptions.isQuorum()) { - enableGoQuorumCompatibilityMode(); - } } // set merge config on the basis of genesis config @@ -1571,6 +1568,7 @@ public void run() { runner.awaitStop(); } catch (final Exception e) { + logger.error("Failed to start Besu", e); throw new ParameterException(this.commandLine, e.getMessage(), e); } } @@ -1860,7 +1858,7 @@ private void configureNativeLibs() { } if (unstableNativeLibraryOptions.getNativeModExp() - && BigIntegerModularExponentiationPrecompiledContract.isNative()) { + && BigIntegerModularExponentiationPrecompiledContract.maybeEnableNative()) { logger.info("Using the native implementation of modexp"); } else { BigIntegerModularExponentiationPrecompiledContract.disableNative(); @@ -1884,12 +1882,6 @@ private void configureNativeLibs() { } if (getActualGenesisConfigOptions().getCancunTime().isPresent()) { - // if custom genesis provided, then trusted setup file is mandatory - if (genesisFile != null && kzgTrustedSetupFile == null) { - throw new ParameterException( - this.commandLine, - "--kzg-trusted-setup is mandatory when providing a custom genesis that support data blobs"); - } if (kzgTrustedSetupFile != null) { KZGPointEvalPrecompiledContract.init(kzgTrustedSetupFile); } else { @@ -2133,7 +2125,7 @@ private void issueOptionWarnings() { "--remote-connections-max-percentage")); // Check that block producer options work - if (!isMergeEnabled()) { + if (!isMergeEnabled() && getActualGenesisConfigOptions().isEthHash()) { CommandLineUtils.checkOptionDependencies( logger, commandLine, @@ -2144,17 +2136,18 @@ private void issueOptionWarnings() { "--min-gas-price", "--min-block-occupancy-ratio", "--miner-extra-data")); + + // Check that mining options are able to work + CommandLineUtils.checkOptionDependencies( + logger, + commandLine, + "--miner-enabled", + !minerOptionGroup.isMiningEnabled, + asList( + "--miner-stratum-enabled", + "--Xminer-remote-sealers-limit", + "--Xminer-remote-sealers-hashrate-ttl")); } - // Check that mining options are able to work - CommandLineUtils.checkOptionDependencies( - logger, - commandLine, - "--miner-enabled", - !minerOptionGroup.isMiningEnabled, - asList( - "--miner-stratum-enabled", - "--Xminer-remote-sealers-limit", - "--Xminer-remote-sealers-hashrate-ttl")); CommandLineUtils.failIfOptionDoesntMeetRequirement( commandLine, @@ -2199,8 +2192,6 @@ private void configure() throws Exception { ethNetworkConfig = updateNetworkConfig(network); - checkGoQuorumCompatibilityConfig(ethNetworkConfig); - jsonRpcConfiguration = jsonRpcConfiguration( jsonRPCHttpOptionGroup.rpcHttpPort, jsonRPCHttpOptionGroup.rpcHttpApis, hostsAllowlist); @@ -2458,6 +2449,7 @@ && rpcHttpAuthenticationCredentialsFile() == null jsonRpcConfiguration.setMaxBatchSize(jsonRPCHttpOptionGroup.rpcHttpMaxBatchSize); jsonRpcConfiguration.setMaxRequestContentLength( jsonRPCHttpOptionGroup.rpcHttpMaxRequestContentLength); + jsonRpcConfiguration.setPrettyJsonEnabled(jsonRPCHttpOptionGroup.prettyJsonEnabled); return jsonRpcConfiguration; } @@ -2810,27 +2802,11 @@ private Optional permissioningConfiguration() throws final PermissioningConfiguration permissioningConfiguration = new PermissioningConfiguration( localPermissioningConfigurationOptional, - Optional.of(smartContractPermissioningConfiguration), - quorumPermissioningConfig()); + Optional.of(smartContractPermissioningConfiguration)); return Optional.of(permissioningConfiguration); } - private Optional quorumPermissioningConfig() { - if (!isGoQuorumCompatibilityMode) { - return Optional.empty(); - } - - try { - final OptionalLong qip714BlockNumber = genesisConfigOptions.getQip714BlockNumber(); - return Optional.of( - GoQuorumPermissioningConfiguration.enabled( - qip714BlockNumber.orElse(QIP714_DEFAULT_BLOCK))); - } catch (final Exception e) { - throw new IllegalStateException("Error reading GoQuorum permissioning options", e); - } - } - private boolean localPermissionsEnabled() { return permissionsOptionGroup.permissionsAccountsEnabled || permissionsOptionGroup.permissionsNodesEnabled; @@ -2853,8 +2829,8 @@ private PrivacyParameters privacyParameters() { CommandLineUtils.checkMultiOptionDependencies( logger, commandLine, - "--privacy-url and/or --privacy-public-key-file ignored because none of --privacy-enabled or isQuorum (in genesis file) was defined.", - List.of(!privacyOptionGroup.isPrivacyEnabled, !isGoQuorumCompatibilityMode), + "--privacy-url and/or --privacy-public-key-file ignored because none of --privacy-enabled was defined.", + List.of(!privacyOptionGroup.isPrivacyEnabled), List.of("--privacy-url", "--privacy-public-key-file")); checkPrivacyTlsOptionsDependencies(); @@ -2868,10 +2844,6 @@ private PrivacyParameters privacyParameters() { if (isPruningEnabled()) { throw new ParameterException(commandLine, String.format("%s %s", "Pruning", errorSuffix)); } - if (isGoQuorumCompatibilityMode) { - throw new ParameterException( - commandLine, String.format("GoQuorum privacy is no longer supported in Besu")); - } if (Boolean.TRUE.equals(privacyOptionGroup.isPrivacyMultiTenancyEnabled) && Boolean.FALSE.equals(jsonRpcConfiguration.isAuthenticationEnabled()) @@ -3450,34 +3422,6 @@ private void addPortIfEnabled( } } - private void checkGoQuorumCompatibilityConfig(final EthNetworkConfig ethNetworkConfig) { - if (isGoQuorumCompatibilityMode) { - - logger.warn( - DEPRECATION_WARNING_MSG, - "isQuorum mode in genesis file (GoQuorum-compatible privacy mode)", - "--privacy-enabled"); - if (!minTransactionGasPrice.isZero()) { - throw new ParameterException( - this.commandLine, - "--min-gas-price must be set to zero if isQuorum mode is enabled in the genesis file."); - } - - if (ensureGoQuorumCompatibilityModeNotUsedOnMainnet(genesisConfigOptions, ethNetworkConfig)) { - throw new ParameterException(this.commandLine, "isQuorum mode cannot be used on Mainnet."); - } - } - } - - private static boolean ensureGoQuorumCompatibilityModeNotUsedOnMainnet( - final GenesisConfigOptions genesisConfigOptions, final EthNetworkConfig ethNetworkConfig) { - return ethNetworkConfig.getNetworkId().equals(MAINNET.getNetworkId()) - || genesisConfigOptions - .getChainId() - .map(chainId -> chainId.equals(MAINNET.getNetworkId())) - .orElse(false); - } - @VisibleForTesting String getLogLevel() { return loggingLevelOption.getLogLevel(); @@ -3531,13 +3475,6 @@ private Optional getEcCurveFromGenesisFile() { return genesisConfigOptions.getEcCurve(); } - /** Enables Go Quorum Compatibility mode. Visible for testing. */ - @VisibleForTesting - protected void enableGoQuorumCompatibilityMode() { - // this static flag is still used for GoQuorum permissioning compatibility - isGoQuorumCompatibilityMode = true; - } - private GenesisConfigOptions getActualGenesisConfigOptions() { return Optional.ofNullable(genesisConfigOptions) .orElseGet( @@ -3675,6 +3612,10 @@ private String generateConfigurationOverview() { builder.setHighSpecEnabled(); } + if (buildTransactionPoolConfiguration().getLayeredTxPoolEnabled()) { + builder.setLayeredTxPoolEnabled(); + } + return builder.build(); } } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilder.java b/besu/src/main/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilder.java index 1682aa14ba9..2cd374a2f57 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilder.java @@ -47,6 +47,7 @@ public class ConfigurationOverviewBuilder { private Collection engineApis; private String engineJwtFilePath; private boolean isHighSpec = false; + private boolean isLayeredTxPool = false; private Map environment; /** @@ -165,6 +166,16 @@ public ConfigurationOverviewBuilder setHighSpecEnabled() { return this; } + /** + * Sets experimental layered txpool enabled. + * + * @return the builder + */ + public ConfigurationOverviewBuilder setLayeredTxPoolEnabled() { + isLayeredTxPool = true; + return this; + } + /** * Sets the engine jwt file path. * @@ -237,7 +248,11 @@ public String build() { } if (isHighSpec) { - lines.add("High spec configuration enabled"); + lines.add("Experimental high spec configuration enabled"); + } + + if (isLayeredTxPool) { + lines.add("Experimental layered transaction pool configuration enabled"); } lines.add(""); diff --git a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java index aed7e9cb8bb..c5b9e8e8ebc 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java @@ -621,10 +621,7 @@ public BesuController build() { Optional maybePruner = Optional.empty(); if (isPruningEnabled) { - if (!storageProvider.isWorldStateIterable()) { - LOG.warn( - "Cannot enable pruning with current database version. Disabling. Resync to get the latest database version or disable pruning explicitly on the command line to remove this warning."); - } else if (dataStorageConfiguration.getDataStorageFormat().equals(DataStorageFormat.BONSAI)) { + if (dataStorageConfiguration.getDataStorageFormat().equals(DataStorageFormat.BONSAI)) { LOG.warn( "Cannot enable pruning with Bonsai data storage format. Disabling. Change the data storage format or disable pruning explicitly on the command line to remove this warning."); } else { diff --git a/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java index 790cb431018..1e894e0d9c5 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java @@ -83,7 +83,7 @@ protected MiningCoordinator createMiningCoordinator( new CliqueMinerExecutor( protocolContext, protocolSchedule, - transactionPool.getPendingTransactions(), + transactionPool, nodeKey, miningParameters, new CliqueBlockScheduler( diff --git a/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java index 0bd8c38bb80..53d4771b5cc 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java @@ -146,7 +146,7 @@ protected MiningCoordinator createMiningCoordinator( final BftProtocolSchedule bftProtocolSchedule = (BftProtocolSchedule) protocolSchedule; final BftBlockCreatorFactory blockCreatorFactory = new BftBlockCreatorFactory<>( - transactionPool.getPendingTransactions(), + transactionPool, protocolContext, bftProtocolSchedule, forksSchedule, @@ -310,7 +310,7 @@ private static MinedBlockObserver blockLogger( block.getHeader().getCoinbase().equals(localAddress) ? "Produced" : "Imported", block.getHeader().getNumber(), block.getBody().getTransactions().size(), - transactionPool.getPendingTransactions().size(), + transactionPool.count(), block.getHeader().getGasUsed(), (block.getHeader().getGasUsed() * 100.0) / block.getHeader().getGasLimit(), block.getHash().toHexString())); diff --git a/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java index 7bd297e9975..0fce7f484ce 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java @@ -49,7 +49,7 @@ protected MiningCoordinator createMiningCoordinator( new PoWMinerExecutor( protocolContext, protocolSchedule, - transactionPool.getPendingTransactions(), + transactionPool, miningParameters, new DefaultBlockScheduler( MainnetBlockHeaderValidator.MINIMUM_SECONDS_SINCE_PARENT, diff --git a/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java index 3ff13a472f2..8bdbee2d9b2 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java @@ -174,7 +174,7 @@ protected MiningCoordinator createTransitionMiningCoordinator( LOG.debug("Block builder executor status {}", blockBuilderExecutor); return CompletableFuture.runAsync(task, blockBuilderExecutor); }, - transactionPool.getPendingTransactions(), + transactionPool, miningParameters, backwardSyncContext, depositContractAddress); diff --git a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java index 126dfd0cd91..45fc52f3695 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java @@ -184,7 +184,7 @@ protected MiningCoordinator createMiningCoordinator( final BftProtocolSchedule bftProtocolSchedule = (BftProtocolSchedule) protocolSchedule; final BftBlockCreatorFactory blockCreatorFactory = new QbftBlockCreatorFactory( - transactionPool.getPendingTransactions(), + transactionPool, protocolContext, bftProtocolSchedule, qbftForksSchedule, @@ -381,7 +381,7 @@ private static MinedBlockObserver blockLogger( block.getHeader().getCoinbase().equals(localAddress) ? "Produced" : "Imported", block.getHeader().getNumber(), block.getBody().getTransactions().size(), - transactionPool.getPendingTransactions().size(), + transactionPool.count(), block.getHeader().getGasUsed(), (block.getHeader().getGasUsed() * 100.0) / block.getHeader().getGasLimit(), block.getHash().toHexString())); diff --git a/besu/src/main/java/org/hyperledger/besu/services/TraceServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/TraceServiceImpl.java index 321996d51ea..f98e96c15af 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/TraceServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/TraceServiceImpl.java @@ -15,8 +15,9 @@ package org.hyperledger.besu.services; import static com.google.common.base.Preconditions.checkArgument; +import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent; -import org.hyperledger.besu.datatypes.DataGas; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.TraceBlock.ChainUpdater; @@ -30,9 +31,9 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup; -import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.plugin.Unstable; import org.hyperledger.besu.plugin.services.TraceService; +import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer; import java.util.ArrayList; import java.util.List; @@ -68,7 +69,7 @@ public TraceServiceImpl( * @param tracer an instance of OperationTracer */ @Override - public void traceBlock(final long blockNumber, final OperationTracer tracer) { + public void traceBlock(final long blockNumber, final BlockAwareOperationTracer tracer) { checkArgument(tracer != null); final Optional block = blockchainQueries.getBlockchain().getBlockByNumber(blockNumber); block.ifPresent(value -> trace(value, tracer)); @@ -81,13 +82,13 @@ public void traceBlock(final long blockNumber, final OperationTracer tracer) { * @param tracer an instance of OperationTracer */ @Override - public void traceBlock(final Hash hash, final OperationTracer tracer) { + public void traceBlock(final Hash hash, final BlockAwareOperationTracer tracer) { checkArgument(tracer != null); final Optional block = blockchainQueries.getBlockchain().getBlockByHash(hash); block.ifPresent(value -> trace(value, tracer)); } - private void trace(final Block block, final OperationTracer tracer) { + private void trace(final Block block, final BlockAwareOperationTracer tracer) { LOG.debug("Tracing block {}", block.toLogString()); final List results = new ArrayList<>(); Tracer.processTracing( @@ -100,6 +101,9 @@ private void trace(final Block block, final OperationTracer tracer) { final MainnetTransactionProcessor transactionProcessor = protocolSpec.getTransactionProcessor(); final BlockHeader header = block.getHeader(); + + tracer.traceStartBlock(block.getHeader(), block.getBody()); + block .getBody() .getTransactions() @@ -107,13 +111,18 @@ private void trace(final Block block, final OperationTracer tracer) { transaction -> { final Optional maybeParentHeader = blockchain.getBlockHeader(header.getParentHash()); - final Wei dataGasPrice = + final Wei blobGasPrice = protocolSpec .getFeeMarket() - .dataPrice( + .blobGasPricePerGas( maybeParentHeader - .flatMap(BlockHeader::getExcessDataGas) - .orElse(DataGas.ZERO)); + .map( + parent -> + calculateExcessBlobGasForParent(protocolSpec, parent)) + .orElse(BlobGas.ZERO)); + + tracer.traceStartTransaction(transaction); + final TransactionProcessingResult result = transactionProcessor.processTransaction( blockchain, @@ -124,10 +133,16 @@ private void trace(final Block block, final OperationTracer tracer) { tracer, new CachingBlockHashLookup(header, blockchain), false, - dataGasPrice); + blobGasPrice); + + long transactionGasUsed = transaction.getGasLimit() - result.getGasRemaining(); + tracer.traceEndTransaction(result.getOutput(), transactionGasUsed, 0); + results.add(result); }); return Optional.of(results); }); + + tracer.traceEndBlock(block.getHeader(), block.getBody()); } } diff --git a/besu/src/test/java/org/hyperledger/besu/PrivacyReorgTest.java b/besu/src/test/java/org/hyperledger/besu/PrivacyReorgTest.java index 6a161f272d3..f831e1ecd59 100644 --- a/besu/src/test/java/org/hyperledger/besu/PrivacyReorgTest.java +++ b/besu/src/test/java/org/hyperledger/besu/PrivacyReorgTest.java @@ -28,6 +28,7 @@ import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.cryptoservices.NodeKeyUtils; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.enclave.Enclave; import org.hyperledger.besu.enclave.EnclaveFactory; @@ -59,7 +60,6 @@ import org.hyperledger.besu.evm.log.LogsBloomFilter; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.data.Restriction; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.testutil.TestClock; import java.io.IOException; diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index de87890b169..9a4fcc0fdda 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -155,19 +155,26 @@ public class BesuCommandTest extends CommandTestAbstract { .put("config", (new JsonObject()).put("chainId", GENESIS_CONFIG_TEST_CHAINID)); private static final JsonObject GENESIS_INVALID_DATA = (new JsonObject()).put("config", new JsonObject()); - private static final JsonObject VALID_GENESIS_QUORUM_INTEROP_ENABLED_WITH_CHAINID = - (new JsonObject()) - .put( - "config", - new JsonObject().put("isQuorum", true).put("chainId", GENESIS_CONFIG_TEST_CHAINID)); - private static final JsonObject INVALID_GENESIS_QUORUM_INTEROP_ENABLED_MAINNET = - (new JsonObject()).put("config", new JsonObject().put("isQuorum", true)); private static final JsonObject INVALID_GENESIS_EC_CURVE = (new JsonObject()).put("config", new JsonObject().put("ecCurve", "abcd")); private static final JsonObject VALID_GENESIS_EC_CURVE = (new JsonObject()).put("config", new JsonObject().put("ecCurve", "secp256k1")); private static final String ENCLAVE_PUBLIC_KEY_PATH = BesuCommand.class.getResource("/orion_publickey.pub").getPath(); + private static final JsonObject VALID_GENESIS_QBFT_POST_LONDON = + (new JsonObject()) + .put( + "config", + new JsonObject() + .put("londonBlock", 0) + .put("qbft", new JsonObject().put("blockperiodseconds", 5))); + private static final JsonObject VALID_GENESIS_IBFT2_POST_LONDON = + (new JsonObject()) + .put( + "config", + new JsonObject() + .put("londonBlock", 0) + .put("ibft2", new JsonObject().put("blockperiodseconds", 5))); private static final String[] VALID_ENODE_STRINGS = { "enode://" + VALID_NODE_ID + "@192.168.0.1:4567", @@ -3684,7 +3691,7 @@ public void stratumMiningIsEnabledWhenSpecified() throws Exception { @Test public void stratumMiningOptionsRequiresServiceToBeEnabled() { - parseCommand("--miner-stratum-enabled"); + parseCommand("--network", "dev", "--miner-stratum-enabled"); verifyOptionsConstraintLoggerCall("--miner-enabled", "--miner-stratum-enabled"); @@ -3698,7 +3705,7 @@ public void stratumMiningOptionsRequiresServiceToBeEnabled() { public void stratumMiningOptionsRequiresServiceToBeEnabledToml() throws IOException { final Path toml = createTempFile("toml", "miner-stratum-enabled=true\n"); - parseCommand("--config-file", toml.toString()); + parseCommand("--network", "dev", "--config-file", toml.toString()); verifyOptionsConstraintLoggerCall("--miner-enabled", "--miner-stratum-enabled"); @@ -3753,6 +3760,46 @@ public void blockProducingOptionsWarnsMinerShouldBeEnabledToml() throws IOExcept assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); } + @Test + public void blockProducingOptionsDoNotWarnWhenPoA() throws IOException { + + final Path genesisFileQBFT = createFakeGenesisFile(VALID_GENESIS_QBFT_POST_LONDON); + parseCommand( + "--genesis-file", + genesisFileQBFT.toString(), + "--min-gas-price", + "42", + "--miner-extra-data", + "0x1122334455667788990011223344556677889900112233445566778899001122"); + + verify(mockLogger, atMost(0)) + .warn( + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture()); + + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + + final Path genesisFileIBFT2 = createFakeGenesisFile(VALID_GENESIS_IBFT2_POST_LONDON); + parseCommand( + "--genesis-file", + genesisFileIBFT2.toString(), + "--min-gas-price", + "42", + "--miner-extra-data", + "0x1122334455667788990011223344556677889900112233445566778899001122"); + + verify(mockLogger, atMost(0)) + .warn( + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture()); + + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + } + @Test public void blockProducingOptionsDoNotWarnWhenMergeEnabled() { @@ -3801,6 +3848,33 @@ public void minGasPriceRequiresMainOptionToml() throws IOException { assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); } + @Test + public void minGasPriceDoesNotRequireMainOptionWhenPoA() throws IOException { + final Path genesisFileQBFT = createFakeGenesisFile(VALID_GENESIS_QBFT_POST_LONDON); + parseCommand("--genesis-file", genesisFileQBFT.toString(), "--min-gas-price", "0"); + + verify(mockLogger, atMost(0)) + .warn( + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture()); + + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + + final Path genesisFileIBFT2 = createFakeGenesisFile(VALID_GENESIS_IBFT2_POST_LONDON); + parseCommand("--genesis-file", genesisFileIBFT2.toString(), "--min-gas-price", "0"); + + verify(mockLogger, atMost(0)) + .warn( + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture()); + + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + } + @Test public void miningParametersAreCaptured() { final Address requestedCoinbase = Address.fromHexString("0000011111222223333344444"); @@ -4148,7 +4222,7 @@ public void privacyOptionsRequiresServiceToBeEnabled() { parseCommand("--privacy-url", ENCLAVE_URI, "--privacy-public-key-file", file.toString()); verifyMultiOptionsConstraintLoggerCall( - "--privacy-url and/or --privacy-public-key-file ignored because none of --privacy-enabled or isQuorum (in genesis file) was defined."); + "--privacy-url and/or --privacy-public-key-file ignored because none of --privacy-enabled was defined."); assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); @@ -4476,17 +4550,6 @@ public void privacyWithPruningMustError() { assertThat(commandOutput.toString(UTF_8)).isEmpty(); } - @Test - public void privacyWithGoQuorumModeMustError() throws IOException { - final Path genesisFile = - createFakeGenesisFile(VALID_GENESIS_QUORUM_INTEROP_ENABLED_WITH_CHAINID); - parseCommand( - "--privacy-enabled", "--genesis-file", genesisFile.toString(), "--min-gas-price", "0"); - - assertThat(commandErrorOutput.toString(UTF_8)) - .contains("GoQuorum privacy is no longer supported in Besu"); - } - @Rule public TemporaryFolder testFolder = new TemporaryFolder(); @Test @@ -5160,42 +5223,6 @@ public void assertThatCompatibilityEth64ForkIdIsPresentInHelpMessage() { assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); } - @Test - public void quorumInteropNotDefinedInGenesisDoesNotEnforceZeroGasPrice() throws IOException { - final Path genesisFile = createFakeGenesisFile(GENESIS_VALID_JSON); - parseCommand("--genesis-file", genesisFile.toString()); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void quorumInteropEnabledFailsWithoutGasPriceSet() throws IOException { - final Path genesisFile = - createFakeGenesisFile(VALID_GENESIS_QUORUM_INTEROP_ENABLED_WITH_CHAINID); - parseCommand("--genesis-file", genesisFile.toString()); - assertThat(commandErrorOutput.toString(UTF_8)) - .contains( - "--min-gas-price must be set to zero if isQuorum mode is enabled in the genesis file."); - } - - @Test - public void quorumInteropEnabledFailsWithoutGasPriceSetToZero() throws IOException { - final Path genesisFile = - createFakeGenesisFile(VALID_GENESIS_QUORUM_INTEROP_ENABLED_WITH_CHAINID); - parseCommand("--genesis-file", genesisFile.toString(), "--min-gas-price", "1"); - assertThat(commandErrorOutput.toString(UTF_8)) - .contains( - "--min-gas-price must be set to zero if isQuorum mode is enabled in the genesis file."); - } - - @Test - public void quorumInteropEnabledFailsWithMainnetChainId() throws IOException { - final Path genesisFile = - createFakeGenesisFile(INVALID_GENESIS_QUORUM_INTEROP_ENABLED_MAINNET.put("chainId", "1")); - parseCommand("--genesis-file", genesisFile.toString(), "--min-gas-price", "0"); - assertThat(commandErrorOutput.toString(UTF_8)) - .contains("isQuorum mode cannot be used on Mainnet."); - } - @Test public void assertThatCheckPortClashAcceptsAsExpected() throws Exception { // use WS port for HTTP @@ -5636,18 +5663,6 @@ public void kzgTrustedSetupFileRequiresDataBlobEnabledNetwork() throws IOExcepti .contains("--kzg-trusted-setup can only be specified on networks with data blobs enabled"); } - @Test - public void kzgTrustedSetupFileIsMandatoryWithCustomGenesisFile() - throws IOException, URISyntaxException { - final Path genesisFileWithBlobs = createFakeGenesisFile(GENESIS_WITH_DATA_BLOBS_ENABLED); - parseCommand("--genesis-file", genesisFileWithBlobs.toString()); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)) - .contains( - "--kzg-trusted-setup is mandatory when providing a custom genesis that support data blobs"); - } - @Test public void kzgTrustedSetupFileLoadedWithCustomGenesisFile() throws IOException, URISyntaxException { diff --git a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java index 3b9aafe35dc..fc6f013b2da 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java @@ -73,6 +73,7 @@ import org.hyperledger.besu.plugin.services.securitymodule.SecurityModule; import org.hyperledger.besu.plugin.services.storage.KeyValueStorageFactory; import org.hyperledger.besu.plugin.services.storage.PrivacyKeyValueStorageFactory; +import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; import org.hyperledger.besu.services.BesuPluginContextImpl; import org.hyperledger.besu.services.PermissioningServiceImpl; import org.hyperledger.besu.services.PrivacyPluginServiceImpl; @@ -312,7 +313,7 @@ public void initMocks() throws Exception { .when(securityModuleService.getByName(eq("localfile"))) .thenReturn(Optional.of(() -> securityModule)); lenient() - .when(rocksDBSPrivacyStorageFactory.create(any(), any(), any())) + .when(rocksDBSPrivacyStorageFactory.create(any(SegmentIdentifier.class), any(), any())) .thenReturn(new InMemoryKeyValueStorage()); lenient() diff --git a/besu/src/test/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilderTest.java index bb330127451..33ed9bc2d16 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilderTest.java @@ -137,10 +137,22 @@ void setEngineApis() { @Test void setHighSpecEnabled() { final String highSpecNotEnabled = builder.build(); - assertThat(highSpecNotEnabled).doesNotContain("High spec configuration enabled"); + assertThat(highSpecNotEnabled).doesNotContain("Experimental high spec configuration enabled"); builder.setHighSpecEnabled(); final String highSpecEnabled = builder.build(); - assertThat(highSpecEnabled).contains("High spec configuration enabled"); + assertThat(highSpecEnabled).contains("Experimental high spec configuration enabled"); + } + + @Test + void setLayeredTxPoolEnabled() { + final String layeredTxPoolDisabled = builder.build(); + assertThat(layeredTxPoolDisabled) + .doesNotContain("Experimental layered transaction pool configuration enabled"); + + builder.setLayeredTxPoolEnabled(); + final String layeredTxPoolEnabled = builder.build(); + assertThat(layeredTxPoolEnabled) + .contains("Experimental layered transaction pool configuration enabled"); } } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/subcommands/storage/StorageSubCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/subcommands/storage/StorageSubCommandTest.java index a8a1bedc649..e3b67d8b430 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/subcommands/storage/StorageSubCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/subcommands/storage/StorageSubCommandTest.java @@ -23,13 +23,18 @@ import static org.hyperledger.besu.ethereum.core.VariablesStorageHelper.getSampleVariableValues; import static org.hyperledger.besu.ethereum.core.VariablesStorageHelper.populateBlockchainStorage; import static org.hyperledger.besu.ethereum.core.VariablesStorageHelper.populateVariablesStorage; +import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.BLOCKCHAIN; +import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.VARIABLES; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; import org.hyperledger.besu.cli.CommandTestAbstract; -import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; +import org.hyperledger.besu.services.kvstore.SegmentedInMemoryKeyValueStorage; +import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorageAdapter; + +import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; @@ -58,13 +63,14 @@ public void storageRevertVariablesSubCommandExists() { @Test public void revertVariables() { - final var kvVariables = new InMemoryKeyValueStorage(); - final var kvBlockchain = new InMemoryKeyValueStorage(); - when(rocksDBStorageFactory.create(eq(KeyValueSegmentIdentifier.VARIABLES), any(), any())) - .thenReturn(kvVariables); - when(rocksDBStorageFactory.create(eq(KeyValueSegmentIdentifier.BLOCKCHAIN), any(), any())) - .thenReturn(kvBlockchain); - + final var kvVariablesSeg = new SegmentedInMemoryKeyValueStorage(); + final var kvVariables = new SegmentedKeyValueStorageAdapter(VARIABLES, kvVariablesSeg); + final var kvBlockchainSeg = new SegmentedInMemoryKeyValueStorage(); + final var kvBlockchain = new SegmentedKeyValueStorageAdapter(BLOCKCHAIN, kvBlockchainSeg); + when(rocksDBStorageFactory.create(eq(List.of(VARIABLES)), any(), any())) + .thenReturn(kvVariablesSeg); + when(rocksDBStorageFactory.create(eq(List.of(BLOCKCHAIN)), any(), any())) + .thenReturn(kvBlockchainSeg); final var variableValues = getSampleVariableValues(); assertNoVariablesInStorage(kvBlockchain); populateVariablesStorage(kvVariables, variableValues); @@ -77,12 +83,14 @@ public void revertVariables() { @Test public void revertVariablesWhenSomeVariablesDoNotExist() { - final var kvVariables = new InMemoryKeyValueStorage(); - final var kvBlockchain = new InMemoryKeyValueStorage(); - when(rocksDBStorageFactory.create(eq(KeyValueSegmentIdentifier.VARIABLES), any(), any())) - .thenReturn(kvVariables); - when(rocksDBStorageFactory.create(eq(KeyValueSegmentIdentifier.BLOCKCHAIN), any(), any())) - .thenReturn(kvBlockchain); + final var kvVariablesSeg = new SegmentedInMemoryKeyValueStorage(); + final var kvVariables = new SegmentedKeyValueStorageAdapter(VARIABLES, kvVariablesSeg); + final var kvBlockchainSeg = new SegmentedInMemoryKeyValueStorage(); + final var kvBlockchain = new SegmentedKeyValueStorageAdapter(BLOCKCHAIN, kvBlockchainSeg); + when(rocksDBStorageFactory.create(eq(List.of(VARIABLES)), any(), any())) + .thenReturn(kvVariablesSeg); + when(rocksDBStorageFactory.create(eq(List.of(BLOCKCHAIN)), any(), any())) + .thenReturn(kvBlockchainSeg); final var variableValues = getSampleVariableValues(); variableValues.remove(FINALIZED_BLOCK_HASH); @@ -100,10 +108,8 @@ public void revertVariablesWhenSomeVariablesDoNotExist() { public void doesNothingWhenVariablesAlreadyReverted() { final var kvVariables = new InMemoryKeyValueStorage(); final var kvBlockchain = new InMemoryKeyValueStorage(); - when(rocksDBStorageFactory.create(eq(KeyValueSegmentIdentifier.VARIABLES), any(), any())) - .thenReturn(kvVariables); - when(rocksDBStorageFactory.create(eq(KeyValueSegmentIdentifier.BLOCKCHAIN), any(), any())) - .thenReturn(kvBlockchain); + when(rocksDBStorageFactory.create(eq(VARIABLES), any(), any())).thenReturn(kvVariables); + when(rocksDBStorageFactory.create(eq(BLOCKCHAIN), any(), any())).thenReturn(kvBlockchain); final var variableValues = getSampleVariableValues(); assertNoVariablesInStorage(kvVariables); diff --git a/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java index bd8d06d2a5e..fd35430e273 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java @@ -134,7 +134,6 @@ public void setup() { when(storageProvider.createWorldStateStorage(DataStorageFormat.FOREST)) .thenReturn(worldStateStorage); when(storageProvider.createWorldStatePreimageStorage()).thenReturn(worldStatePreimageStorage); - when(storageProvider.isWorldStateIterable()).thenReturn(true); when(worldStateStorage.isWorldStateAvailable(any(), any())).thenReturn(true); when(worldStatePreimageStorage.updater()) diff --git a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java index 4ce430e787d..281cb2b2ea1 100644 --- a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java +++ b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java @@ -23,6 +23,7 @@ import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.DefaultBlockchain; @@ -48,9 +49,9 @@ import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolFactory; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; -import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionValidator; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; +import org.hyperledger.besu.ethereum.mainnet.TransactionValidatorFactory; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; @@ -61,7 +62,6 @@ import org.hyperledger.besu.plugin.data.LogWithMetadata; import org.hyperledger.besu.plugin.data.PropagatedBlockContext; import org.hyperledger.besu.plugin.data.SyncStatus; -import org.hyperledger.besu.plugin.data.Transaction; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import org.hyperledger.besu.testutil.TestClock; @@ -79,6 +79,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Answers; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -99,7 +100,10 @@ public class BesuEventsImplTest { @Mock private EthContext mockEthContext; @Mock private EthMessages mockEthMessages; @Mock private EthScheduler mockEthScheduler; - @Mock private MainnetTransactionValidator mockTransactionValidator; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private TransactionValidatorFactory mockTransactionValidatorFactory; + @Mock private ProtocolSpec mockProtocolSpec; @Mock private WorldStateArchive mockWorldStateArchive; @Mock private MutableWorldState mockWorldState; @@ -128,11 +132,12 @@ public void setUp() { when(mockProtocolContext.getBlockchain()).thenReturn(blockchain); when(mockProtocolContext.getWorldStateArchive()).thenReturn(mockWorldStateArchive); when(mockProtocolSchedule.getByBlockHeader(any())).thenReturn(mockProtocolSpec); - when(mockProtocolSpec.getTransactionValidator()).thenReturn(mockTransactionValidator); + when(mockProtocolSpec.getTransactionValidatorFactory()) + .thenReturn(mockTransactionValidatorFactory); when(mockProtocolSpec.getFeeMarket()).thenReturn(FeeMarket.london(0L)); - when(mockTransactionValidator.validate(any(), any(Optional.class), any())) + when(mockTransactionValidatorFactory.get().validate(any(), any(Optional.class), any())) .thenReturn(ValidationResult.valid()); - when(mockTransactionValidator.validateForSender(any(), any(), any())) + when(mockTransactionValidatorFactory.get().validateForSender(any(), any(), any())) .thenReturn(ValidationResult.valid()); when(mockWorldStateArchive.getMutable(any(), anyBoolean())) .thenReturn(Optional.of(mockWorldState)); @@ -195,7 +200,7 @@ private void setSyncTarget() { mock(EthPeer.class), new org.hyperledger.besu.ethereum.core.BlockHeader( null, null, null, null, null, null, null, null, 1, 1, 1, 1, null, null, null, 1, null, - null, null, null)); + null, null, null, null)); } private void clearSyncTarget() { diff --git a/besu/src/test/resources/everything_config.toml b/besu/src/test/resources/everything_config.toml index d0bb8c2cf76..459346dc537 100644 --- a/besu/src/test/resources/everything_config.toml +++ b/besu/src/test/resources/everything_config.toml @@ -87,6 +87,7 @@ rpc-http-tls-cipher-suites=["TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_R rpc-http-max-batch-size=1 rpc-http-max-request-content-length = 5242880 rpc-max-logs-range=100 +json-pretty-print-enabled=false # PRIVACY TLS privacy-tls-enabled=false diff --git a/besu/src/test/resources/trusted_setup.txt b/besu/src/test/resources/trusted_setup.txt index c22cfff7515..26612cb8876 100644 --- a/besu/src/test/resources/trusted_setup.txt +++ b/besu/src/test/resources/trusted_setup.txt @@ -1,4101 +1,4101 @@ 4096 65 -97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb -854262641262cb9e056a8512808ea6864d903dbcad713fd6da8dddfa5ce40d85612c912063ace060ed8c4bf005bab839 -86f708eee5ae0cf40be36993e760d9cb3b2371f22db3209947c5d21ea68e55186b30871c50bf11ef29e5248bf42d5678 -94f9c0bafb23cbbf34a93a64243e3e0f934b57593651f3464de7dc174468123d9698f1b9dfa22bb5b6eb96eae002f29f -82b8775b874067bdd4479ac237f8d56036a742c17901354caaf38bf8c70e696650fbec76f0cd941ed8c658f44ea359ff -a7ce299c79c7d7e4f1adecd754c5aff8a720728ab27f5737b7b399f72724407ac54965088596375b8c876665ed8e4ff1 -81ca4c808a76a6f217f8b0540ff400199295da69b2587b7be6aeb56447fa4fac08d154a27c4aa6082bc40660078d36e9 -a70bad5311c97f1f3fea5d3375da1a11ba948aca41609ea28666dd343e07af766834e1256dc685ac1dcd915073250864 -a91c2911a658ba79f56abe30716a3398387630e785b351b07344022a04b2f5c90de5573bd6e8048fe8878dde19336c5b -a8c560283fce9813bcbaddfb78cff93efcbc39b33025cfad94ebd40942a9fa605d2a947dc3a1f03c2e454075892e96bf -aa14f07fbd2c1ce7bd995e335c69b5f675ea573517c1834e787b30ab4fa10aecc62ecc5e617ac8a539af1aff114dc9ec -87f03429aff126b7c5a918423da278e17b5f48a4cdd6d34dba77a75f4f99e26a417e65d6a8579bcb2eaaf1d4d8c64dce -b1ac81ba91ede78315f712d524e9d821a152203f04141ba77f4e481ad5881473dff14a71788ce941f0905b429e7ee5b2 -8f5c2af611ddfa3edf7e442d00e56a24d615bac848c05070c908c741ba18b67eb2e82e6651c9b3c70fb8edbf051810c4 -aa4115b19221e4d17cc335d4f9b0aad22df566231f2286d550e97ff2875cbc419edfa189c4ecb24001123b95c6aaa2da -b363ba913969df0debd4e2712ae6e9177ce82e169ce7e0ff1d7616ef8e352aff3efb40fffbf7bff1b21cb8a33e19b455 -b1013d778727d20466778cea47e1bf56a77168a8ce1b33bb1265f66438ab2bf4a7df4f4142b8681f2993ea9baf798d17 -83b7250ee17d8529207db97b73c1c4a92ac076951a577ce2fe3a2cd633b461c1820c139ab36a895a5962e143c6198386 -86d180bd2f0a4919764e6f4e846ec0d5ebe44060ec1e529ed15101d7e531bf1b8f9412916ea5aeb93b37b2d7c6bfb408 -827451462c79d74b504c01bda199481b3c70416f66a95b2216686ca4d48da48932b0d323d0cd630a1e86e8033e832e5f -b789d217cb12c334fedff0ae01f85b96e968fb98761755d1ba3ee17934e8fbd83172225df7c0c6cb99432a30a0ef8c24 -b730e5412dfbd646b0d2fe084a1a32eb5596c3fe8a5bc0f430151804f9e67f05f70b522e9aef08082b0afdc652a1d213 -9987653bacd9bc1659b17f6964aec06ea63b787813d4601bee0479706aed5595ac82c87ed4f96f0cd30c19e1d9510a91 -9506a9ba38f1d26c35a17c7e2554e28eb347a19cef523846a2559fb80fb40306b2f85bdc2c9fb98c2267df21c1ee3589 -98dda58de74c0cdaef97b2826b4a9d53c9e9ea592dc0a755ccf5b3fbc1264979578563f5979aaa246e679918053c5f83 -b00aaa16841ab53883af481e2f925050f5f7bf7d8088bc696f55f30593bdbbaf434f5d2b46095ed097b6cdb96c8fbc3b -b463d656480f89335d3a840a7b9398877003985388871b148ba708c60f9857c7585ef17c8b2ae67fbb191c04ad61e692 -80af54f3d0584126e23635276d650292baf7e3e12bb06468708107bcd80937d36575721ee7472c5f085ffa71dbf438ad -94ccb8ade84e834685110c96908b42e10d2184208f434d7f98d96cc158e0c0c95135979600e5e9f465d5846b0bb3c787 -8e13674b00c633d7cceb4f6ecd61e4f99420d6cccf9db5e81f8c90f6c661bc76e10939b83b56c225fce8565f525d4fa4 -a46a15b2e671c1a1df2490768dec1093caf537e1a21fbc11ff8ba8b21b9f2be8d50257027d9357df20d9fbb1307d7249 -b8ed532d48b0533a3084d7a5eea7b401255c5825e9a1b80ed81fd530cd69e347d152b1ad8a899acff7d68e0103bbfbde -ad6b7df980ebaa24177d830c4aa522d6179a9a489257f60ee6604cccc2cbe90fb1f72aa9d5bee0d3a88f73b179485f56 -a56855e9fcf62ceef3043991a93ec24f8f6b5667ef5fb7ad1771249ece68a73580ec3cf3e58a009ca4650c01241ad172 -ab2f25517d4b0b33d317eb78d091d3c3f98dc352b8a3e4650f7005f9327129e23d95f38eaeda5e9b51c50a31d20a4c20 -a2d4071385b8a421da86f39739eaadcdea5685466feb6ac083cba0ea4c71dbbdf655032097276d703f9a77a4ca6fab03 -a8681d7c258984f01e92e92c95738692b7bbd59c3a802adf4dda8d34add69590b080391c09e98e3b75c085c9f191e5e5 -97685643da6c07b5e5fe91393122813ba11c8ef3dbd43a03b3a22a7a1603201fd516c1929418eafb14039270694c239a -a7bb3b85d6101e4fb0bcf540f52041cdb3e819d517465e342b832f0e91346a9a18bdb38845ea4d2b71ab87ef3bf59f96 -8afc90b7d35336fdcf8f81cd024e921e244520ecfcb5a3994f2bbd595366b68bfa792a8dceb11e1e889b11432c9dad6b -94d9db7bd04f962d8d6caa3b7aa0f19acbd58a09d35ae187158d77e537d2fc65215f51f1afd62d4ba378e7d176a680f9 -ad62d7c01b14b6f97e6084ec9f9d084f106a7ff3d603032e6e34c027cdce4b0fe3c20ac7931f1209439a59c9fede4815 -a5b44a87bd0ada7498e011e495a2818a8694746c4e7dc9d24c0c1096f54be6439e08c1b11c10d7c4bf68fe392000e971 -828626c6609acc599f1bf216e9a4310fc3cb227e0d2e47bfe3360239427c8b0cc300cddf92456a5c36620596a6d37027 -8380f91baac6447dd39886455ec5d99b874ac114a3c6a6ded18fc4ef69c2208ec19732428d8329d200a69f31792b852e -85a8389b522b0a686234450165514127006baaa3907f6eb29c976522591a542ffb681b3b88c4886814fd7ba3cc8110f7 -b8ae7949ddafad37c0bc4d48325a7cbcd3096fb92c04a027c650a03cc609c7eac250d6a7ba341616bc36f64f1b4c8be4 -8f9b9d2c2ab5c85abe946ed9986e0f304281b277d4d48c7760ea2331b55a9e9a1c4d53a6bdd83fa6294f421ca7431e29 -9464b906ea8bc994b31e03c5f2af2be0724a43293fd42cbd2263b2de75a2ec04832d1100ce62ac2c0708f05fb6bb3ce6 -93d923f6805e7cf972d8387b352d77215724a3e1f5489c4114fcf0b25fc2231963eda872387a1369a02b2e8b888d6427 -aba4af392884eb7283fc5611ddc1cebfecf9477462e951bdae650e311606e129b4424452a3a14717146f954a7fa1cfc3 -a8d0bab694d116e4f21fa19ff8fa4c6fe4061dbb54cbceda8235a7e05159737f87e008beccb90df0bac9c7d572281903 -85743e3ecbac7ae04a81a09c2961397aa4bd20401533cd24d5fc0693cbfbdd2b37bbee6dec2ae5d0a66250d1fcba6944 -80ae913447d7d3f6c54f9cb584aa1603308146daeb3024c8e06ede66ddc97821df09f9591453e9b617b828a02d54c719 -803c2a64bb1c68890b5f1909be3aa180830ee3ef316d3aac38bfd909e2b19d890525e18e8fc2f405ee70ac14f5569b3f -964d2968724eb790f2f42263fcaaa1869c373b57b3eeee904f8b36f13169f07d5e29cb2b03c74d3a7adb772e91d5a59a -98a72ce71a57262aa058643a5cd39af64cc9eee88bef7edb003143983f29d87c7f9658b1ec89712f79f6f79dc24a6a45 -91f3479c5d7c76acd2d51883961179efc975c714720187cc9c0aa7aeff71ca1b3e2db5b0a90fd3ff6abf880ebc49fe36 -84312757edd09f111420bfede10ed3c1fa39d1723ddb9bd4d0004c829f0c1eb060e9648fd75f2e5427a67a5b37945a9f -95edd726cf4042a082d786262304c51d8d5e6a89b1b58e825a11febe5f861d5ce076bdcb2fc0a5dfa95eb2e5b0ffc32e -96500da38f942871d78fcc46cda1e72944c7888b538b82e2a979f149e5061a20c7602860f82b76510d02efdf3a911f5a -8ac62eda98bef8864df243696b53651a02a391b898535d2d76ac5a8e9322e0178a290c83f5afe72ffe80ad56183469e3 -8ab2d4427fb6d3da5cf6c59835bdb39fb0c2de82c213b5de77edae3304458ea505511bd98fda95bdbbb9058bd5e92c34 -ab67c4344a5080930029ca3b803883ad05ca004ddefb48d5164e71a1c6dd96b27aaec70f62b39bb126ce1a57bbff1453 -86c6bf91686bff714a873a78b0fe449db5317a5172a0a14eb3a96b2997b888d5d3f440de8baa32a6966fe44c3625b014 -81d4f1e9d9e550125290d993a4886d46aac8cb29dbbba1e608aefc3432569c5faf14d8b49fcb485d9b75b649ad6b2fa5 -8594140f253ced6fa98dd90ab4f38899916bcc6f1052572f182e46c00752f3053c390512338a0bc8f8c27a91916b855f -911284d4fad4999bb37590206d582b9e62ffbb815f414fd829f5b2843e6f0e1a132cd64464c131d5a0f476469a37daa1 -8631a6a4987410982db9c0ba632023a5b613f553b6b8ffd3cfd501b2417523ba8cf06741c62f24b405554bd93e39e626 -906ac35d22794a10a7273fdbca499fd921799b1ce9414643779dce9e1ec37920a5aa2caceb4b70a0eaf56c6032ef1b43 -87374cdb8b7a1ce3c182b31eec465d435e35df782fe3a11f421462b48cf56c6fef2a9cb8ee4fe89672ba7804156d9e3a -a1f825e0246eee506c8ce40f849a17f75e8a0d6fc3f68b6a4dd431173b4fe997d30dca53005829e4e2422a4077ce35c7 -875ad0379abd9873f6634692e33e9b36353e1a0d15b13d3215eb591244e1f236eb2f8f75274ca7f096179d1714fa68b7 -b87b4e1acc09c5701fd9d75375ab896f178c1b3648fb9a2e2c6e1478778156decc32cd390766f3e80b36beb1e3a6bdec -836ca80949269eb52395776ac5ceb35b7df717a981c5cbbbb627f73c274aa8164e973a7b01012fa72a02404e878a9918 -a770b13a8f07f74e5a75842b18f2520f6d0be42c865a29dd81bfe485e69a83c40ad10ce229afce276ccc9cb46c54b912 -b4b919322bba2866baeed38bf0e2389d4fe6ab6166597e87dbfee75acac7c2f5ad3bef55293b56957c103d5825051bb5 -b6171f1bbeedb3ee1af368c9c9f327d1dc3e55aeaffbe15f14db8038cd72540b62fe65f44ad0b5486dcf4023f0e91af8 -8e42d0c1e8e8c2ccaf06edcc3c686aed56b8c987f9d68f20937fc088120a410cb92fb0ab45bba5db70b86876015a6b72 -937bcff1af9685fd0d1f6616acf91d97ac9fcb1eb96d49d1c880c9945c1fcf1414f63d59fb78348d08a8546f6e83e407 -a6eeb4873c0531fbcd407c2e702c68e4980fa77c9c032b9913b89031702cfa56f335fc413576c37ac4d523357a841203 -b3962b5eed69cfa27fb94edba74b6cedd7569352ea71861494dd579da96d9743655b6308e54f8a42ee6d7e805c1bc0f9 -8eea944dce7202b033ce734c9e88e82dd760c916e00b217cf1f00bf6ec5f20e21885d5fe95d6138871d167de4c46359e -81e6c7b356e2703ee333a9dfeb2b54260636422b9bda118e0523a20ce83b30fefc2f019e8291a8db05d207f0fa7332fb -83817f6164dc9e8e2506252511cb9871a8c9b595dde45f67e75ce3505f947b3fb3b804c18c054ad13b1518a98f59f008 -a9ab4dbe7699e7982cd750d7effe031f273fab6b2e024a0b4f8beccb5c280903bcd3f2400b9cac7e8c94e157b4658ab6 -84d2e3bc66fc6b59a1ee98b8981ebca0901d846c40d207e5bb5004ec9339d28956d16f054af52453f6a7ff3fc66c346b -b24bf0f69c3e86f610b6d27885ac5f4556fbb14e8286681538ddbb0b4921aa0d5604fedef0daf4a514ae15268a640174 -a4be967f7f31995562669bf9587f5463bd1d9873fe9169687790e75961efa5ce2252fd21276d022f580de23527282838 -a3f3c4e673b302bdb91fa3cbdec88499752e6ffe37e2215d69b8a426f4da98c3a10e4c659e77c656172e4e8b1b1a41bb -b704ffbb3434563bbbce69ca7e812a8bd30757b1e90630bf3261735f9ea221524b36f97dec324ffd209bef45bdf6f2b4 -959dde49f15c663a2de000195e182a11d8c396c1380f98322cbe5521b697bc3bec3223ca9e94ee2734c4ffdfb6a19e8c -a469685143cd82b78d7b1854c350da63819d9d86670e9b35a72381d0362cf5c3f1d24e22ef2ea6a12176c9dad39fd51c -adb97ef4463e5e13d91b75a3086d72a841a60be278e9651d9ac5f76c9537bac5eac33424a1ea00522b3357fcefea0738 -a4597b2ced7566576e71b4f105b5ee48aa4ffca93901e9b626f7059824f53be3e8f3560e6861285f3d97fe88054fee83 -a18d9b1b81564447f798ce5966bf10c823aedb14b143972eb4dbbba9312fc79f46635aa016cd20c53be90f170f06fb84 -ac4724069177d3c6ac1b72ea2a7d6bc5ac3d4b2a4dbad124152fbd170c9c1038cdcf255d162a25c14ae8df11a3849945 -892683f64179ba84f6a447c5c7489e3cdf02474d2837dd7bf3b82a4dd05a6461ce94fff28d65b9539cacaf47dddedbc1 -a68ad797bbc1b2909e216a0b3f39aa6c3e4dfc7a49f81a206b530ec0c6ba30f871e4a0053625aeb99448026ae2e0a6eb -964ff8badf35b6b93be6d97209d87f4ac8847be1c2ac4bcafa1db5c3f604f61834c85b3dcf58af50d09bd03ff8d78f27 -b76dc9ec64b1fab7be269097a18a77144623d37bc656934fa1562817c922485e69b18ef40413ee309e100fde645fa7b2 -b2a812be6e69f284580ebdec5ae2cdffd587bc7eae10989e9d2f290498b1eaa934b148ec7783edec300be5d7a9b34af0 -85ffcabc623f8ffc58c5f640f857e27b7c105359315a3969f346e1366acb2af88f4acc025b299b9c324a8535c380a2c5 -8d0140f79fb8ef02d13b1d51c4ba1af5b5ffb19322f88912215d4198f9a592f7ec6800c8a3ca853a3b68f9bf0353a13a -b3174deb53c1ebb6a1e16c915cac287573b70fe4e0036e8e971e8e807a77362ede632f6e3f29cb87a80a318213946ff1 -8c58d603f6420e3f55522ec2853065125af4e7773a909e28296552f7f8ec4691ada9211d834dca38e118f432b6cfe03b -aa7ac268e155ff074bfc197844e21fc2a9f9aec9b50d9cda63f50d3c4fbbf9221e6fac3a6ba0f7e4cde71fecd493a15d -a191337721bc9fd2d3ec2ca6f6f97ca2462ef5e207464bf9e746a650a67d69abb5f578a8238521cee3f704b275845e47 -93521abea8f38c103ebed3313a3af8f27f03c9a54681847f4201bf9f72f1f63064b18175986fca64f80b4380905e894c -a1b9d063d6538885f9826b84944123d7d6027dd030aef29fd6229f4cf5d32404f7dd0e899a0c8f4b6bdf4649e8a8966f -a15d5497f0fd2fd0b2c2e5df58a25a72a9d99df8215951ea58c15569d312c6f096f78034f6a8502f808e649f6cb9283a -b3c275306852612362e1073d0f4da3ce598dc5fac3f3eefa22ccee35dd57a4caae347b43342cd1f6a6e068d3ea9fd30c -94eb678e0700bf39caf428c65bbf2fbf7f601c39e382570a4df9186ff1dd5a958d78e051a5fd084e4f75536a14b7690b -97b13995bbcb8e824bec28488994a830a9c1f34ae4c1a16d5528d57f09e4c8b5d81677ea9f979f0acb8cac629ee09c85 -817c99ad48bc05bd4fd29f952dbdc5ef56bb02f3442c18e3b91cb6d72ac2d2a5df901c099165ded1bee62c3ed13c41e8 -a884acf980f6470e11cff347692d8a7cb7860d4822112f7bfeb02efb05948ea98c837d5d98dd7a104aa36eb8f016a0f4 -95debd2ed23a23a16a393f59f666cfc864f63751238b73981faec4a85b4c04cfa11520c9e4cbe4e23fe80e86c260093a -937b4691c59453bc6cf6468ed5b17dbb25496bfa3817798562cd5fd86ab5ee35745991afea2fe271ce0fbe5a990c41c7 -b4da98c879e6b475c540ff2c5501299f0e3e97b7b93beb45faef1253f7de96968898505e672cfc4a3ee7e20c1f72c256 -8ec9d806f344d0c675bb5ecd47c54defb5f059a5233dfb2d459632b9b22edd6c4b8c47fd7899ab13e35f37ede9b124f8 -aab4408410abb4d2cd98694f71b5452e6fab2690daa3066b3f9747e7dc40b57259d52e6fddeaeeca227b733d049b9694 -b85a12f39808961c331038159255140a61dedc56050345a2eb13b1f7d140ae07b353d68d22f2cf60925fe66e598213e9 -b61bc3bd68bffdbe9731f48fcd523491da04dab83add49fde390070513b9ad87a489010f1ccfe6f54e9a48edaf88b5f9 -8f50f6d8235824cf25031f09e4b139bd89c1090269dae95a5aa0dacaf5f9b59c329a5a3cdddf9efe6c77cd61f481dcbc -91a543b85e18f34361d7df5ece8504d456627fbce65abff437007e9109359538a03996e35393a40f0586f962921eccaf -b7557bc52931324dd4c58d0e63c89a8dbdd2d00d0baf79d81d7a062aedd2de9dd743ea30fb031b18c806ba03175d7e1d -8e056b842a9af7aeb6c0d113a3acc8bfb5c6a8980fa81869747f75abef76b7fd20cb67694e70016e3de6e7821cde030b -966c00fd6472bb13ffa531d8eedc145ffb7733114e0f4a6a9fddb34ab7601f6cfb056460f757636230b692453d8b31d6 -a25d85947c6939547fbee088e0131988053c5bb23aa2bd48ca764f4ef2b29235a817b8918d1de6865695977a95711e9d -958567f217ce7a6d74861777801663d7175eeeca8ff62e240582fb603ac91dc402331034fb4855632352df2328fe0233 -85e53f3802a7d32dec2db84fad7f8c8fc856037cc0cd4ef9a8988e97ab580d4b929023f1fcde7633828b5e8bcdab08c7 -878d1fbbedee7f7ff72eaa3848d7f6bc3cd13b40149278b3afe5e3621e6d1f0386f8ede32971d3f33be189c927bef6f7 -b041e880e4ecb254f6f8d92635a1ef3be3d5d885c751f247bec2d8a016aada6a7fd2f7c599f458ee466886abe721bba9 -920747dac9f35ba0b2670f82c762a71ee9bfb9e490825fb7ed613bf2548ef4ea00bc01e9d2c952dd9c56f3586a3ffb49 -800005cefda1ddb860fd8974342fe315d227902dcb5f3736f8b9ad1fa2f8fbeff8c8ba0eb3f0c21a6706f288ef4bb13b -91f2b822b728fc5d1f15b69a303985bab14c08df5e929decbfa5aa5689f3cd93ccfe19ab10499d31df9d38c84039e492 -957a909486abd85b1e627a4739c7d212cd03f2b62952045b704c415acdf2e6c0cc627af93f382836603f33d1a716ac7d -9733ec7a30ed833cc1e7e0ada4badddb1cd1908bcbd3d4e4694576421c94090a9297aacd7f42d9d305b87d711828304a -ac2785a0dadfd246fe12b63f759e9f021006cff4f06b2b5a9986f0b02a40f29513feb1c9044af6e27d1c5029b1e1db35 -948b22bddf55f4b4bc26892e83f70b882a0458582ed87fbbc81bbd037c946d833c19162327354240c42e05cfef55394b -a49c5d81544028d56f4caf8699477bcda589c65f6754dd40a487ef88d93925008dc7fefa6d458619d51a54b3edb5e5c4 -ac57b8ca2d0623f5c4137cada67afd6935fb75fd82567f2c57cb22e89a0562d3c0716d5e903fc06694a8c2edbc9a6f1c -ad52af6a0cf838bbca5a97aec5d87fee1aec4fcf5e802b8bbad1b110c31ed777de0b0ebf74384bae68289af20e351bb3 -b0c7c48d734e5a1b37674465eb07a629dbdf8f9080c44a578f3dd687261d9d1cc5cbdc084488c745c9114fd998bfefb2 -8a2b2ccd4c52d15bf7aa4a8847b8015bd53f58ee484589339b4510ef08a27db56178c15b4d79a9c6eba1ac0b641eaa61 -98f659a37bffd7a9b7759bb111412ea9e9eec483645511590f683064eaf15e1b101b5eac3b98f79ea38662b1956a06d2 -af6cda3fb2479b6f2d959f2d03e52b49afd12bdccd7a65a1bf6b91e345387924d5e355363f79bbe32a4624287cf4c1ac -a24d325d8c2dbf9d2e346e3504154018937efb74246ee0658e68d148d9ad0f4bfe348ea9bdca77d4467ea1b3dc2fae5f -81a729dad3798121027c29e9310d56e36a48c1c479cffe674cbf9131c562f541d7e6c52c2718025d3470b05b67cdd321 -95bd5cd6d9895c775e58cd4296ebefa51ab9e324418208c3c4d073be59410497a4d0daddba6c1e7373abc08e13d32b89 -809fa97a229b056def6b548902d8d90c873e496db6cb1b2d448709b9ae08d9b9762559666cd96b6bba396eebbab4ea4e -8bcae63cc680494606e44037a3bf6dc7bae2e723e5ec3ac0451550b8ca7914ee1d4bed0f40adc3dfa45f8f80a36c11a5 -b3474711a0f933cf269e97e4e1e98762ddbbf49dd72e468f1e8a2f89514c1c35cb8db32d08dff50f93e50db43bed54f2 -9788a37c3d95310627deec58ba6d9e0324618469275276632a3fa7841fb127c8fefc1b7392064f2eecb508056bd346c7 -8d031fdb156023e185fe5fcac67b966baf9c098fddead4a6f1a3cef54d8e912d0de2d1e1d3f3f05da538eac4af5b6973 -a5efe72b86a714dbbae40fa69fbccf41042e0647d177cd60275700257aa583708130a64b2f9dcacde4fb636b5cbd5aac -824092ea32eb7a8c619182d926f292cedce7ac3d3fc64f60d00fcd767649e1d6cffc20dd9c1d1c8ef6f64be315d1e2b3 -900ad22d3b63376b1ac80c7343a58df23c03c4e7d6e5740dc10d8cdee793be07fec09cfbdf29e1d1c6484d3077630d6a -826815005550844ac5a6e831de0e25fadc49aff808cd601d70743d4873a341e3f0cd40d490422c87df3f3c40921fa723 -b39d189aea740c52b03660c0abc8e796cab72193ed44a4b1f59fd1ec0e283ef7d5e157ed23741eaf289cf968597c0900 -968ed61662d1e656e039900912ab61173b49d2e24aa6b7d3af07c3b04a2c89c4516540934aa543bb48ee14153780d10a -a433b8b689007ecae7f1df15d442b0570664a2db6318de66c6e5fd68884615778d296bd260ab7d07469bfb5f6d8c94ca -a69ed4a0f39920d1a62a01214daec143fb7596212e2439583df9ba508784ef4d2fe86334f0f9a6b7a3342ec0a72ef15f -96f260d9cd88757e7c45201d57bd816f1cfd37587ba17a64997bf7716ca1c2cfe16a7119c36acf1754231f303058a9cf -a51f2bb09d30028eeb0860e2de38094623e5b5514fd5d591a7d4a9731cd4b9c4c12c5dd6ef409e009dafb10d185d5346 -8abe821036140ccb3ff9063dcb5e8b8724cff1cf0784b8f44486c8380fc51715cf55b443cc20870f426c4874be93caeb -acd73facb964d9012ad12405dc866beb52d8de3ef81fe966cfdb14d22a19bbd2e7ad3a29cf029617b9d6510ed323c6a2 -8f18f6883c8e4741cd6c52e0d3335dd71b5571446ee28e8c27cb0625f77a9f5bd0720d960e5e8970257907f503d58a9a -b66457a91e7ddcf56c8ce4936a209c69ee53d71236b72ea386f7719c8b8c9b4ba4ea19039a8de17a0a869da427da42e7 -80b1de58bb3ac5f264e0273061f485e49413de604b5ade73ef81bc249f5e89ce97dbec7d99b088b5a2ff65c0bb93fa76 -8bdf276c88f80371ef0ef7e1224929681629aaebc8cba3c0db0b258be3c26cd17268f56369832f564b1679be33e98c69 -943cf6fc88678816da42e4f337c730eb2dd59f8d738ea638a799e8b77214ad7e74723056bae96b100f9a972155885d26 -91c8c1a8a61f47119005869c11edf0b69d0bcf40534b82e46aa96bb6107f940e582b6733f855144accb8dc21d79acc39 -96ba98bd291faa0904ca0398d6c50eb5bc2ab5a389c359ca42b8909f41f4fc37dcedc370ece777d5035074a597da503e -b4598e6f889d319713a9896161a6c9bd8575ca30c21d3fdd37cff15dc0141ce28dc536f73957e6fc8f6185fc0adb731d -af1ed593a0547c26ff729c159ef14bd0818f25e7c1c6c51ce8ce5425bd2526086eff9fa3341279daf82e480bfe431230 -8c02b9ad3aebf156c80fec9b012241f3794d736adfbe4a272faf505ab818cb121ad2ad7c2eb1716e252d0a2e7ee6b246 -8d2a8a31784c446eff4c2ed7b004009f08b86c87a4786a0b7be3df36ca9130a0ec42a58d09dfede1279a4a6d3d37b501 -a78b61be13005b1718a3aa3deba103ce71e1ff73163c76815f9cbcc101d993f119ca128a25c51a12fa52f46550c4b609 -b990d81d7aec9fc50d798eb8c38b40b162004f78730e9ed4a103faeea0995bb654893e557e5eee9b74046ddcaa70617b -ad56d68777d0ed53d3331b0cfd44503b27435278416ac2268965d8ef711fdd819c16ef5499d8d7fddadd229c3d0d4bd6 -b5110140b9ee542ec03c945cd6180ab1af205537704fd408fc4490d799d87a3f3aa0f1f0ae9c8daa55c1757f7bb53cbd -b7d8a4080c5eeb00be4540a00e65e744f4c7792b518c9fd2dbdd25abd0dd89e76563618cdb92e4cda0fe3ba4597508dd -a880b33af98cc0bd1065767a2600145e6e326c3cee25602dd22d531c26c4b8543f846fadf679e26749c929310779d858 -941f124078990e03310cacd79e4a38667f4dac4dda4dfa3173a03c14aafbf538fdaa01b940fd5be770c1cde0a84bfefd -b234e9d0f04da6efc5aa5c77bf71cb05001cd193178fdd546e4ec81875830113d3d4f1512e7405b16d0b3aead285999d -b857bf6f62c4b19ca9441f700ea6676ffa3b0c7138299533ede59a9b9cf9b94295046e7eafcf1d4ecaf0341898ed6b15 -a2b0d74f17d3387566bb4f17dfef214cdc6b61dc50698fbbe298a7e2f4a82d20aefd719c5e82bbf4ba4fee0e2e35b4c6 -b5ffae433aafad3fd51ac137976e2c22661d8a286b221e0107baf19f5c8f2f6c7eac1e785f145bf7c16a497310fbf51d -a69e9dfb14f8c6cda716166cb69f06879718656c9f46730d94f194e2888fec371a11c9701071bf8690e57996fa91d213 -a1f51ecd5c5d73155013dcf02b327cdbae9f9c2fbc62f73959050cd3a0bd66192213d1f4bb56a85cd21343722ff3f57c -ab3e54b8f4829f1115694a4be7d16e8214c94387ae783263cfe145f965705d51943176191c706f6211c8be2699dc79a9 -8cd6a64c5d30149ca4dae4fb7e8974dce1200aba9be9c8cf9af5d43e40098746ecff7bcde7ff84a0072138dcd04c2771 -a52f6fe24305bcff685f2d047c9a8d9a1f70c2b416cfe55fc137c6b5b185029f3644890418873665712dba4886e3fc07 -b2e8e3d2ba2d64815bafb678dfc1180534186eca415bd8cd32b303bbac6cfb637b17200aa7cacb953e656ad19dd5c9b4 -b5412d1073b3b80bf0d18f791a6d02727cd9c40a86ab0f13ccfd847bf4e767b8b79aba3935194398da2c9cf17c6bfc8a -8bbaee84aca9089585d5ff385dc2ee6e653d0fcb9088f98bc5fb1c6c83db026d9a73d77c33c6cae3268be90805d862fa -9691343d1a8b7fcebefe2584b28ab5808764ed79d8f28168a65ca90b0094e7920fa43e56b960331209f4b8465cb8a5bd -8ea475e12088d558f5cf6dea2da71837791093a622d5cbee608a95b4c8a61296255c1545d454562e371ea0e2cb2e0b1f -951d6b404667ccca099d01328562790d1e8446231d7d22bc2b1c4c6b15785bf59f2099accc58817a06d24d59ff4e6a2f -a5d012687f341eb9c783c1c2040388eb7ad662cfb2b84cd94d270bcc99116939aea80440d7ab726f9abcad22fcd90274 -818fb57b7a8cc59f06af054ce09dfef812f8f115eb2473d06c8f20fc50cf17423331aae1f843bcae57fe4e2926ad5aaa -aad27bde8eaa2e7fb1a9a5ab531eb41f475afdc89b7f02085f7289f8f84d172fe516d0104560a40c89e97db7e5e836ee -b8cd923efac1b09d9c6b1d97a0c1bce9fe4eba1d872eaa3c0df34dcff2e7ea2354f1b31b69c6b266944ec8cae2a16865 -af628e772d609224aa7cd3eddbbfe965fdae6a05cf6d14959c5c26c4806043afd5fef803091bec710c6854ec095ba18e -b662e1d32704d96919f5dbefc3cc40e7d41d4124c5865b46408c2ee5c40926eed71fa3df71fa7ad349d476d9a525d7fc -ae4c5512396f9c26381394ff8e22b1d6267e3d3a5d3fe48457450694520c5e173716572b68fc1dc352761991abd262b4 -86b530978a7e549e6ca014168fa4aeda9438bcd3a29f7edb1f4e9c712c16faa58b81b028c25a8e90b421b61a1766d7d7 -97b32f1371f76dac7a449295365780d1bd03f290a041b3d19db3f14bee6365a614ca356e7cbd6f966260420b451f6117 -8be97569ea08d0b6c4d46e9565ae14f79d1990f192a26ec935a865cedd6bb5f69f608b069f7d645877c5081fb4a68c54 -9733488f48de05f57f623752b80b37c91f6c9afc0f9b4df4cf400f3f82b137bdf06fee82190f2a4ad4aad20e964cc214 -a794f6dbf155666056529748a792be13011bee6ca10e0d55c82c3e84c5dfa1f370c8e8abf2971a75c73a4ddef3da3319 -95ff5d16c0d9bd679738257a1f7f309f257c20469f2fa41bcfadc671ad65acb249793defab591f515bb3d8072e2e05f3 -8d849150bf8dc3452839256ec4eb65cc9ef87aa0f90dfea4d1d486f16ee855d6c480a8fa4b6cf8d536e435f9fb7bf507 -b61c29121dca2bbc6024ad2f487bb57b926786ae60a9e7a721440787752432ba9c7e1df86ef0d74c2592d23f0e89326e -819630a678e4a5e6adbde9b292f5c8f2b6e3f2ecc9bcec60ba0f8502e503f697b0ded4f0f7157b60ddc976ded66713aa -b3525b071e26babf669ae2b98319b3516c083e797d74bd5b9b0e1f67792a2e8ab2c60921812690b5928de66290ff7b86 -a344c6670718b9824ae62b309813bd31984eefb5efee38052cd06812308edcc39fdee165f8164629267bc0e98fb50ba6 -81d78d54738817dadee7bf70a468a51728de0e9775f8779fea5d0d95e55b2004377b4e2db595d420f017af18a384d9aa -848c97b9413ba6ede751ece925ba57b8f8ae27168c5d46347d39e0232a5eb42069a85f1ee2d30d8b94fde574642be5d1 -b020048c5a5a2d186df628550c6f61a204f16e6eb991283e975de520c4f916badc999b3b7e9402ccc39db5c0b510e2d4 -9298c1aec9664ab3fe328f532428e9b037efe8412ccfdd15e33c9c82dc3631e49f84e0d2d75dced85e3a4e0fd0f3f2dc -8c4a78841f51e2f8b91defb0a3844933999f9884e2b324bd89a01e482756758b1b5a278289163409947c73106bf934f7 -b328a9db915c4bea1783218c7668e2bd7a8fa62e52d3a005a43590041d34ff388c0555b044ec5ff85368352a3643b7eb -8a395d89469d374c1ec472c4d571ae670849549d05124907faae5a086519686683c1773d22d290ebdcfb8dab926d10b5 -aec52b8a883f4ff68fa5f418cc91c8e9d08ef324544356b0ac56a7f0980fab6b376b8f567e357ba96b408652b8e568ed -af80f0c5d50ab23d8ad99c7fba504f2f02b7307b5ae5ff529142bead28d69c3d55f4e2226c44549548fdf761ce30cff2 -af73700803caf7b06f5453a620253731de33a458da01f5790106e9418fb59e7aecf6fc1d1b650e1c7b3456f7a55d4301 -8be3ee3caa86cbe21ce9998fe1c0de73ba6481125ef28e312002377676317b5ac4c27180086fb83794efbf86438ad27e -a0439d051d06a7fbd5ab83f32f0f95364bc043d9d934ac64df7031223e731d7992206879d567e77f35badcb7623f03fc -b99de1a16670fbbe3ec26ccd37399e2a23c96813c26428deda4f74dd3afdbd28cbe47e074379f6094b85176f8ab349fc -8a943a039aa33f38d3887de4e77566d446e87225bb8333e3ea991466c15c6487077c6decb9cc10e5de6af03e6b81a10f -80b109fb49ab810121fd411e4cb85773a1004af2d257e85ab5b4c99aad8d66e5803a8ca7b95587197e88abaaef0b8d42 -892148bd190b042fe9b7914b8aab073c0d19001158087077a5946690dd60d99a1ef372ac01e372a434d00b0568a75fd7 -a266dcc9ccbda054e396e1605eabde6cf79a028b697898090e9f34a4a4e0b771c121b8d470b14130a79cebc19f8d6e58 -b1ab30b97c76392712b173460c227247cac50597c036f674361c63c3638a4c03420fa5b7efdacd0496a9b83956cf5d06 -8a33c46084f669455ba089b369b9c8493a97c131f09c66f9347873504f35d6b94a09483b2775656ab32a12c7b9766ab1 -b77a7c1402edd9ae448b7a606ba2eed192a9bb8f852b647b6ed689b0a3ccb81a4632edbca4c113750f62643a0626e2a2 -8586e85e3bb07b07a39ecbd822d2adbfbf1fc66cf2377fbe6b1bc38369f86292c6cfdb5b405a0bc4d584c0600178321f -80cfe5b1b032d5a28662d13772fe112e9b73c997f8ef0fc796576bb39e02189c3ec0228d192c981061dcccb9dd3c4f39 -873c085029b900d1fcbe93f8789d635e3a8fa558766701ba9fee76dcf05abb6cef518f2b56c4ca5e26f3847cf23bfd72 -ae8075937a23505f51a1a26f7f54e35caadff44ffc43465368daa9c330b553cb4548adbdb04e24c3977e35a08841c36a -b1c7076afec527912f7648bedef633ea0e3b02e5fc3fc495779b93e8a9f64eb503f46a1372c8dcd8fc2572c198112da2 -b5233c4545bae360b07c4411776218a1d9040bad1e788e099f90149c58258ecdf01dbf246ddea48ac8fc2dcde6f34f20 -b62655a8376ce1ca225dba04cb29f1a95d09e1a20b58f0330c478c6acf931ae52268779d6cab87d9074a362b9e82b205 -9684e676088b409052773bb740bd3577bf0dc15d0392ea792393a158e643b165f8cbdd91cf355d5425682c77f2a91f34 -a892744cc0c428c97bc929913ada86c36f280f49bd1603e21bf6b6abf8ed195cb05b22e586f0c841ee02f234731985cd -a62c089a73c6dcf3f7d957719c7d452962ee851d6ed8c4b57ade8a1e57156762c348fe5f20adf6d6ce47b4e98f93d60d -91b29be6022d43937df9c597d19e23cbb83cb6f5b764e1f7db6cf60dd9b3e9c79f1f617c3101c60fe6c7af9b5719fd5d -91d13fe99d7dd7b4744fa2fde41bb51f4edbefb2189ef3ca5d337ee84ca3f728e300aec19b96dee18aec090669c85400 -b17a5328808ca929b794dbf0bf3a3fc318f8df144a892ec0ac2163a0f7c3a4614d7ec433b66bc491c05a286fe986d986 -84a9e84bbecfc2aaf8bd623d79bd4240c630b81ecd55a50198de21758255207238179a345700e65d9bc6eec1a1a1985a -8d428be451efbe630740449ab3677ce6f69d94d75c5a9d91d14b2493a838260d6418be3d4658fd15218eabe3adfe455d -af11126224f6ff0e88a09dbc0de6db3c70e3db3f6e154deb448d044100f989ea41c6c0259a8ecefdcf531f892a957d82 -a51716b900a00277aa932bb03fb61eab3bd8e74edfad6153a06f85aece6f832af710f1477d883dd8e48931deca12bae9 -9542a82039c2d3c538f15da884f090622c5af556c16370d21bdd6544208cb17e0a30e511b0af4a618e8ef70d0c43af07 -af76f93250bd7bda2b5e30e6f88416ef6fc8ce0cb614515a1f8d81dec717077209493cb47b79e8b1a62e09e394038338 -8fa8d657f1d584b06d5bf41a52bc2c73853e4092290789df04eb8952c6eb236df601a1c6cc81de420a424d8e748dfc38 -a6e93e27421b9e32b170d240b4cf2710c97b49dabfc0ea25759c5f61937eb3da8d45a6400f8bcfbb42bc9a7ae9b66ef1 -81848c8d66d34d274b21dfc10bb36fb9497a1b152aad64a8f7c874e58d31d5dd5f39e30e6000b6d7b444e573da1e043f -b85692a84154f87869d97cb5f16c81fb0559e097fc37473bb11dc9cbd311ab91a46b01aa9debcada590992c2473ef0fe -b565371692ab0f0d899d8139d3eaacd213e7d23d6f5df6ac3409c961aca019ce861fb4ca8317f462be01e8c1dc7af154 -82ae2bda0228d36343f6153fbc41fc5c79fafbc03c99a7926c624dfa28ed0a1d215e11ab83cfd438fe5d85d7fee50363 -923f38a2f839e165fd197e1711ad52673deed9774e0590ff63ff9a9985f99612aabe003b9a98db2407c2878abc6d9b0a -af8d5e1048de3b813308544705eeb0facbd604a0ed03e66c1d221be64cad35d71748d2a55d1ff3049e1e5053c7b1f712 -a90a4b3b9d3b7c87c34f85c7643fd67dc771caa940c9e2ea81294ce6c072eaed698368a0e8056d7b819ce3d73de4424e -93a106e914d2c6892fee866602edfbf8d03dea1918d82d511e528b99c8423c260c0d103bfaf9992e0e24638b913af737 -864cb44b1adf5a59ce7baeda0ddec3a0ecedd42923205dfabf30dcdb216a7b760d8895dedab52ee09bb09e999486b521 -acb5f2bc1257c49c7df89837502e699bcb9652567c1716513f258f021755092954f2dc65b9766ffd9a10584bba424c7c -86653b3a479bf6e10e781e316e61437af1abc988f59399bed8fb4ff128f5f6d53f50a293da58774acd42b8d342e52429 -926b7b90eb7d81fdad2a8a59e13b1573970e15c10515954b7c232c37955755b6758178314439ee6c3b0c881d4092c838 -ac05f011011a354f0e16fbbfb7e9dff03b3cf403dcc449eb5c71067128e314badf4d4dc5dca4b8616994ecdb15909c93 -8e063c6601e553f33abc64f9553db5a19ea794a1f254d5a5f7b8ff2db4ed9d180f68ec919a0f83142c5710813baef4a7 -b6e891dd4d44fd54120b7b8716292c27d4bc8744d96253a841433cf4b07895606db4a3cc5872c480616b863073bf77e1 -8dc623d7928234bfbb8cd0b4fce5c8d9a9db848ab0af967ba9c49daffdf719cf8b55e1dad0b7e421571b8770cdfe9df0 -b5b53f7d6b5d1af75e5a1720281feefb8c9039ef7f1e1969d83bed5a2f73cfbca91dbf4fb8179d9b0d3bd06d1207089b -a5dbce9e6db637e053b4b4d3df07b724b50d11eacd3327ddfc5aa8f37b9a5bf628cc9b428328e16cacc552c1dba505c9 -acb82d6c9af9af0dd426a07b1aec81b388b61042bd601546cde248730ef85a09016bdc66dd014447fbb56fdcc23011a7 -a41692e96f1d775b3a9378b3634495a8350dcfa52b4b2b7773b39d36f7d349fd5ee9a2b3e72769ca98f2319319890216 -a0b4bd6a68ac5735539cbbdd78ee4faaef7d6488eb7a11e091d94e315cfcc49a90f204f636dd8033857378ddd67cc153 -ac3dab32427b0583159482f73f94236980d69f9f8f781b93f44aeb43dbeaa740c77898c38c57677b42c248b9bbb1d673 -a6cd1090b97826486f59a056ed90cde29f2ed821211391f2f16e66f1e8914398348cf6f0df6d3acaadab31f0382bb5bb -abd1252b722aa56010e3bd4119f2a28a852e9ac1a8ce68c96b6da9d00fac0c9fa70e67cd4afd45e0a8042a810b8e0a91 -9194b629ca80b3bfefc0144553017343d0915aab59faa3d0e2bb3720dd3c8fe07804be6e582c6d57c764be96cd40f2c9 -b6bece03ae1c5935eb38b14f0f64d9d0b4410c02ac309e085a233c74bc3e67ce63edea56ea37f4532e8b864aecacadd0 -b753eb9184f5b30e77bcb5d3487323e0f1178f1ab3e15130953381272209a97c3e8084e810dcebf1ea7b22f0a90b9c77 -87dd4a76955bc98326823cffd653fb7b7eda5df1a971b72ec2a4d25fb3958b9d6092369539361069e7e4f1dc9343d929 -b0f1e8b25a2687d98cc037272473b4e3f33cc8d49a3c83a335d48b8a0d3ca5f84e8e2bde304ade6f7d50e5f3539d639b -afce1c0205adad1ce52fcca71a99cd6df9da5b748209c2ed1013b5b7d484b937bfbb26db9e9f8e77c081e0a0384114b4 -b363d31209c075b94441d1a8ddcc6bcf9eaee78f8adbf0992d5c7e7d638a02d58e19203247443c35d700fc8ac8a1b7ef -a0aac7dbb08a10f6cc2c6a4d37aea6bc3dc034d933f49de3dcc79bc0b7a011b1e27df7cb882d155287436b72092a1da7 -86dde01fb7090c80fb404afdc9ec64ac40909b64c4e16460a4c862c3a3f857ebfc0c3122250306c266cb1e9f9f245934 -8b3ebbbb0ccc466c72afb4c27ad99d2d4e98b5aee9c05bc283ea3332e5f67a3d9263b71d16b20db31ad4d8f48174b0d7 -8610c492ce130e76c06b7e0204617087ebd8f285cc3f007897c253a0e1af50f80a825ea7fa3167f882e146402fd342b7 -b17f04a257d3142005b8517dfb57d28661604eea9050ce39c60ba9a05d23897114c59c55af199ed186034e456e111cb2 -a04cd806847686ffe023db1721fffbc26160582c239d5bdef08f4730e2fbb64c341fbabf1fd831af6eb84a113ad7e2f7 -879018340deed1fc762e1b8f3a8b78a40539d6f917215621b725c0a3aa347eeff60765e5ad6f4a36bbea51ab77f88726 -b421e65891dd0c6641e8ddf479b065163897a418d723fc6dce19046501e01c616bd19c9d5fd6b395e65abe0ef956d53b -89350af1d432a8c209b69f937d2aa20a24d5eb95c5b4cec097ca3dbbb3ea9efcde2a8c56c58f8d7901b96a627c45df9e -a32d6b31cc9efbad4bcffd8b0ffa46b8fa97ddf3453ed151d7de1d03a02cf233f07415584893155d2d7e14b9534921d1 -8efad47caa32277eb04137c92def618e0715c1e77b5053b0cdd60fa03256fa1c9fba9aa86fdf1c04cda9c5450863d58f -8dff9d309f7294ba750158e70474c978d1dd98739df654945f5f29fedc607caa06b2866c93a0c7b830ff9b26955833a6 -84bb00fbaa4358a2563abf96d2434e4a26acda87b189cd8d2aabde1323dc1eb2eefcdaba3b90e9ad1215ee469745b72e -b75acb924159ecdcf49df587d5ac1b1b04291600a4f530fb7cb6231e7fd1029f8cfc957c891a59182518480c2947f472 -8d2c671ad0d442664a0cf267b39be742b1d3760935137e4c50195695bdb99254c4a4d5830634059d96dfb2b4e214b067 -ac27b31843caa8140e729a01e7d0229d7c221feccc89ffc173c11a419af3db0f8a47a41cac358e15ef41f679a3f0b96b -b0b3e33c590bc00faeb83f4b160748fea4fad3e21dfa324bc14a138ee8c5e18743b6bb27cd0ad7c7c28c2b3e92040b0e -b0d2882c5a0a21fe05b522f2e8a4f43a402bfc961874deec962a1e3d039e411d43bd3d95a26d930c2509aec8ed69e2e0 -aded1e47b3ea6ea7276736fbd1896297b9ead21dc634d68ee56c20fae3da90170f30ad0642be10929ecfe7de5ad8ce5e -aefe525c0dd24d6c0a66b43ebc6403ac75bfc322d1a22f76340948cf3536d2ae87290ca80acd3e55d2df9aaf0fe6bfcf -979d1510d3271ff1f06d9cefe30badaece436fae8de70b01ac843850f678aa5f48821dea48ce1c363fa35eec37283f3e -b8e8d10692f1bad943052fc366291c134a0fc7ca4696feb216aed46eb32de7333a9ba4f553389e7e58c8fa96ba023f58 -913353bc585c0248a54d4705b5e29cc778f304472446eb4baaf30bafa30f2ad0643aaf21196a6c4d177b11eb4e2ad5b2 -b25a0e3b9f983c47b8faaae8549fa7d00d12d7145e1b232d1813ff94058ed603957a340beff25711075cefacde767661 -8515151729ce9a7984af3b94f74880a2402ff853b99f924d581fd3935d8ecfc80e2a1185918a5b1c4902106bd1561ff8 -88e4282ded5e2163874f6464236d5bdcc3c484a0fef8ed0da8d0177973e8175432b75afcde2a4d7d6aefeaed52fbeaa7 -81c31113f2a5ff37250f395d6722a43cebe2a267a0ee40ac06faccaffd7d6eb522103f0431a325aa46a54e606b14de84 -9302ade30ccd62a803b9610a397661298941a644b1ee9d293c63a6c3368fa3557dcf6bfd0c9b44c5c2a6be06d1baf663 -b4ff9f1f6a2a64c50b0a16980ca7cdcc297c6f93e11c580019de52f58381fd0f60a66d3e010fa7ab56bdd250e7b2df2b -8e57eb61ed3c919dfa0f0cbca2cf559cbede5bbb1e89ae4849b380339cb1c567c98fc2c671211fff4df1a058d46a42bc -b3d5b45b4096eb088523d16bda1c6aacda01473533314961e6a8de36ccfb35d4b717eeb1ee1bce47ad3b80e9e5084d4e -b933ff4d3c5a77cd7cd32926266d4f05198178ce350f7215e512e71b07177ac1ff89ba183e424138e1fbf088ecf86c24 -8cf430a6e4eafd23bcb5ec8ca3d711bb56ae719c8621ecee964ef3bae7c53044f7ab3d5d0b911e09c7543e56c1e82e11 -8b3c34f5321c9ed48024196e1e941fb7a5975a045a5a9de88d7f200fc7ffaa0b3e500ab7b535e02bc5c35fbe420e2c3a -b3c235b65fbdd5c4c2aa45271b9e51674f9a0383a8ac383b0de53125a67c87261540a95b8f81ffe67ecdbf3955b13814 -aaa93ce79ed6e7084fe906c9a1002435ed6829ee3d1380681b902d35dc9e5a23a214ae12dd4fb76691b0016f28d43651 -b4c9533e50ec58f75ea82e2aa7f735c4257bdc1ecd0da0b6521d1442fa61f19e4f73cc90972b47a762f5cd9af591d957 -ae0255dd70befe7eb979d41f9a7407040937e7a879daa64353c66d524d3d3cf1d5e854886a6c32c142f4673c56a4df1d -805fc5ea840d1c2e6b35ce586309698530f056b41de7a403d9e7d81efc2d7068976e8e23bc0b9ee256f39b15bc4f7ecd -a8de5055b6d2310b6ccb211a397077b211683b05c7e68e55ff05b546c5c81522e6097a3c3b4b4c21fe06667071beaa4c -a4014d39b23c13efb4326956c5ee476b1d474663950c9e3e45aa1345037be862cfa14aa1d03bb388085bdb4ba9d70a59 -aebe9a9ba34d6cd3692a8bc0b0aff5648e16b36d6c123e636e9260386642e29d52ba71ef7778481c1b1cfeca7fe6acba -b59706380c9271918ee16a04e84e91046caf99623a0120aeb37a7a98d4c954d3d880960086de6cb180c8b922ca1d7405 -8dc0713371808850f2137a89c33fd55ec2df6a028e22b2679e09f7084d5c471451187f6488fbd9b5100b84593540e5f3 -b492c55e470c35c7a7efa536f3e7c1e586b623c6669ba6eceeebaa1f81fe3b8b927c2e522fb12e603ae246d9566e4d23 -a5148eadcedab9ae08f5db6265326fa415aef46d0b24155910210338500be6d77bc9fa6f6e284a4c2552dac09167e450 -a0af7b66c8a1319ffbe7a0180795b442cffde153f9a871046d6bdef959378c3068813c516e280371825af06ef2320b15 -95479ffc4903f252fe58632e833d63d963469e89744d5c91315d38eca21b98f1ad6fb3ca77d620a6f97d9ca3aefa1f7e -84861bdb5880f663a5d9b5e89b59a940611a233d82a9895a330464f7e9b7a6965c2420704f3adc61f876584d06771f03 -933c374f176381a3a63fa98d238d3b7d337aa745528e271168f5b550fb703664c3128097b927b5922b4ae8fad30d5e40 -a3ed2c5080c52ad1235fd93c9bbf128b48ba8abe364247104bbf298582930bf3faaa4f4b6103062a4696e68c44f79555 -94668bae91eccfa8ad459588f927bd1a169af834a76132b2f2d5cda26a91094cb94661e3c59f7547b290f827eb43125f -b704404a487a7dce87ea8207dd5d813378a345375e8e2c07de349c1448a39af8672bb4436779b3485adc46df2212f409 -9347dacaf6dd678574a4f1a95df79369e3f5543c565b1580f907ecfd17b5d6e1ee3322d83601cbbc6d6ffe0bd2833a83 -92841abd813bd9934bfe945e428193e33ae6d4dd235a16edfecd6e4184abefb8a1f85015ee83caf9532dda380fd678b6 -95c14a1d3a1e1ea18f8a61f34b85ee8a794c95d3b4b0ce6ffc89013c9a80291a9a2487b00bb3de51ca2e4290fead7482 -962fb52a2134123ca31d91027fe9fb62dff4e0542c66b55899a163e50f6ff2c4c4b9c1f5b5b3d6c6dbda40e757c0bd3a -8aa06ae95b0ff361dea2792e465436d810b86f803ba6121ff93fddd9ba60ce47e846eb2d248b28f2c47bccc9457c1ece -81adde02ddc49b6cc89561716a839fdee2879c78d1ea0fc0418a6cd4a2a8189a2bc245bf2d1e535dde07e93b8a5e18c0 -a7a5713055455728d6d982a6650d1edf1a3b4612c9072ee8ee0bdaa3992963a6fe91ca242fe36f839595d09f6a47aaa5 -93900cefff6f918dfb12ccbb256adec89fb8da019324b811398eea03f6fd34f28a6eac2ce5580904cdb289879bd4b4d1 -820262cbf7864213e768b5a38f39d27dcfa7baa5abca557ab575b07c33917f7b0f06f0a6abd81222fe8a5a69d95d774f -a33114d4cc3cc84258fdf252e754c8bb1feb6a130785d35a78b4b05d0f782424a5ce0f34be3c1a14e3bb1bc0246bf0b6 -b966ca0a11f0361e611ab2a8907f78a3d639980cae405d380f3a080125c734059acb08431a42ef3a60ae9331a07e6a5b -9305d107311654ee727182a1683f322a78fc637bc214eae311f8778773e5bc52063bb0a902a5a962a4a26fa0cba3b06c -b3dc808231c75e681aa2bc4358c41f01e371bfa5bd504e7bd2282e35e72a2889a51747cc008dd4d8b2a070c8e4c2d7a5 -8f05cc76848367abf2020461b6bcc1ecc412ae9f114d44715875f25f34d8cd26b84b01fd6c0640648676b8d2d5120814 -8798c23f0ca8a7b23152ce17086f31e2a80533067f15ab4a7b43c127a5d8af3297115a3cd7978ace811fcc38805abccb -99a917f54253059a45103e15e92e1bbdb03e80584a85b658f231aa5947b29388f5b04588de1ed6de998741d360015313 -8b0ce3f6afb5aa83ff229ae1ee0f986ec4d31b113070c7ef3c1ca3613d74e3f23cc1cc81957bddc709a5c5bd85cc64f1 -9035b71e4cbdc7c410fc03a85543aed34a1c0a98e07ddc933e64886f1796416ff3a0f7754b5246ec93d617aad0f53d5d -87478f69c45394f94c67b7196f60aca42823ad92ea86a427d705576fa6a9bead40b1a4106767b8a20411e757f8762b68 -b36901adf577f159b4263821a48fc5888e7bbd6c9f3857968a9cd02e1a1a788c08a566b7bd5bb6be294fa5ab92b4ff6f -8a738b1392aecb35a5a1f12920522997c9016a0455354e41d2e1b81d8ec9b30a90f71492c7bc122505b2ecb0654545ec -a5a422515f17f2bf4b9b6c4b5b94df27ce80826cc3ad2a8579eb6666c67a96355e60bf227b36e1f082d749ade7a38a92 -b6d0e36a98e0518b14728bfd79db76c408f58220111e8c4dbf5bcfbd7a85bc68022456196f07b9f40158037a3c3eb90b -82ad91b812d08bfa815a93b47bd3656b493853bad52656450eb408fc915e430192ae123fb9daf4aeef4608800e818b74 -b8ae5b30118dda7b972464e14a96853147c4b362e9cde22130250447575c0d8d05053202db4c650467dc16330cb54b36 -835d913a3d15ff205497b98107eca77058beebe1aa35ffc20241bbc2a9b4d2019ba41fa3c9b43fe2265a1110b5c2fbe7 -a283d88acbddb50983356f2aed99c2f153b6a8f489b0597d8db08ff7e3b04392609e01aceb37fe985f59773327258195 -b6927dc3318931eac59c6e21def3ca79154beeaa4c57e11ec1f3362aeb33445366dae770e533aaf33c273eaa4f54275e -a6033a62119e077b438e0170f27835597e21c1d6e4acbd53fec7df69bd1372148f90966732fc5c004857cdd44b8a03c2 -acc764a116e31d63f534b3e0e42a3f899d817d3ec32fb4504045bce7ba3a952ddc81a33d48c5b0499eacbef4268bd5ae -af5d1f6a67dc6361e19f222a24163be388033a3fd0d33ad204f4411302668436f933c4a91c6472fd4262397417e3c588 -a2b1fe93eb481d4fec6fccbd64945a12cfeca85aa8b8bbadc4e4ecab2f3ef65616294dc168d6c955744b7c6acd712012 -acb6d3e123572ec20d0ecceaf4916401874f0298218b36a0ce089acef90329204611968c7397c2a518c0a78d02a9285e -88e4457b1c9b56957b76a08e98c569fb588b081e0e420a0d859b70296f648a8d64ff35ca61a39d1b8ac3613ea5fdc2eb -a7d1643b3bbef49b2f9fff326061cc27a7f65228e40929562de73e1c66a9d164d42bfcc3dae9103b2acf27606f18b031 -a66e3b97efb7ce4e81534453d3d41ecd4b5b6e9bb829b07b5afbf11fc6ea30382a0059c33c97afd906656ec19432830d -ae9a17d0044abbf3e6aa2e388a986754d6b0fa35d115e410f69ad4aa114db1af5dd0389222b838cfd859d436aded1b5c -a4a66a163365528b08333f15c6673ca48d7a9b6d17822f1e5390fecad122bcf7ec5656eed2f22fbc6ccb6dd96ee260f3 -b7dd42c938c2ec50c3b3fde92ff629a571e46f8ce128fde7c2d8f18796ba1b1d7eaf7337212f55cf5cfc540c7d2dbf31 -a36bcad22f3408b3bfd45d272f3387cdfbff57e014226dcd1db54bf3f8d1d896fc4fd16640b5d1484c9567ab9322a37d -8c9831fd5f74ffac203aa6b6ce03acfde8a2fd939b79236a01931d28b424fd8f6b6e44522d28e086aa12f0b110e5688c -b48bc95abd331d901610335299580ecec02a263d2b03bb0579cae3aa87ebf5e93dd110e7fa4306d31974099fe6e8f58b -a15e27a87bcd8ba69ebfb6228c3c48e19d79b22978d3a63af553b3083ad13e48dca496896cec195e63b8a4e2c40cae7e -96f3de6fa492dd2d653888311bc918ab832d6342dc7af9155bc7070004e89ca940b7672dce0a1b4976a7c3018f13e49b -81a022bee3593997f556ea53e2ee484188cfba0be4b831ccc048ae4b5a6df9e3b4d57c436caae5cba92486abb71813b0 -b9d8e46df67e481c84d5520a9613aa92750c8e8a1e8f376b8ad7b71a3ebd95d2d191ce538e6f7fde3ac5943f70c670a9 -8f0b52365d944f59d2ed445b6ecc4f88c687fd281c1913912c8e6075c3a59667060b42f2c1589a5955e9f3791e23aa02 -ad07429bab813045fd909b928ba4eaf262b6ea40b353aa43157e1e683b2752c5bf19eea7ab6ebb8daa8ee91241fbe84f -b90a99ec1f31c43060ef649e047bf24f2fa7fa9daf904136c6a5846d9479966b54090ded7093e481c52d872c6377eb65 -8cb05fab3ee23db24c9bac109db52895b200dd115209bfa41fde510b29d9871907d44f689fa0f5474d12314a711f6fa4 -b00d8f280ee21866b01ba3de3bf943a7d0825ed67db03d13a0b69f54a4ab389df1cb10909e831ec0af8f1675fa7dc399 -b383d14fdc47df80be46390420603e7f505052b1a44ebf595354726f2b487f7f18d4243709d347e1e584c28167a0e988 -aa951f60d1e069304222a8eb0338a94c8b3b4515d7cee833864b6c222ad76f6c48e0346c5603c35a3b52edb6f9381911 -b887070ecae2884109eed80ff9341f5fc514d59158f5dc755ea46ba396f6783b8a86ffd2fae4419cec2ed57f4dfd4327 -b1a6f1e4d25f4aade76714e52bc426beaa7592b975f07d0a6b372a3f94e7a3ab0e8829575bccc953195ba0c9bf46e68c -aa64bc4e0d9502d294f0d3e6a1400dc38f28e87c85d3429ab3575c821e1229f1dc8e2c13f03080006bc897e8fc3555c8 -8f215476d94bc2af7d2e0eb68783292e314c9a4f812f3065cf064f427aae165990dc9665011af502f5713f3664317989 -a578c8991e9e29bf3ad7be44bce3817e1c4af3e4a8ba3d82643378da78538787f581b9caea7602b87619e5f8cfb337fc -abe5453b650106cf65bf2b7faf8ff973b7b3be0e6f42983daaa5359dd4ca225edb7228bcca3d71bcb8d77241b320fa90 -b7ed1d027dfa91d0ca5d797295e359bdb1b0221b1f5eabd2ef76ea3bf456f9aa9788dd00ea24fe0add9e3d9b09ae2428 -96ba0f0c5ac0eae3f0031f8b7a87543ac369c22122681cade0ea33a6ca370cafd360ea6b80758476ab94cb07ad6820e6 -966f6191951b998202b8a63e3b10ece69616b989e9695cda84a450cb953acaf9c4f902200b7492eb66cb9ae0cdc8ecf0 -8d7bf21f76ca0e3b3758c293e66e977f83533d918dc445a09f4f38975ccf7220855627de6460d318290daa03a5f5c68f -b10dcd91d6602852783bb76b0a286523a0942e8eaaca4e0ee5bc76cf19d33bc631f6d0fda1c1ca51bb3d5d5c7dd43728 -884d502d934e2b045357e981506900849e6eb051ca3ecf3079b485b348372496db97da384f8d2b5a52216b4d223c90ea -b074162e5d33171477ed48f2f185b1c83e8fc2e7906681f96ed97da8ee86be7476d65e61648383c2766ad9853ead35b5 -90bd3d8b475da20c6e32324e30bab475f2059cd81fa67840a6c831026cf3d5806496a3a25192128da4b819c1b7cd6bd8 -8da4889258cd6ffdf1608af8325230f74abe6a2a511872c2dd10123b491cb09407fb979d80fb1185ebedf421ba22d0fc -96fe1d9137c24fba18b1ac431ccffc01ef1792623bc334ec362751b7bac73c4d4f7e9bdc2d595ad4731c71808adea15e -ac816ee0b9103f0bbdb50cc05f9c5c8f7ff2f14bb827541c51ae5d788f979c00fe4796b86eb9e3ba5d810925c1f34a17 -b231e98ecb3a534dfda5b40916fd4fda270e316399c9d514dd510f0602cbc29e51c5ed60107b73e3c9721f7ada779f91 -80115e104f22ff2653ba7c4e1cc417dc054663d488f861a9bbec4b9e907dedbb985e6e78f31dc16defa3aaf4f88dabe8 -a0dbc25dde933e6114f2ec22445f1e209836585997b14100f3f8b7e62f5fdc6aa2a85ba5ec39a5197c9d4dabc9a5c452 -8d2deffdeb1f0abed8ba62187f5e1cc06a1e2bc49b3e15f73c3d8e574dfba7efdfb762ab512cce53d7db790a7354c56b -b73f4897e221927feedbbf209e3d5b9c08f52bb732dc0d710822576abb7ba5ef0e728d2d95c802a00eba925ce99d734a -970761c7ee891b3ed08253d2c0d28478145d0776e2429c85b4734e5eb7a6416d197d0b1ad3392b37ce8d86fcaf9de7ec -b4c9e2acb4c05236357be37609abc437612244bb4421d69486050e390d5ddb52887a1b3e1bfe968a90f1695d892ba8cd -87caac2c93e192c34b5dabc36abe26a844a33bf63e9b01a668c90b70701360a0417ae3248173450c64034685d913f4f1 -a16ac64cd1a7ad46cde1c93024fdeff724afe228818b72bb66176c7daa090acf58e7fc0aabc582ad22486e46f0b96c5c -936bdd6d67d666274c29765690f4ad9c4b9203e9bc9dd5af558a8d908dfe8d6d4346f6fbbfa69158cdaccb0058ed0193 -b39af8d43ce9d120497888fba0dc95ceeabdd3d84421c1a30fea226e03b78cadca0eee57db524f6ccf1f6235fadd1470 -847da75509ca07fde2277aac9e7622c5874256903a92f7a56382ad3f79d1b3b0cc0b06b2a6b2bd1749ed567e68816d31 -969407bab3f8106a49be63f17ddd603e185afc1c9fc0ca0e90ac415f53923e3c6a69fe488d33403521231c5008bc11e4 -82e25ef35abbd9b98c55a45e7a71791925639afd92780e64a154ad8a94e9807f2643854250f30bff1c5e8806632778f7 -8e6da5cb8cd80d6b8e2321ba3f034ece1813a7b6ee3afac73371a51434a3e66221188162cd9b9ec035326e7e04e74b25 -9868bc3e60478fd0ce37d35e0e4f7695f1ffb7cf2e05842b3a09e832af33c7ba48448935d425196fdaea9c3e8a5122e7 -ac7733adfeba1da388eee6540a127d0eadcbd23770f2deec39edc0bfb1002beacb9a8c7106baedb22e664f37771c1410 -912581c23e3ad0d7eb886cfc22633fc704e530b6b4977086f68f1d9f839bbca3bf0162acede87c853e8ad8137b5cf345 -a0315fee6285a33d4ec60f6c1557ebe4473e8990ade0feff7e008d3be1a709f5f486abe784398734d9ea1193929697e8 -a44a08d6fe0a22849a8f518ed9b30b78367de205c3301fc8159ea273076488299b35c362530436dbb7e21b6b9f36835c -a591ea6ef83f2ec78a402a86ae5b82e330998e18ce66126a89046f169dee58634dfc531b1286277eed49f571df5202a8 -a60d86619b41f59b48c800a302775656266725b44ff8318014fb668f331bec82b3b543ca848a7d40b2718f29e5ce6cd1 -9420d0219d407583fff43c560964e1da06b105043187ea156771b1e4dfb5d5851d06fcfd819c7d8bb6568fa1bdacd916 -97ba0b6731c78eed331530be7cc374a7f4a7cb2144ac73b7c000ca36036f68754d4edccf73ce373dd6c6be55177d89d0 -b4e07b5c1376900fa2dfef8fd1a5a4b6152df7b805d5efc29057d1df2343f8bc841284ed23d2bab5cd1431fb95f71b60 -8017de31e62a24bed74460dbdde1717f3a9cc17e2e2ca9848d77c3b5c364e7e1d58ac0eabb3daa2b7336edcc8a418b01 -ab6e409231b778bbc1ab74c3062a376c5287c0cbd7d19d4ac1d5da1a8d0571864d0723944da72581783cd7b6b0d529a6 -b5f2fd4ef29a2ac847358abf2b3e7a3567b8653a4b9ed8da70809f2affc6ab44c65cd17f255db0cd8315e4801bb1a408 -91b61d5d047e9c672d7312f563b8da90d9c2c1c1268913656f061028748a351e116f524593b1be7117a46f168b3e829a -b6c10b09ecfb92168906191756cb824694caa32c6f2f9b19c51658d44dc330dcd344e7b04333392a8a93c73346a3845b -9431d01a121e6ffa15c32e724dadcebff65f806c11717b050c106c0c80e43e622130f41224533d13be4a8d14a66ae1e7 -a1248085c85855b4df6eb5a02df0dbd5de5a8a82656e1a5f61214885fcb75428647c8545a848960701d61c3002840647 -9867caba8f4be9483df9b48e2bfa024e79e6797adc2198f2b5115d7283931fe4cefc382323edfa1e850c3970bd1a2d53 -89e88c50c43d7e966e60d49b3afea792429563c93550b10584c91e4a827a3617971eb286c39205e2af4e7dfbc523fd8e -8ed261502f95814410fb081e7348eb09f3a3df22cc3ca82a2f071abca0190e9f041e8714b811418caf7e1753cf284e9e -87ac65370073b6bb85a945e138e4d0a5d71ed88739f72b9ba747d2a03b5d4877e8e526026348d2578c752bc4102055ed -b07de38d07906dc2838be840c291f467d9b695c62175c5afa46d80f34674d061107d6fec6847ba5f17f2d8729f31f5f5 -899348bd385a7c3d38f9d740001c9a543dd8496b58807a6a73180c94f3aa5c15a56cbb85cd7124458e2ae44a454a8a58 -91b70c3543b8e21cbcc8a40cbe00cf2ee0372ba9ddc7f610b711a070110508159e6a52e8778b20f0194ca09b109881bb -8ab84d75831ec1e708ec74eb6d6de2b13bf97e2d2262ece39e5ba5a4a3049c8303023e40fce5e87b237bb1dabfff5246 -914ac70dd91ccb6d7b83a5ed0a9250c66e77a815aca17416f1796fc0e1c26bee7acec5de11e65061a44d2d9c35f5d19a -8867260f8024f533fcb75d9c3f2ab113d349504b40f650a2c92bb46aebae3a55de6a113cb6387bf00eeb2bd4719d87ea -9976dd4e56b16fe11533dce2734e2903a3ec986dca6540bd9ca8b758a59a1e45b1e69c0b8f094d42cf7e015363ce37ff -b48c840786653a0f3ed6b07f8f980284c5eb2dd22e9ecd5a0566754a1534300e129b39a8a6d4fc48bd403b351e714f05 -b1633aae7c5e5c51a82aa4e4bf9f92c0cd30cc1067b03364825ecc492fa43391ea075195f2f73b99a11dc49f670c0e89 -8769a592f503bf8ab03d767524d9ec2223c502ebf15b69eb4b3d53325ab366888afbb668bcb380230b5bd74b32d90a44 -87439671fda66bf5989fe1fa2aa32519ef908aa6ab3eb34eb5b7d908e9a7db2d679170cf3fa0e0a388a355b8c51d306c -ae1ca219832c90554a91a7258ca5598f8bcaaa7059c574803b2688d8026df9083985c2f8f4ad3aa9b122efe64e0b2481 -94916e6dca309d9c7afb9aa4c0bc89a3de875a8537cae1fd32258b34782994e5be5c4987577d697ddc86b8d68dbbcbaa -8c5361b85176adf77ab1949d34edd562d8c16979e33b59d09548ad372b8c913ef385166bae53c8fef814a529fceafaef -b968172a6a831c6ae53e876dc4ef8686879cdadff0aef4147c4dc3ccbc173f89748b840a30ad393eaab69e422363bb86 -8fabda060f8bb2bfcd675803ff0a3f834e2356152f88bc79c23f58fbfa6b0c82850f281f7b8fd2a5e16230aeb4077320 -8e5c887c318335c5561e63fd3c3f64edc669c0b03b217e3ae40ea29245885442864dde15751d7c6ab177a91fdc1f7235 -b2f67f9d64650c6b51b88e7ee6d6a796b453131c93a7791cdb2d0a4922d3c913a4ac988bac5b4b9bfe61469886e1e7a4 -96b836824dc2a12ffecc6a053f7549b7faad9808e98bf20f3c9146fab05098df56fc2833a6002eb39c935fd8757d4716 -a4aa33fa77b62605f751bcad91333659e9345967845226371e5f38d5a7f72405d0e30777b485b730e6c62d8216790cba -a041bf3467320df4bb7baee569cd685a65c9d0e431824b7de93ee47ab8b3ab20298d60746fea7fefb5bc82d3f7e25dd6 -a85842f11f490bda22e9f73409de0909a2e61efc6d8be0c3f561d881988b4d2e6924ffaf0a4c40843481892b272943cc -94de0ecf58ef27228f5afb12496c53b075bb347f900b2df98f47ceda8675bc2941aec04d1c8ca0dec0233430f2759824 -b1795a70651be509c0955b07d58a1b8655a2e6c292b939b6c156f0c0983abd7e416cb0cf14afac6ceec85f2c46b83a28 -b6beb936ea1f1639ae59eaf53015dc1855ca0f798d9ed72607edbc6c119741e10af5354c29571af8befd83b8255a8f58 -9424188ceb15c1b470c4bb17c71a37af56c87625e7b7fa752099802673c3a5a99d16e7d6dd8f8b680e89b75cbe7920f9 -b9e22b5df8318bc0ff81003e8208ff3217ba1a84edf6a0b326b7180208d3a9144c6fa54c57ce6d6071ccb1a40eaf4509 -8e5fb55da49feb7a9152528ad6a6766af75cce249eadaaf4806c6d4162f65f3c7311bcf8da72b96f6636cc019546c05e -a55f751de82aed5842f94d1ba1e29976c3d0146267b11eacaa4fc765da8d2acf617d3a65a2a74aa983130851f8c57d05 -9647758fc596b78fb52db58f2ec31cea186d9d4f68692f56e474961b277396af4a51781b0a358a6a6aa8138e46443a43 -9461f6dc72988b44c662865cdc01c0f970f078637859cbe6314fb17d2cfb3451b222cfb93a5c6eecafd1ddb36de075ef -93b30bbf4fa0926cc5483ba9803c8b001aa80322addcc866bc514f2a10aa43bbd86008e4671ea26d8e0d2ffd4bb8f2f1 -b44020d0f062a001bd6dca2bc3ce61b17efc7a121a9035709f01a8c34708ed0c1c85cfe98c534189e0669eea719c88fb -afabce43f35e0d3201b60226c72c30177c4c5d75bac654fd2b58b3ce9de7d83ef01be60514817f1e7bdb525c910b8bca -a97bbab394253ebb02ba47ad391db3aec1b4d03e88ab3e7505730640558c11fbfce42d53b7f85787cb564208d3dc826f -805a34cb0c8c7ade28c69dfdde46b7a283e539977602aab165316e973c62bc65396b6fe2c96750ba028c550de03100ea -a0be38fdba281e0c248933ed73f1119f90e34d5b4435bb704a5fb7c20805e195518a2a424bb483f16500d74f440d4a53 -abbabc7db0a20030c6e687b89162e704720a010d7ac53b9766a9ccb7e02d4ea1926792f5263d715cb97d67f2010288c2 -b9e471a7a433a678090fe4324739dffe238ed7e9a867159e0b43fa80c9c0798cac6b58bc09a389223f94f22fec43e18b -9818e9a42ebf415c6d970c87261645f876d709751c8629d1ffbcba4abc8e3a2a1db8c4c6a6324dbf433c43fff62803d1 -8290ed53eecdb61157cc458dd081b9e890bed5e4cfb643d11b549b2c65fe68fb981d4311473510781945b0ee763a84aa -ae730a7c69866f22d8f9b0d8e17d7564c25763cc77a5eb718d5651b9c5198b2b9d3eed1c066f4985b2f6d7edb0a109d2 -88325e421a1be440175293efd498cd167dcd0914c8827ebf64ad86788f1fdeb3c16d3de7a681f958b0f49046c54fd804 -a8f592d6ba7fc3ab8ce8260f13f9c4886191530cb1d7505d0beae54d4c97d09712930b8f34ad74f1ac5ebedcea25dc8b -81c0853b0310a96674a92a144a14c48fcee0d72a772451ed046c284f16fd6447f67389ff7841d752a025da172d62e73e -b9f50526ce4bee12fc3fd8f3582f3829b90840f6eba06f37b53febc1d0987bbf58107d73fe4373d79e53827270bcd817 -a2ca28f619d4821f450b9431bdcdb129d4f35dbc2a4976e4d416dbd14e378d4d60a517457aa0343f7a5e60a7e246e22f -b9576225cf7e13374d3975703b3850251d53ccafc6feeedd07be2b0bdea63b899139a1fb446dcf76f62f3c03beea0486 -a88df9f6e95df995345c6265af546158499fc0d89447d3b387e7708fa037f95ac9c4e20ed35b749b8d8a7471dedeea87 -a853ec333af8f35d51ddd6c4d45972b68fb36219e34278efa6cce02bf8193d72c6014ba6961f8448785b0a43a31a688d -a1ead9282496e590bb43908dc64341595cd22b844624e02f2daf597f708ab0d336bcacb5862bce3ce23d1a9616fc6179 -b97398d8ebb52535a1ce3a10b2255d358142ff653def823ad9e9ce4ca5f372c6e7c9301588ae5d914b2b921a0fac7442 -8d0d292c7e9122b8d001b3a3323f9d37dca61de5a595f9402ab0e53e941c83f80237a853abe4aaf012a35cf59df48c68 -830535a5a8268d5ce4e7462fca4f809348908ae7ee117312244e0a9c30b09d91b6f798654d8064091078400346614e04 -a44a90d3d307ee3a3c3838ce43a873311789a9b9292c62a01622bb813a02f6defd21b0889cb6dda6d7225009cc6d2641 -a219afe00a9327f2c937afabdf5f10bca0687f48d8f7a2a046a52e6924af613f38cf82454df4f412f5991ba20b7db74e -b448ed4b15ced4de098781793a6e850ea1547d514646fb8f1c137c86e14231ac4340b308bf07813fb813cd02e47c015e -905fb68b8f5bc14834a06d61f3da686bee77b3b590a33c640c82f34e68ab993f8c4897df463973d6d9f0d53f9ac5cf5e -991cb6857dd0b3ee6597aa2fb1f4ccc962cb038228615466964680795587240e6ccf7861ec220a53ede1e2e9752e1cb7 -b823dc0249ae72e2de91108cd4ae6d6af3e464f12a53a46ca583727c7351a67f2d12c911534e234ee187389fcbf1f621 -981ba6bda1816036e75a864f635629a141905a4805c706260e7a5e12b82dfa9de4f4058143065b10a1012adca6b7d083 -8bd8ec0e77a6867057e5393d82132474eba9fcc4bbe025544bab0ada4ebad3d296ceffa3788acfea0a44406e2ab637bc -93eaca3a7f9a0dc809eb9f604905b0cab18750a9bfa42d98d99728a6de6e0f1e05b6e98bb3b0d9862a69eb57ee2e18f3 -90b077d7b7b1651ac0d723978b3e408191c2b8b08247fe2a7fd69afe0615dec09e43771cd845c2cd064b56295e53f634 -847e8f607332129e95eb1f3e00003b087e92ebf1ac9477304b0d54ea38419fe8581122d21bef8d034f788a9c92f4ec00 -b0301becb003dc7cd56ea7d830bf0fb4b85bdb33606d8d9ab2b70c6415ab5c8f4934bb7079ced16081b8f6d16b77c0c0 -9068fbbfcc95fff7ef79ab64063dd9bff0c40b4855eedb39bfced9250cc351b5b3b1bc6c2d038cb6d59a12a41b3db664 -84857e081fa1c6c08bf7b0bcfe7c6d74b57cbad1b67676e99686bcca0b17715ede19f826517dce3f84cfa014e11909b0 -98fbfd6a94ac3e4b53b811e4d275b865486a52884352ff514889313c7a15b07822f76d428533a0f8d3cb42f1e6f72356 -b4faa1b1245aa6339b5bb987f3423d187f6e7e5d4b4b341de87ebdea53b124932cd0e586470cf4a3b1060a126e4ce7e1 -973e88d073071c2cf5ed643d770a45f6be7b230896caf72a2cef10e56ff0a4e032d6ae1ff4c19bba2cc29f29ba70cc19 -8d40b3285879fb9ac0b6c9d92199afaf4716fe21edcd56b1a1fcb6ed298b5ec5b3b64222eb6f0cd1086d41872911068a -b5e338a02076ad851778d590ada4af1c217d035c2505b891163689a554e5a957219410bbb435bbb38c8a1515146f8789 -b1d3e990d027a38fc8a38579e39e199d9984dc6d857bf51e2ed5fae061c8723fed3c74662405378c29342bc4f1fff7ca -8679f10f866804b19dd0b14b24068c1d32908a52149d33ab03394990cc60c0f388eef02bc0db819f92f8197b1fc60c17 -aee5157db1cb7ca8013b0c19201ea1e7af32e4117896b3f8ec0ef0b2a4ded6a5e7c893281865cdae7deff4532a6a3fe0 -950315818b710d3903b679dd0de0619059bea7dac3bf4edc8fd4a6dba81b7aff9bca7cf1972940b789458f287609439b -ade345a6171b8e8afce7a455cb98024d0d91dfa347632e1a5a40721868bfed1c1959300f1e1e39a551d99a4e1abb563a -adde1719c13b3ec224bdb6b44dc2c5f2daad54e7ee736209653a0198a769180019d87fe6bdc37ec1b48f0212ea5a8927 -a3397eba3ed2ea491e8d0328333689f66b2bbed0e1892d7b14b2aa45460a12e4d592d78a5d0ac20bd6d34c88b8f1f7a3 -8613160aca85f0154e170b1b3f1052ba984f5c422c4c25e0771a53469c274130a31f875a0ba9650f77fabd910cb10467 -a91ae4d048c56d5b2383a9d8f6396837543b609d8b0be139ebd5fd31fe4a90071656442ca7f14136cb8205734d929b5b -8e42732269c77887f105d1c326488025f9938cbade678bc6b39941311360408ea6baf274bbf5ffff996756cd2390bf1d -b96e1ca66d51a186237fef402bc4e14f8f96a138db377b7e2c3243954b6f47ca75cf4fb5dd081aaee634b5e2efe2a065 -81d1c20d76ed054923c17b362b50205050f185137ea10559e35ee7e191bd89383b68179c0aa4531eb61abdc239ae6891 -a350b5778e26ee808466619f73900e09bd387849d072c0c014517d16adb4e3394673238c4f4e705d30b4ec2edfe5a695 -a13657433e39c0241d48075ae8ab1efe3680c96d078685c5dc0ac3c49d468db98f2094dd4204f44e8e90bf54059b5807 -a96255abe489be9d42ce6fa76ee90e4bb6a36421fb78068432cc935632ea5b5bb2ab70790ef79422f93d35d1034568b0 -b745d643480edb577b1f92ded38a522236fa1be2944ad8102ca64c3d55f6297b7e0aa1beb082261af1cc334f5a723614 -b235ccbf94e2bbd3c794bcaf84266141c0e04ecdcd7d2def83a7eeb86a2ff4dd3ddbd8245296b27344770f3d5d332f90 -935f3e4e9dceb4f58404ba1a489985001827e96bf6be227a8ac4e2eb8a950d4a446320ce3a245d09d2d74776c7033a3e -99cb7f3d6256ee8918f40642f5cb788f0047a04c482146e70687c3298629bf082dd98d4a4c222fbfea3afa3d7d806f00 -ad6abd2fcc67af691e76792432b83b8cd9b0a9e5e73de21f89ab54081ea002ffd904d77ab8efb6906790987e29c53ff9 -b6de4c3a45ed7898abc037a47507f46f7327c057a911529d3a671286f98e79a421f4586a7ff3235f1892d0cbbd0e7bff -9120311b071d38214e39f4b48ce6299ae9297c7b76ab364353d3816669cba56592fe4c7f1f93507bec7ddc1df471f0f1 -a6daf71681485d01ae7fd4bb81a326d3d2764bbed5d3be45efcbc04aed190163ce8f9d04a84bacf25ec151790f8fe917 -9534da45c2a497607f7440f61943f4c16878a18f0bbce00dd644de88383470705b489225f5be4428d1f988256b70c926 -b2d1b633b4832dab1a530a1d85415e7fa3e4a1fd383ddb898a79c7ad028f2dd8fbd56b83600cf481eb14a073cd65431a -8c43dc994dfeb5f22df9560518df32deb1af43f254acb8e6f93eec3fb3ac80081b39610800d0822246e130e8c5f7a067 -a18174ffb85d13b7edde5822f22872ece12383d79fbbdb8c02bcc9f654cea904ed8c03b8709d70736dd4b308ecc1607c -a54e4bb27d6d561261a3fc48705781399f337448c0afa68c074918d2c14ea7d51263199b01070b7161c3db8b9949717d -a7457cba2c5b455584980ab6d0bb5253dbf2cafea4efe5bd769020b970dc35fba4109d002f5934610b8b4a158252ebdc -877d4111f50f77463b60e07843b4521b2c44629a7deff20dbabd412206a4fe03f976de1a3897b9df7eed16217f03e2c2 -84d1ab99732fed1470f69fdb499dd3de795b055354e89d522c6a7df4d6a5375052c8befa4dc7615d29b3d92ce7df2f24 -93bd139c343d8b83403e04547072c3e546c67445220afd06c119f7119730288629439640302d0628e74fa596e305c0e0 -8157b5ab48d026684f6b51b802b4d8e7f85ef82583d1e8dfeca042b47a0e0f58e30cfdf4738e6d51394b260a4ca7e19f -8f03d5c1720540c29a1dee44ef5c7f8b209094ba8376d8e5eb9b52537d9843912b68562eff742f0a7a07f5faf6abd1ba -a15e4999a0028b8b083c2afbf4968a1f0397c26cda8dd7f6c134c6a860e740ac4bf1a1936849a4f2080e0cc9f8e44387 -8b71fb85363158c7afc3c41422e9a32ecb2d1f9d3c01fff00b77e0ec6a8661e95b552a7f05f4acebee751448ed750684 -b34125432d0704c0638090fc4566780d2d8038d803f96e19ff748325f8b5579cb8867e12491921feaf3c0df949f36aab -968196e10bcdc6cba28331a229acd54b59edaa83cad0f8d14f39d787467bd5ea725a3dc3d50accc334e74c81fd762cff -968abfa40af365986e68c47b4eb3562a72793fbd66a7d1b3804a5bac8137f0a3cbbf5cd306097cbf1a3b95c3414fb061 -85395fa84223dcc16b7e620a7ef6f902f7b29dce7760f57baafb37d985755e65623768b8bd745c8de7d00e2035aba7ab -b57ad86ab3f5cb00ca0855088921865893b6e539edbbd504238df2f9b2fa7c7bdbf2d6eec6ba8e2a70a4c4fa3f459a97 -a2f203ed1f07cca3f8c0d35ccf7a63216ab98c9e71557e829dea45e2c723583bfbaa7a83d66521b08a0718c63973a6b2 -99a3522974525f4ed10623bae83dddace6f9495687cb9cf4ef52c8530b05672c2b226d3fc5058c56462ab3737a068baf -a4a50d127ad06067f1eac2d61c0a1e813fceba2e5e895467b5e6045c9b7308d3678bed9212b98e44c19a1783e0f57bef -a62d103ecc1d5e1d5cb98a0bbf9682ad65774d63f67f95bcbfb0cdb5e2437f2279043e4426d490f534961a2487782cce -b12fdaa5ca77456e6e96eccf97a303ee2d73f547916ed67378835402136c2aa03e63912edf5a67785f7ac1636f6ddb51 -91315750043c4e08c7e4359b9cba25309eedc9c85672851f05a0651dd9b9329bef00a79cfe73ddc308d97cf548486b47 -947115aa6cb3c635bda7f3c5fc3dd0e4881500d74db4c0579e4b9039b75b131eb5db54174b1bb970064740551e6cd1c7 -aff091a9c7e86c80646cfffbf154ecbcfeb66877c5b773b6e8759649ada1094270e57970cbf2b0a4bcde9bbfa9689b1c -81e3cb9116f81e583b7579f9af06931a5337fae0d57d9ef777003f32e0eb619b75b74137385f9e30dfe0e10c2120b02e -81ab49647db2a5a6f47ec757d8427325fe721142377a287c547fbe04ea280acb32d71f3dedf7ec0f67b43ffc5d748342 -84b0e16d8478b798694503ac4a87ff31affe0ef6d2bad47abe0fcb3a2571fc8e4e9c966276a5f4968b2675827a115818 -9567b2edd65974393cf2181d235f877f5827a6d5ca16e77165ef35f6c66370f0c55a2dca5387c02ae73a66b81f01798c -af19f841026271e284548b2cfe9fe7d6f9acdb4759ca76fc566de7a8d835408f86627185fe32e705f94e6a719e463cd3 -83883e1c9d215c90948d066d2210528552093a726f0a27b8342b611e4b8639f6d2a5f95bef8cfea4312c1f2203f34986 -a48019b2da37a232b7999f6b668e2758f82132e15ea93608bb2350d3188297c8ff8c791977f2a083ad9773570bb560db -a1fcc29974eb065a350cdcb4283b2a813f02421b872eb3c15056ef96e2d5ffe2fba0e10ba19a4d271937cf08838e4106 -86f9ec59a1f5a5796e498247c0ef1457ea7ab098247f363329a336a1ee57afb31cc18d35e008a5263e7c401fad5719eb -a903f95675c14cc618b02f7a0401ab67170b4a143925979791d76aacc90ad1faab828fe904f13d155425b2ffd79c008e -8f652c4982220b8e9868a621a91eee85279b13b0c2974472fbba11775e6bb1d8d53309f500fbdacdd432170bc76c93a8 -a9b02cfa052b5808c1c9ee65ade446a6ce20174bd2e9d9c7388a1973b0290debbb6fe82697f09afee6ed01c9dd99b905 -8b4c700fdbcb13854c7b1d257a781fb7449a9e3236b962871f11b31b1f2e69ecfa6039e2d168ebdf2f142f93b91f5882 -a9ba2295980603515f80f0130993f1be434281fd4442ce7e68b2fee12b24e440bc0282df67707e460bc67a4706bdf8b8 -a382b85dd64b70296a2d16d1d15d6de80687dec9cc074445fac8de7bad616a95972ec399bda7c2cffa4247bd04413b76 -b6adb37da1c6cba5ddfaafa3718aa66fe2821b43923ec371cd4eb9e974ebf3d0e94dff1ffc1347cee5c9e19af7c76be9 -b5b531ea7f93c4756e5799118654ebc478a3ab57ea51125fd31c012053c759c8a52c8830b53208f74215e437d059eda6 -89c88a5ecee1931dc027d1553b5aa82dbc5fed2a4bed329809467f79f2712fa5529c0f80ce6891817927d0b66d356db6 -b4ad1964f73d3b7bc338909df2ab8889c4faad9b3b8a5959ea81f44c6c4bec95f0fb6e8fea1fb7e09789c690423e2b85 -b573bcbd8f484e350db04eb263187ae4e99ecd03494058e68221aad8d044db82957f4bf23f71a9634b2ef9612a78ecc8 -93c3dd86f7c3105fe482f62b0a56fe43338aef50f0d10f237ca774f834151273aa653e17bf919e54aeb35343ed790c0e -9069c429e7c6507a755871b301b31c3b4233006c51bb66ea2c9051c6caa52e933ad81a8e879129e0c1b099a124bcb295 -a22203e5bb65593bd22cd5bc6e95a2f5c9a9aac1e14d948a7e0aebce4f009a56623026e0980bd194a633b42f15822ad5 -b1585de69b3014634da2ba76218321ff4ce8476b653ea985a7330290b1bb1445db3e1f3c510f9ae7c22940157e2df36f -802a70ea7fa057a03d12538c3ad6b348a8e694bc6b483cd62c97af8809627a161223557f1d5196e23f13eddce15c814f -afe8b0e94d8d9b44652602c5ad15bb0140456d90c95af4ba58cff528e2834e0036572af867488f27cb2d27d81cf02e30 -93bb332d924bcacc41b4b9bf726647d7cbb642847fee5ee7dbf3d2a0489d71802d959a3e905a80ab1f34097328632f00 -8caad1d29fe712bf09d505ccfc724574c8edaf5fc743953b2771cdae006ad9792a889e0c8136409b8f92e2cab5ba09f9 -8678be67412da4d43d74660df98744c54365cf10aa59e522c59afc3836d115380416cb1ae497ba4b50ad31a23ece8b92 -a48e64a5447ebeb5f6b0e0fea29fd5845b378e83f6b06b79b604081e5e723930a0d4c6025627382f6baba8d47425cd27 -b8914eefa2f5613dfe99f11212912dd53d678ed349fe871781074d5b6eed1fc7f2e5bbfad3356a685c52a3c8a26e7963 -836ba66155facd2a1839f603644aa5520cecaad130fcd5cf379139056d3e163bf35f172a4a1f015924b89137f83d366a -835b70cc340b57a09b1fecac678be381ffa4c4951f6742322c2751cf1c748ffc2b9bee8f155c007d88ca69c12bd9db20 -8e98b4ae7c68941a48a70f703c3d5bc9a4cf6c20c61eb4c1338095920c4f23aa9eeb474a0430dc28d355b15dc6e83b22 -b24be8171a105f203c5bf2ab0797dca8ce61ee07307e1d82fd26fcc064bd8a8a5b6bcae8dd611f8ab650176e694da677 -b057bec8ca008dbfd4982ce4516a4925a61bd68e7a36b182575c6a4044c7a413ecd1dffa66ae3cfe2213763dd0f55a01 -8d270924c541120a18d587cee51711486f09a39444182800355c4193a76789614c6925e6a448f46c1891106f866f08db -a0ebf85c44453153764bfc817364493166833b0f84b7a7c505a955cf3a7d4c1b4d2dd00145220d8a3207758a82dd8e4c -a56fbc83a3f1034337ca0d5aa89a0a18f900c3654d171d47ee86b0720c6a965c09c9b06678e3f25b151b115d129ff7bb -833618f5d13b7919206c8e9666997ef26c04a74844f57150e7268bea540e30b93eb785803535566765bdc899d4f10667 -987daa13c00dcacdfb1f0eb13c38ddf773e7e8e19af125604ede42c6d0907f9ed1e4b8b8c9118b14f9449026802a6200 -99b6e669cd7532b435d01b20dfed29211042beea6de58acd68b6eba26baa1687d80aadff901b5607a2553df047ac51d0 -82c81899cb76ae21838558a1946425c719cf68d07950b0f106b859048107c13e4e83b0f2762ac8590cdd044c3e731f6f -8f1c5f634e38f47cc6967f2a80a449f5bf69585622c333d784263e3f6f027bccf8910da76435a84155a6fbe9a8adc4cc -92d3b5515744115dd20742be1a72a455c6d481855f4366a0e960104665db4ecae8925182f32d4e1d9dd7fb9aa246726c -ac86e14775cc4ef22cafa8ac3298bff27fbefa9b7004ccb16d2937128492a2c1319641062f609d27b9314aa225301d14 -a07e1ac19f4c374d68084415fa4a8068c0be540c8b9d81c0837347fe096547d8318bbd804b7642820e43c284af663258 -839266a2fe6dddc446d4b515eb538a27b5a3a5e1a8246f6df77c2de8267e172bb7522aa7985e0503c68db9cf93399b95 -8a381fa29e553fb57e3780f915a86048aa82a8a09059c80154df9490271aa6b99baf6bb217df43c8ea1265e85f07adfc -8d8806db0093161d7f83aaa2cbf0bfb8cabf823cb54bec094f886da6461397f41d54c39f216d7ff4a8262d12aa8ebfc7 -90aff3f98394674791e194b57c3f4e6e019471df1a74dc47bed725d4c47399e91c88a955612be47e89002f451ebacb55 -8bce2d60f3e82042ba94cddd02543b46cebb8770e9b7833b4e79289d4c491df7f4da0ab69778cef92dd81e5a6f0eb71d -8246fc9424b5d5ae0a3344acd7d6962fba6b68cde09332c262d7b3f379cac2c650d80cb5ed4baeea16a5557efb6878d9 -92ea8547fedbf440517522c687f1d652ae4637cd072147ef31338a40e11017bfdeac42a32808d33522a71136cc3bf26b -84f6a64600184c54d3d5c320498282947b8a8166f09ccfdfd6d285cff374312da57087fec3838a49eac5b93315f03b80 -86dfa1485e343c861286c057109119ce8e20abc646a4411696a3bf4718ce03d37fe14b6ea1600d8a7b172fcca6d08ea1 -8dd3404facfe49c2f096d2e74641c474c9c54cd6121771061db3c1757cdb1cd6813d3ffd79e3b839b348d34b7b4f1ba4 -8870cf255b342ffbaa2dcff41910a37afb29ca6a721774953dec182d95b426a481eac7bc107c4c2ef3df9f70e04e0b88 -b0b843ccc630209b9ab35a69f3aad58c76b2cd3cbe94579b5757350460633217246b342fd098e365fb3ae88d5b7d13f0 -804fe307b2d477085f8d9800c8a11c2dbf6f662d684d6a0d2fd415cbe4a09255e47535a08796a805188e1bad779ce121 -93d91029bce430ecc5f41a460c02cefd3fdcb8c3e761ba26a020e108e06520cbe2eb0c04139aad0c0fe58ed34d8b2215 -830867ec984210b314e7f23dc5b10e6d9ca53789cc447e29ebca229f4c79c9120618a540a9d21e4ba2ed8a811d6c456b -8d7a89ae9d7318d6578c1fa75b3babfa7c9df7099eefc2a9983ffa96627f4e7fc99dfde21b92fef5e0034dfaee35e97b -8eb68f5875dac63cdbbeb5df2fad7c1426939ecb6e3b6a48f737bbac1179ed4cf5a1e6919529878169d6d8552fa5ad56 -861e26c9a31d21839735cca8a384b981f7346b026cab7d60fa95a7ad7a4a370cfb409812ca285090c3f1c3a95e5194b0 -a02ab98589d48b2240209f54b0be78edb56b614b1aa02095ab5a9cec6a04faf065eb7b81bfe45aead551b1f774c60161 -88124374273a2425bd5932a6b446986756379c7eb93d3ba0c5d7cbc3477e6267d9c67e5e956cf6df841bb263d1a8e224 -91a766128a4c718a45db571606867bfe6e1b1049f0ccf71a01138d5443014c9758000a8be4dae0caca56321e3f992e99 -8dbfc433e2477b9d86f221e9c49fb8db67c85438fd54b670ce44b68b62d4c0a9cd56c37a2127fb2adef22c07643fdd3d -880cb650f01191db0dbfe63215d208f70f924380fa22baa0e5bcab60f61ece3c6d4cca0e4363291f6a10aca9649da69d -8532214650619e201bd330865a3228e9ffaf1f64ddd33d206be5616c691b1965814f8bc507fc8a695c8291c2f8713dae -90e81d5a9d8fc976a3bf6ee6d3022107d3a9441ff212305cbc7c35bc9163321cadb352632181ccdc1450f91f51872b00 -94d656836edd68384df1fe61239d40a36a0fadd59abead673e4a2ae58de5e2a6bcc4b980dd9b517e7212726b8ac94ee7 -afa70edfed2d81326f26f111982aafad55f510de95555a4d05d9916a600f3ca6c1e3f66d6b092c91c1fce6c407e022a8 -95cfbd616c2a59acde8152578737d3ed329aa82a950dcbb9378bebc3ec8beef9be2759a937381ed5aec1a46d486d1afc -a0a1ae94bcd07ba44c30bf50cbe0ddca2fdb5db82ae73e53c2efe9446c2464fea8e5de31da4afb99c6405798f0f9a59c -848e10f6c12a6adcf711ae3af8382178c46b90b9ff9970350f14b1a1b565a7efd91eb96871277b86040d26561acee099 -815e749e4a56c3b982b50ef5ed249c4defee558647a5c6062022c3ef42b5ebb219ba770f0de74869bea14a98eec02360 -a4d88794689a0f2e194988114ab96d28f77a29cfff606228ebe030a62eb4fba25cefd59d3d5f2fb66acaeda866f5c24c -ad59a8541eb9641c3045d5cea6e3930b35886da4c96906f701ed3ef90cf74431df3c444174d9071a1657efc8cebdc739 -97ae83289d535707039e9df8ebc73262f881ee8e288f73b9f0d6fd209385d3e2b761fb87ca852e10cc4818384ee155de -b47983e11702462a23e26c8d6407b01b67ad532bce3f1e0626fe3164886603bbc803c688729a64a69d119b15235389bd -b447011409a07a2d9074e08502e882098799f3b649e947de44c79ecf86a63045a19985857ec500638a3baa2b228a79c7 -870f506356aa4f8df7d61449a7c7a8689705388b8b81dfe08fd79e8a734c998a7ba71f1f6e9df085b8aa5813a4ec4adc -a07abf6abcacd7612338b455c1461ff484dccda7430d4e9c5f9b4e5c1cb65055f4be650e6d67179b2c62709cd52a9b07 -988b73c2a71f3b1d6b4734d231c089ad6cb07f7ea6f4b8fcfdd34aa33f09feab6cda91232c06b47e90ae9930ea46beeb -886443bb8d7d6c7634f55da1c5695f1691750fbf9ad2d63621589f91a0205ed4adbd4b905c62effaab235e740a172040 -b66caf1ac38a8a66c43767e8597ddb66fbefd888989ca1ed56abb96ab9fb41937927a792ce422577c68286e53bb4856b -a84be3b37007cc932429ba2b4064ab7fabbd0b77400bbeaff09f8c6b818b5cd127ff8497e131dd8bf4323e092c690219 -a99e9898b6f9b7b1b9ef6f28f60fe2ea71e961b64b262cceae41003f6aaa16fa3dc1c2ab63bf63534718ad812e882a35 -a1cea8f3f5605a5c60144fed53943d3f259e3e33545eb0dfeb211a9dad8d99cb3cd3b2cf5031b85778ef6520700eac4f -8b979026924097a06b3827ad28f3efd7f0e5aaf7920ebe5347fabc61b000631f0ee973b61b7468fcc60ba6e4381ee478 -b5dd7393dcff33d6d337328167ceaa7a04a98e0acf1dcbaf454247e85793fcc9a7d280ab14693cf2cee01afdf44506d4 -8580c90d72c0c83c6c003dcc340553ea547eca5989780493c2551ea9f04225d77ea76acc1bde20fef1a0bb7ec01685c4 -8c77db66f09e76ebf7ac14fe2fadabd41291f7ec5971060580b317f6af0daabe099f9db2c3d09c4c6edfa41211da0c4a -b6dec051200c25f150d3b9a7802f5b7c361b074528c79dccefa77d26ea2f67562a6d9fb8246369c6a60f832fec6b7636 -8620173e19eac12fdc7796df12bd3648c66f78fb83a8e6f6c9077c34027a3acd0884ef2e3455a3de0fbfd4ca130ed545 -b44e3ae4047f917fe1af378cacae2813f8774307c20d54c565b674de197fdf90e1a6da0733e948c3218353c613d23fbc -b330af874ac5d749a4ce1a23f4fbfa67f71e8fd16f6da07c714218be431b2a30cc4ad2594994a7a35f5aa06bf87ea3ff -a5be67aad05a965685aadfe03d66ea1136e6979cef00605e92912fe8f84be7351a6acf6b73c567a20ce6045a703cf557 -a1672ed63df30aabe34e8eb81209ff31f4e5eee620b58074d92d9cf2687e40217169df59be8af7374aa5a9107c5f51c1 -ac01de17b74e2dacfe3db539910b6c370de94e646b6f2dd2a828a381b04f2979f8a62bac473659fe7b6e126f15ed7aed -b978099cd3aec49300ef9ce5561aa30da4d37cb5c697e0b5cbc3c42ccf2f96e53e948fc579cbd24605101176a353a962 -8c8c439d9da3627e9f74da784bab8191552b945bb5bf9abb673659c939a60903e11f37300dddcbc8a495adf5c038234c -8b4570ac55ea349560a4e7043fa17f264dbaae15a2f3dbc5ef8a6579e1f9b5a440aeda94122982fe564f78b615de3e1f -a76bbb163db2ba26f5dcae8267d1a890815a76196af10444d3a04c1debeaa3c7cd51102fd0bff8944710c743f5393745 -8d3ba2494b612f93b4ebab77e6f207b636e2d09a3e4a9666d4ddd5859fdbb9747a88eddb7749356b141a071584677ec5 -a8bfd973dee352ae653f7c7bc7df2b32d790653a3f1f2b239d71677992938cabe941fa609e915e607809b5fa954c9073 -aeb4c1ccee15753d4fbba545ec4ebb05c7428427f087fdc0852a18439b19b1669a3c744a0ae2e7f74c46905f520c3231 -8fffac3ff9de863257a836aff3cdb705fe7f4bf604c2cbe10180d81c0956f723b69438bb8a3aa094fc755e386234dbf9 -a583153b241d31223ebec9a95e11ebc4a657b14056b8ca052aebdd9866140dc4669bef4f02b5ffdf667ddc9a87e0bac4 -93177005082ccf2143f24c063d20068fda393948bfac34af57ca58cfbcd0bf9a0de46f8f41312e83a502b7ad69b8f2ce -a79b0967599894340ef2408b48f42e6ba4f406e5ccaff13b46414ee38e5329ffc145f6c34d8e8acc6aba41c23e57e7f8 -809a356a76d54a05e5006f2cddf0decf73e5392b57ead32ab56bea9fe13c1ad090cd69a8e297fa6e017b39361906360f -b051226cb44ab1bf94a9cc0e4f246751d68f32ffd12f1d077d3318de642f3997fbfb0f2ae1dd103264542c2bd0293e57 -8cac28256b1a82d0be373d884d00e9ff2e384d5afbeedda706f942b1d222694f126ad44f9453fc8a985cf69fe11ad70d -a13b073290de7a2f01a65e429e1adb78cd37eb23c24d6fd5a1632cce2275496179e3c22e0b7f59fb51d526402c0f3f7a -92dab68d1dbf07e5b058120422ae610806809ddecd2aeb9d11d8fcac738c72eca584b88ff52c95817b79b9e0369e3ba6 -b24267fbee28883cc8649c243b13905874e5d97a285b9c6abec749a53e106db0a6fd6fd8671d5b7c9a1851da75a4ac5a -99cdf977dbfc10084b698c81cffb431a9eabb55b1323e1b15baed5984a1ed212ec5f6c58372f965fe18de0100292e26c -b021c697c56989bc8c06636cd623c3672e8885598fd2014f5e560fa2f721f9487cfdbcf4adfa34c178ac84771fbb77a1 -8fd7e3ad3330d4eb1a0bd42801d95ce40a82b43c366abc823e25311aa1ed882446d60b6309e1a1e201e725326736257a -b1b3c641ef4cbd5e9c69955217f53373cbd104916e04d012eb40a24d798e76bf05ed0a218862ce02619ef694c42be170 -a376d0296c0105789e9fe539a5d22bf62ee36a2de4c9aa0f5e57210ae49e2cfc5209fe0f467ed19dc95b9746595255e0 -8a0ec125a145e373929ae33efb978bdaf16041eba684ada612c244bc3e28c7027886e6308373a5ea53c9c3d8e868ce1b -93fde45cbf04cc386507b03eeb93c885da12bfe519df9fbdac5ada735934ea6e1a6cce066d033be66163b078e96e2100 -80c1839ee1d2ddcae1fed77d5f8091ae3074409461e04153db801e05b44a7658c6ccadd33ad682e51e211dd9e3c80f72 -87112961553b4a243875ac8d46bb6e274325699ccbdc40d7d9b7f7e58d3fd164f86b0b1df5df5f980785cb3918dc9b33 -a011463964a319c1ea11c7c55c607bffe0116fc834b8a1d3684df33f77f6e51dbe16a891307c9f51d5b4d205c4530072 -b316c4be33abd10400a4925f9d20ba02ab1feb50af39b6f6120d6dbcf1bde0a8dff7e08c64bd1f5c43543b013e242483 -9555b696d428c4b74806a7d08b9ff17c8512a86cbb13040360ce248de241facc42c042d3779c28fe98dc3ca96a47b2fa -819f54bcfc58a7b793d185d8ffe411bde6207b77cf22b0d5e1b3d9843e4638009c907fdec1966b485f95870da57f131a -82c3f9623bfb8a8ff3573197497c175fcb314addafadd025528f805b7a63c87b0e54b48d46c0322110b0043f7f77153c -abc023b35318fd97ec81933ce55799d8c36c3d55cf59b9efb302b276a76a37c517d5c690287f216ffc5d1fc082e116c3 -a6579226d602a7ceec06d402d38f217b836c8804e9da202bfaf1f3f4f15c24762ad6a2414ac022d8de68fb76ba8a725f -b701d6d60387d4e2308a77cebd210e868eaec10d86532ea18c0c6393475b3976a3eddd79e469458bae4f496da7398fcc -ab202a2acd4ff874cfc147ad1b02d4515ace254f8b828f619df2537698f4e1b2687e004c70a152d605a73ab1ae40fb3c -a7e09ef6c86ec7475eb3ed69e57e0cbe86114ca5c0748069d00b6e3a1e2ed74e4366adfcb4d938023560fd91d0f64612 -a9fc42b05ceaff4312d5dacd78fd2394dfb8dc87d52efb0529595877727747827c1c7e3a3da81255356033fce1f97513 -b0150a1dadde09cd60ec3686256b4378f47dc6a55c092c60a3a3f0bbf586013dc37ed53ba7a91c72791c0d52e4c49c2e -ac88e91b48f031df297c29fbb2cd0d2bcc767be5e0a7db87acc87fcc0f4300cce6deffc0b1cb6fc7e51c6ab13ec2ea24 -a8fb1542a956fdb1dcf90da2672d40c90a4aaa2f1232318b4112816bab660657eb97e3d0fee9f327793f6ba9bf8df2cd -b78191d1ec4615b03b21d7730d48fd9643c78c31feea19866429073f4cbb0d1a67f7d7ed210ab62b760c679515b20acb -967c20d53d46011f59ae675a26aaadbb7512d9f7fe87b7a20c3a84c76569d23920121063235e37cee2692bca3af69039 -9766abf0251cefbcfbf85ab1322f62267c22e6556b7fb909413a7819f635e3ac1670da6f5f72d3bb4b739e12eae5ccc6 -b0e9c5c327fba5347474366eed1ff60b986a41aabab00abe18a91dec69aa54197d3f5680603057f05d5efa0a48dbc92b -ae2f5defdbd14e2c7eaf595b017b4a97edf521f561ca649b6bc2e66382478b5323aaf84f0b90f0147e20ad078d185248 -b841bb6e04d2409a419dff4bf97dd3d4f06f6fa4e5e23e4c85f23533b7f25fe3da9285ba033c6eae7e5e447e35329c0c -85e26db850536cb6d3de259f662a88d23577fd56d1f99b3113ef1bb166456324d3f141a7ff63dbccc639cff68e7ae5a5 -8cc36d89424da80bcc2b9d9969bbd75bab038c0cf836f561080e14bb691e8e0c17306fd6d42522030d4640a01d5c0704 -817e72d50f68dfbdfc9d5611eef7c6b490ef1509559801fe1ff916050429a5f79c8d03c60d2bcb02e72310b3c4c9d068 -a15ed72881c49b545413102975fc69649fd5417f5b7ea9091f8209974024785496fa0682352c879953cd1e9edb3fbee7 -adafd20b962921334f4be2188f9ced4a5914389d0afcdbb485096d3848db85152e2881aed0fdfca11f9c8a9858a745eb -8d8aaea706815f1ec45d9ee470698ff199c40b1ff2d75bb54afd4a29250b094335538dd41637eb862e822c4cf0e2bebf -b8480d2a79cb6ada254435dd19d793598adda44f44a386ccb1a90d32cd13fe129a8d66d8babd67044de375ee59d8db51 -97c17d6594ccefd8f17944fb760fd32cc41a9b046f87893bb7ab2260090de291e8260ffc63e774a4b6b1dfe0e5107ef8 -b5b7e1d4d9683de7193120be850395762ac9a5669cded9226f5ca2a3de13eb13b2900af083645ec35345894de349433f -9405d473872cc9f9b9c57bb9976d3ec6892ea429cbd1b12f22962b74d88448d4ccdfcc6d5c6ffa068d560d7bdc3208a1 -b99cca139a3733b365f4718beb4ff4a5fd6aada0173471156640d8be2cc69f2a70d959b57688f927bca2329c3b30477a -94872ec872f19279fd26abfb132b4a7fd8c485fbdf04515c7b416fc564e61a7b0fc5da9f1a380d2b3db989f1832ac1b4 -92aba716538bd66e35a7bb877cd364c1b8dc3055a9cba2da23c7d9c0a010209ba8afab455da99747fb4bcc8fd3144cd8 -95ec4c205be3dd5df181220c96bba3f4e3b526fe5369035edfcf706c1eca43f29a4c95cfcf94cecfc974e01547e55125 -b48c719d7cbda1e79b3f7ee9c17c13bbac197bb015b344f79bc6785b28a1e9484e2349178178a2fe94c46132c54983c3 -908c495c355a0555544ec6f0b8e0dd0926ef2c5c640fcb89049e6178697625b85492722d42bb5c966aee2cee9981607e -98ded9cdfa92bc8e3664ae90af87f88759503715f6eaccfc983e3ab53f7b3af6802999da93caa7eb3530402ec4d8901e -993266bb366ba46d532973391af7204aab46a3189c83ce7cfd2713bc11e99066b1a5a012bead2fedb09274e7b362e8be -88d462a3a17f84326b1e4177799d6e9c5f4ef57152cb83ffff4353a8382ac8be7d50381723aeca77d33d8f07fccf69f7 -80438d9eadea15c90008ccf4758d4e3fd5a7bd02809eed5b683f2c96a15d24524ffe75683b7167d42a47161c65d533a2 -b9e7dbbd3d3d0d86e347831cf99657fb269930087920637ac6cdf185d5eded3f09cf3eb27759ce3f4b46f41411e2fdce -8f0215f23b4945470f74b99607c12c36eca41aaaf99747f522d8531244b668d6ab8c1096b9b5697208c3931e1fefaed4 -b2c8d8515ff16beae04c855b4365e450e0ebfb423acf5da2501fea76259f862bf29738a858a4093b98c2a444396249f6 -b27364a7258c30a59d1f13d358eb49dcef298a92bfa699b3b91817d2f324be8fff91c0b71cabf26747802a92582e7dea -aee7d6f71fd674cdd8dd1f22195981e7160990c16647c871835d988e881a3d4c52345e74f7a54768fd97a65fdbd84567 -91356cb2024f7703ccd662f50baee33409c28ff13bb5eb92fa93f303913e9bf31bf83b0babff4b5e3649003ae95492e6 -b744e4754043d3ed85c3bf6ccda60e665568dd087548ac70670b90328509d0d5013cbdd07bf603949067e54d8094fc2a -8146cbea5899401a80676850d0b43b02d376b4b8f02ed63a7d92532d13689e2c02846df79cffa0f33ff81c3bf492339a -94bba8a1508c6296d3dd5d2e609d6d732ab2541849deea5436a4a9034e1e6f1c8d26f6b781fa34dcdae7cbf8899d006b -80260b321d932e1179667de4916428c1b77ee1ea537a569dc64a12da5ddc85d09896939718ce08ea7e0fe8f8b115c408 -89d4640cbbca5d105dd67250f3bbfaa96d7ce19a89f8d6e188353f3a9b8737f2db1707c506f8ffe1d3144dd1da371920 -92f5962946ef7190fbb7bd3935427157ffc815a52ef44397ead3aaddddc82e5f85b1edcca1e9082a500960e19b492614 -8b89240c9b7257cbbfcd6e415fd035ce33bb46c773569d217c82ecee5dc2d66eedc9333e0b043616b0cbf21744909b60 -a3d23484916d2c0ad1b81fc7df70c97d711040799cab076223e0ee02a45a0fe9ab564faf7a225982468f3e62e32424d0 -b31751386bcd471b5858d001fee15d566215e34d2d62556c51ddc60a834d3f1acf18c415c23a36b581cdf4791f461ce1 -860a99003b841221dc5ea2bd7e226e5aad72db8a5959d5d4dae8a86114d30b9e8915b2314ef867e9c2a477d9424a2d94 -ac925b330cafddc7d95d115a9e62b2c135acd22b5e35a4aa789f4318f03aabef818805845f2532e9504bb19f69171809 -95d8180cae0815d33bf8854f4590be652f95f72fc29f0c519ca9bf3f490ba4a724b23d9054e08e3d31bd61d609a8f0dc -994f223740ff95764fb88de1ad6dd90c9c58c0dfbf8482e1dd9bafc20c099a6772acf40569c54143f6697fab72772296 -971d93cb1e7aec5defa52815bf202b11de6a2ac9c5d4c0eb236cf2c4941460731e12b718f4a5b980ec6f4c54c3d17deb -a341095fe5adb96dec2be367f09804ef4fe77d553102ddf7d643b7277992708e84be9a7748a97a56f065002a97dd7cbe -843709280fba29d446779b1ac6e31bc3ec8ab8082e8b063ef8d2f3733ee77a4191b55772302964bf867fe1044dbfad65 -b7ccc71fd0d0c9642c32d292ae88ca369d1fb5cabb97b1745c621aee41da8f94bb580c1ab23664c1baee65e97b21f0b0 -a9b41f31be84f8ba061570633bd9e5f4d8af6fcc5276c25d9ab67b2b88c1f8c2a87eb19280cd4fe7b4c04da8b2d02d7e -93eb14ce0632cd325429e1c23340da9655d3d7c2b42a4594bfd5a4e07815afc9eb1ac737228771492020f6528c0b7c61 -959aedea532471b9610150657b895c5f51ca950aaca910df137dbda2d17184173cf2638a2a0efea3f61d82b6ef8a7c3e -8ebfb50bd48fbf9a6f782454ea900acf0c7143164de9b5b46c1cd072c69b76143ac4c99bd43139b5e55f847841fa6a1c -851499b3a1eae6da530a47d3e8bc068e6e7144b744d5eca5394f96253df65094e5f3c34abfaf7c7d78c4d5a5d4863da4 -a8d68bf15b900cc47197739856557b43a5eb233b6c095f21a14a90ac8c36caaa1a54690c95840f0a4d2e2ffad0874a2d -81a6ff8fb1dc4d4042089d4cfc10cf826e39083aa5983e53f4866f8f4c10cf06cd8608c4cb1b785f8d309bdb9b2dda63 -82f658bd1a95fac0b65d337efc95d856aa65541d49aa993b094d70e527e7d478970eeb3daa2904a1309d755e1d677691 -b46ba4f3d8f287eb92390e5d930df4f1a40abe500c9aebf62e2eeeb2e5ecfe5296b09fa22d6c9cfdae28d431fd10a00a -b5b38508befa4623166f6213cfd160782fae5b7c3c7ec279b42a83d43a7adcfaa6c5b34cedbf98bba357fa663eec896c -89b8a0fb37a0c45eb1f234ae9c7be65c8a708f08d431728572169b33f8288b1e17b7d4b18de9fb76afc37ae609290623 -a7d1f5779c043900f3ddf29b6b7ae4301699c0ee9e70314fcd3bb2643f912fb1225a0164f45c47419ab762420bf8e5ad -89d2a69fc014068aa6d0b79784b8953f3519f563b5c9f774f4b148334d822aa645b662d5efe7dc6f9cccc2f67268c3fa -a698d3f0b1b6b72b72358d5fd5e49e928cfde69bfda10e163b9b43bb9604362b32af1909d28da5e0364abcf5e96cc226 -91c12dc25c48aee56484172de8c6aba0d9f5eae8db848a7b53d76001c292d115ec57d816c2cf10bb9e901b2707dcb71d -b0740219e084d56db4829daa30b2812115b2e95ae85ee96a140b7c4012860e8017e19b482e981547e50e25bd4ba76716 -8c84d4fa255e2de7cd23b0bbd110687edc47ed7fa87bd42658fbaf3831c6d68cde3ef403ed6c585f8654d0cd32074bad -a530d3272aa1740a73e15cb9b31c5e2e54c404db72274b0840c19b164642389acdab4514b9b2bf9688ce51392d8b6793 -a601f52bf7b3226fcab93c67dccd95c1d6673270671c4a099b867bd5578d5711fe9acc9b935b867ca780ba4a394279ef -8a238082dc8ae33314fe1257e7bec69e905c194ded6f894267bce97443166fb443628490755e1d453545f389b5beaa2f -88a9737f3e9ded874681fb6cc8abe0f6e1ce18a05ab599b2f855f73e6fe5bf804de5c5dddeb11057aeca6613bba72c8c -8a5cf70293eb99ad3c34992c47299646c8702d1035b75e4784cbec67b28cd4c88eb8c721f4cb8982d3c6a42d1b9f7fae -8a62228b84fa7463a6a8392a7af767b661382175633c5e00b36979d816a53b388f31afedfc47a5d8cbcb645e8d5928b7 -92836b5a41900a1c1ceec83cf4f15c6177dc20f95eed23a203810116ede2a072a8d6c96532ef32c93ee21acfb14448b9 -b4e538d7bf40c263dd1ede65c81883dd31f9237a0fc8d134a2b480a1a681dd89cd2edb19e63070ee69e96cd12069ce3f -913eceddd4c9939cf82c7e9ca5ac300cd79dc5a72b8458cd69e9f8929168eb19e5f21eac12a3b09eb8d3998e28e3801f -81f4a3e7195661b174aa2059796dd88d3206bedeb7d7cfbb7e61aee335a01ac50bb8edeb258a68949492d4ac6215d95f -913a393eba8eb88d1076effa8d2a30258d83635ccb346f1bfe099fb5fcc69d0457ce5a79363a618f9e8b43f53728433b -b11d721b08be428254665bd64a8864d78c5112e252feccca113631b2818fb729129fcff1e739178507ece41b807ffafd -92603fb7d50d11b59fe376720aa57412b866fcd5da90195a5a401e6222201b30c29f8797dcc1b41ee2cbc6349bd5ee1d -a466c5d41cd4a8d1f47a650ca67b529ad3873ba3fd3a36db27f7a5869b74b42381788bb1a1c100ed184118839b9879e5 -85c50607a86d4f76826220286784fa9b6ccbaadccb661fb3489fd35a3a8917d6999ac891190f2297afac3c37abba2967 -966320c2762b266cf7eac7aae39221599df4fd608036f6101cb8c68192fcbfd5f61c7f93172aa2be0934486fdf4816f6 -ab69525f1c77b6706592cdd5b98f840184b49efc6fc2687d6dad3b014f6a12c4d5cbcb5120d8869246da010823534d8b -aa2c9df15c06b58d7b9bdf617df8bcda83ccaaf6ddeb8074db931f7f03dc06a7914e322777e297226ee51dc8268e80af -97035b62f8db4df6e787cc2c940f2298c7d26c2127c7a76e4660d132a14f43c8bac8dd4e261605611b2e9c08929f2bac -8ace33e696953806f594427f137e84ea6b22ca9b48c3bdf3830b3e951e5a463d4a7067c68d2033eff452295a741fa1cb -b621fe49b12580bc8ec68fa39d5133875da23524a5ebc793c35040fa3436350d0f3e4bb4e53eaa23d312a7847e2eb2d6 -ab7d6ccc0de9c7ddea145e83fb423a535cf26d470af3326d1d6a9a579592b32ededb078bae4613028557877a9fe71642 -97528eef76389dd77d33ee7daebbb290814911beb725ef1326c3160b9003c3043be09bf3f84e4818bc2a7960ce1acef5 -a408eaf5c675b50dc1c655f83b9595dabed68e74e6d2eca5a4948252667413cfffb46358400df5d35f92657811ae56e2 -b36537726b26b474e184dce0ad868a66f0944b4105ff6d35a2cae0f3a520fd14a66630388aeba178d400b5fe104e521b -b2b88518d10bdcb111c82a261076367e34718f1d0a1a06b421891b4eca1e3c1f904b66e65dc914ff1ea5991f6a638a02 -aa3172531879a5c8f594ce96277b2c8c8d4a2d0f4bbe567ae40d5b36fa6108e00f0b1dc94b81f36c9eb6d1e9ee1896ca -a53975587f10667a9474ae2756faefe43e7f81bf9e051049de175a8ec085530fdee3d5e3db15d4be874ecacf49f31691 -a1abdc58bff4fad0f6562338daeacdac8e37f9f3212aa252b17389bd9c54db58706129a63bd0695d299d043b5ef0e2d3 -b8588fa1090597fe0f6275e5779da11a4d128c52fb8954e475c4940f1a3e10fc23ce1f61e9aabe8a75e82824f718a94c -8a1981c536747d4cc06315c794f1536db7ab3c9dfa024a0df854b948d93bee72083b6c9c4c4a7ce999c98b904813a659 -95b2b1ed525d629eed454bd6bd059b01869423c3463a56689a7c39cffbd3453c962426a1126ed631b25ae8cd7538302c -8032c60f083477693f533c2d8ae391d62ea754b8eb41ce9cd59bc469b980dd959a8ac840ccac54b404a9d08a6f9e4b98 -a72ccc14eeed758d3d43c51d68341fd7e98880c3687e122238d77dac8d987c8edb3067bb63baf13a0e57fe02334545c7 -aac3eb536a5061a8ec788ce131582dea691957ce8b9c6af5ab7224bdf0fd15c77bc6bc63ad037bd83e0ae52fda738361 -97dfa193800e57e6b19d1b7fbab40da6dd1463f043eeec34b316ba6bee21b6bb633ec0c4fe107c9dab6e06e07e0acdce -966ee3cf2f54777968fbc34f08c8de121ae7c1d6b2cdf1f1f9c675828d22ccb909bfdffa2e3f2ce51b0cc85bb29f8504 -a9df6dfd12f8c43c28b929280355cb23ab0ddd2cc2e4fe76603a2e5dc2ef5d1aca2edf89b304a27345cbb1f24a86cad6 -abbceef80c744e5a1194313f7b84b5dee1c9861cd4bd3d0d12c433e5f2e8c6ef6f10b860abf3b788aa04896f708426bf -b1dffdd81711e9782c992c4b14583ad9d6c39ef88974682a72e717e21923da6892490d7efd121423fdc638467e62e064 -817f30dd799c422da33e13ac2bada8cce3930233ddad495f714a1c789b7aa8f41ff6e688bbffc5f2e8dfc72e5243b645 -96760a79e4414ff1d19fee65b6e65b2dd6665323981ce8b4ee93d0a9c410b018ac086c08fcbc7a71720e1e3a676f2b3f -95445cabb75909262975a5b06381af2bff5c4c6cf51cc84adbc0b7f2a985117f35c014e33672cd5216a9737d3f37e067 -a279c905fd9d49482d213f5eb98256d020c2b90bebac45004d6f152ee4ddcfc72a7e6b188ce3b6c93ebb9ba9b8be587f -8591e8379a78af8860e6a0e002be5b25aa4b93c5e556f5ae2e40400f828dfa19d93a4910823e230a51e2c1ea5464d437 -a6fde17d41fd9f03605ab6ddfc992e36535a23b2c39608d30cd6d72588f1ec6afb9db193e88eb609e104e73ddde779a7 -93e2cb6352a5eec063151e5c9a822f6fd475a072dfde2464af4afaf6a730a6af1fd74c424c09727328a7f23505b91407 -a7b1e4f703386fdd16f5fc9b59ef1dd682bfe5a23bd42b3c4b1385bff894e758ab09674dd6d0ded5b32a0a0526aa6d98 -aa7f01c450e619c4bb42d6cb1a90a94dfe132a641728a642997b71e2c3b02d09a7695b544712b2e14416e7de0252fb11 -ae840b870a938668d0d4404b76f5d4d252d8ae1e3619661df0890ccbab900e3d8dbd5dc9f96013413e3f1e30dc541db3 -ab7552930ab07b0f5d50edea3a2e5ea3ac1a05cc985246ca066fc3350bc58949dfb99d4f6a6408d1bba64d3de47a3c2b -8053634d4c730b5e90d68c2830a73e93f1c9e522ae0e00a04e2ba15a1b7b4fffb8b25516ceea61719f886c7763d46219 -880c39ca4cafa622bc767d3127d62143434d0a1d7de8dce1a2f94cdcaa023a7096641a46e6b97e1b1ce9c233c873a519 -ab9d46e46cb2f382ee7d21b6da01578b786b7998e0fc2b5d5a4e1a0d93aaab997b5c481c2d9a741865d6460ceef57a5b -857a5957adc3a888cf93f144aa809c70a211932742a258978af5e657f4f57fcb6d9e39dbe8d3128fac6c592dd5bc4ddb -8c98656861fb8c8a03d491db45077f1d136a759177842ecf6c1ca36923088237e928558433d5b631590f395db56f96c1 -abddacadd7d536e91d36609fd0047f5db113be0f4d84abc7631ffc5c00df919c085c049c013a05131150b0043d51f892 -a8b14af12cfdd0e11c8487334efbfdd22c8b4fe6bf350333d42ac8c704efe54f50a4bb51d9d802e5185ce72e4b21aa58 -a8badc2bb3cad0143db1bb3cc81751f9974ff3f0e2ee35921d04985409def84ac2803a657571699eba34767b773666e5 -a6739a05d270efdab18462e8536f43dad577158e1c1655fa130da97e469adce9bb7cda6f9ac26f4a9ba3f9b22329b066 -842ed6efb4395603e7fef0bf92326c0c63992da4ce7912f850c4960f7a19e0b2ecc720d9510f15ba6f73a2c5ada8ea71 -8502ede859944047898d533e1923ef90e1b5c17d985c9fb4c6aa39d50636de4c5a4df278f2f62cfd3ad08bba4c5ca6cb -8c738573226dd5617b3ca1dec8780000a77f3fa8de241cac99b0d9b1b6c90cbb8aa2009668005f2c5c7abb09c0ab3f99 -b101335c403d769313bd05c755a9196769465f7068fd6f9e00937f3cc843d48f013f5931f999bb5c0082d4315134f5d5 -925ace190259b321981fcf8bcf52c6852b206099f25c0f278439ef6edc4320d6f926cd6fccf1b4cd224bc52e5c681612 -95f5855ad1bf14224e51f7d5e0d229683c0d38fa324b1abe9d595685d3497955e30289618c4775f6083bbf923ff3a37d -a3d3c7100962c8b60c40b830af834ddc48858e7eba5ebe2874ebf74e505c25cf52e661b49d7619f2f2a039e1df02f5c8 -af7e66c1d5dca63e6be117b210c616efd533e77199d67d8f694e4278841963e0a46e4e44f0416e69bce6a7156e1872ca -ab796760166d1e1fceb20f9bf19b1b7cfcd327650cc7cc35c161ddbb3cd4846e9a971b541f303cf62fdc0124688fbd41 -b920211c5b440b3567942dedf62a65ffbcad1e3516f58d14d8f8dbe86f45c4b9745fbce43f5219b7052b27a3a04df12b -ab6d5d25b9fc46b0824df1628993e44535febd7c62185b6795550388185035ae12bab60fa34848f465fb4f4a8add3544 -a6539b67dfd6f3976cb6b304f4d152532b3f08c02bb97730c03c746da0f7b38ba65536faa43953d46e5e7687a86c356e -95bb225586b1c82d894ababea7e5dfa8468bc0e10a2ef34e5f736fd1611114cddaf1a5c58bc9d664b667adef68b5c25c -a16eefa4e6161a8e7bac63cffb2dd5cefcae57144e63b3fded581abf7ce32016a654aaa582fc25bfa51c83f352e09372 -8b742428f6af81261a47a0df061e480ef9176694d361ecb57967bea67e11cd44df686e38e35b7d4a6ee02ebd520aa1c0 -a2a4f2307f646384a0238a711c2dcf7000b4747b8df1d46c5da962fdb106c5339790b48682e8ec2532b8d319ccafae5f -81910c1d72f6731d27d3a4059ccb0316faf51fa58e0fb3d1287b798ea8f9b00bbbde31fac03f93c7e9a1cdbc9502d5df -b846b933c2acd71e9f9845f1013cea14d35cd4b8f7a371b9be9bec9d4b3c37a2d0da315ba766c3a126f8e2893f10af4b -8ffad59284b41b75064c277ab01c5b4b3a4f3c4b355bf9128160b1a55ed6b0d91366f7804006b4e6991525d3435d5235 -82ff36a72533fd5d6745d0c3a346fce4f62b6aca0b8eccd11399b482f91cdf6a5a4135c627043008cb137ef4ccd935d0 -a11c27f6eefe54cf32fd86333d9ccb59477a655bb0c35dcd028eea58d4cc40ef9a26cf3432fad4e9d058a27b419b8f04 -96642ce0eea3c2c0fd155a75bec3b5cd573d41e8081632c56528464cd69a1141be3180c457213128bcd37f5fae47f7f2 -8349a9e390e05150bbab2351b77a3674f1af000b6eb6752927ef838b6f0a1200e6fd7201dad8565e3caf3802f204246c -b8ae7fea6275ea61935d3047d8156e8fbc4a95c9fefd1c36439b2111b9ebeb7ccc306e0f8c875fa772f7b433cff848aa -b366f056e23905bae10ef7ce1728b317b83f504d128f5bd34701ecb0d25ec08491969625e23d5a2fcf0048af610664df -a3d88d506ba46b73bf07729aafe9698e788fd688647a6b4145761275257d262cc450c7889b8a40d698455baca55e3da4 -891ebaac7a7a408aee4ba61605f44f9ca5a6d5e046eebfd8f5108b6dc4479482806dd01686045b4c7760051f22bce468 -a6ddb74e3e3725e6f2d9025532ee3f357ee35289e1cb38dcd5b2ea8ebc0bb697416fb3aa73e1eba632d593d40fdb030c -a7dc097f440ebd31ec1a005648468c702bb77073ac8cfa32b050e90a9e1cf388f138abdd18f07951c752f7e19f706af1 -a200f25299f9a0542c196adc2e00289f453411066b88b125d3f0e6b17e98efe9da8096312a2f1841e01837da90a65440 -97cd3a9d4185d77d4c7bd4ee80928def7b660d8b949b0face798c62a7cadce1000997af29504d28ccf9070fc3016dc56 -b9ebaba1a15eecae6b1998ae6d08233d05610dc0933b16922076b2dc4418cbeb4e5cbe099bbded3139d8a47f2b2eae10 -86f5fe8fb36b419fe6fece1c5c4b9d64468b4aa0154bb5dca466a243b6fb1227c3b8bdaf7ce5c2d4fd05c061979f87df -8050e011011e7918ebc25825d9863c91046fc3756703bdedf936dec2815cbd10c2403ce6f4a0b4f576cdfa1347efdb85 -ac22132a482d2950be9442167be214ed9d24519073bf5ef1c8e3e6f4a77065da198a851950330fe4d62b2a1272835015 -819e2e8e3ac43b6ae4885899346f3b558bd7658ef7d380070588154694957596695a925a001a9fec7cf3655326c50c2c -b00f40c084d2eafa36811e0d822ffef874a0d4bebd4817690408a737624be05c920a08307cfa0c1195505c5e7a5fd878 -8355768c09515a593c8fc8289baa3b6cf7fc10d302abc93f72090ad99a70a1ef1107eccf839be722132259500a565d68 -8bf0615d2cd11b03546ab7a0c90c0c938776aca8a8b989a709c367f0f5eea7b0a7cdd78f96050cdd5d0a123d01b99c53 -827c2cce458464fdc716a2198fc67b3cf2ed7802a1f53f7a2793b2314789998b13ea61343c723da8863cb63def6a285c -b609cfe6acfccd632759700bbb0a06fc7903a6c0c5875c2c3bd85c65bfae7b29b03e77092f29d565a6a89b85012396fc -b73ddbc330e872363bed36578b245b666d42923393a1341816769ce0af24b700c19ea0f579e4f9aff1c3ff369e63da8b -976d658085e5978807e13b150c7aa539b44ab8855a386bb58a52d9ec9b5e21ddaf89a18b043394d6cf47bd589d04b240 -a213897312aa28cbb2c572e643d3aed003c84bc2ca571dc5fbea8a0b642313be94db0047e293078d975fbc6800751a87 -b54f2914f6a7508b6686280d3cc955730458ff035978be29645fba161ed54ef3d4086f956e68d2a48c49afe904edff5a -af99e470055062390904673e18d04427c16afeb7b9f13ad83bc2599e9a92314bd91d6f1f81b55419a4d668bd889ec8c5 -946ff0cff4030b73a1342a9173fe697ab20cc5e43ea6158573f2def601e12a174da431f8170bd31ceed4be48c90b4f6b -abc51f8bb5f74cee819ee383cbab739026c453bb55336fdf423af2c2ac6712ba90006d62dd72d8cc1b2ff6cac900c8b6 -b43623a56c5fd1bf28bc356fb4a875d72dd4cbb00c9c863646a3376937088f9932a4a0aa26afe2ad69840b06242ec76c -b0f371952f99eabf7ed368a142ee07d06bf2b7ec1ff852fd948b8c53eaa52300753fb9ff6765201e35873b5167583f3a -b3906488172c09e148c571ef0712f88bc9f1ecae0db95380f61901660fc1aa090d0740378d5b9b76883507bed100093c -945373b5e6ffce11d39a722df7b24eb929b14a967d211be3b969f48fe1ad3dd4280317d1ca772a69b033f3bf26c02c4f -b2ad3490389fe5bfdd5ac7eb5bd61facff8d57a8f9969f4938ea56f4a85eaa2c1179a2e5b4f87d9e6409925c75b61828 -a4d61547e405319cbc20cad16a2bfd9e6d093a064522c332dd22134ab05e893bc84786b21b4c71a6265bbd06da2ef4b1 -86749c26715d22b185e1b25dd34818e96aad319d7add22a98486ef9f9808b5e4b938c6320d391dc4e0fb5d57bd41778c -acc554d5b866693a453a9ec46d422c8b410458fe8397384b927a62bf5f2b1fb9706c8c21af9845050fea8a91786e3577 -8eb7e763d297cd93a7a54dbe4654c39c0ebfd73fcc34d3f1338de0c347676f445d32f270664fcb7b33347bd377c9f867 -a1b469e3f9dabd36b13149c83aa5b7b5987eb0ecc1ce6b68c72acb39ed503a11ab4451e658576a92df4aa51d1bc709f6 -b1ef105cd0259486be8f265a73ea089d5b7fab7bd7547932134539963467fb917b2206aa72446e2fed5a8185b04d345d -b3e211c1a14925f6de451271728a3c1e555ebebecd4bae29bf666927868039d4ec99d9f9aa98d835da7845a5c863dfaf -a416632a50500f29b6bb471bf00b37558975ac91e5c5b5004b67e130be1acc954a8ebaee7efcaf6883187ee9173d1ccb -8c655a85f66b5f28ab8760c94b6cf01cdc36fedd19a09c261e432fa7eda7928c3c88355384e689f1d2715d419fd8d898 -b1fa9f82c9866d4f296755bef5b7c39fadd09374f38ef9954aa57b1431a1ea4cc17a9750da844fa1f5848f0ab7ca295c -b45cdf1a9eaaf85c0b07bfe239da618ee649ce90b417d90b08eb518b1fd88c0d25cd29fa7a0d8058d6616627a3dda306 -a2be1552d3c4142755e0371a9543032ee82ad669d7edd24c4e2941bde3b78c5c6df427228fc45812a55943b3663cdbda -a28feb053e86dd9e2f9ccbb7c38467e2425fd580ba0f63190036fb47d01eb198ba8590b5cf68d1c0f47638e9dbdaec74 -ae06b849e080efcdba86fa03a0c9dacb38a15ba911aaec624d15787c3e11ada6909b1e33a2e3de928a23818d833eade4 -b4888445d86bcf4d1f6a9c2d253f277596795084c3d45a4591b307b7ae4ba177d6ce871c2cacdcf9457f9c132f244722 -87a568aa2f5471214f63932b0d48e589898e82a1f4c1055a9e73120763430537c233e9a3cb6cc178df53768e4c58c993 -81e0ec97cdf91ae66d065234492a1119198c396e2db204b7edf192c88eb4238e0a45bf7e245f3714bd864244cba0ebed -a954a3785588d4bb3cfd7cb27df45c82e6958051f916594d76cdb35bb07e4f88e2831a5cda35fe1f3c99f32a275f0668 -a9c9f4d54339d414342e87b03679baf29c219d28b6548f01891cf94d0313a64d3384658d82373d6e838d886235ac446d -8ef46cb24432b419b4cc803e60b3ef5872db8ea614dc37643e4592fbb2891cdff61f6b2a10653d9e99e6c7359ca4c590 -b23eeb458c05ffa5d58be21cd0699974694dc61a9a928fb1eb509954a3dfe7d8a71620a2d4046a448de0fb213be7e97d -ad631be8e17285f6310fb72ba913c564fc66d14460c4e8c4b0c68c572a5c2a45b088ef60eaa9d317403bacf534d57a23 -b7130f5607f236374f5e023fd43cc6dee38286ca47d504c9e75c6504957ac2bb9134fd59d8bb1010d545c56ad9c71c4b -b83cb511757d80781e26b5e9b3e0597c4cf9a976a3fb60c84efeab2b6793e46282612da45b1bb8b45af4b7f39877feb2 -a0c5f8b0027ee11cd5f86515698f689ad514cfa890ac4ead5502b5ede9d7d7ad12285f5806c9c85ab58f89bd9f188938 -aa8e8f9335c6e34bca3472b5f412ce93ab1ed5f9e51c3affdf986a5badd2ba3ca1ee69eae53ba8144927f082371b4cf3 -b2a4f775a10cd9caa776123771f08e928ecdb22dcb91efc440c69e37c6b467acfa6112c2776d4a530bfd6df3b04fd50d -a0c553d5d2a9b0525f71a5a0a539d579d937275df9220a0c3c322d6c0ac7fbd2fc55335a1a283e687856e2b30398e4b6 -8ab800ab4c810e8f6a9d42d2dae9be89841bc7328bab06b88bbe1256f720ca99c056fbe4e1378d7cf805586ae18dcc55 -b9a8766f4f4bf796e2517a8a7a05bafaa6d3ec601a85c466d33b8a7e0498fa1dd4e2a9e42161fe2362c81d4c8ee1fbf3 -8cb7d054162e9f41245b0914e7dcf6108ec11456b39b473ecf6c40e56b172fe5be4e7b0753a3685667436796a977b977 -9131d0395897f5591ad56b62ef83a3ed9e7b3951080b33ea606a15742f78a283f924373e813b877f32762dd69884658e -8d784d7f0884cce988305d314896dc6dac2d2934cf5d650904e1397f9b9dca397eb7f3accad60ab5e34cb2e494bb640b -8819629608ca1535bfc156c1e17f8fce5821d81e6661bca75a1754a5919d0404e31e65bd509387383a4111535e949f5a -820a6f46e251a1e6d92784aee18fb0d265d7e2f0a5b7e0b15180273eabdefb34f1d575e1d8e93dfc2be1114d10abf31c -8d10d0e0557beb8db344c2d8bcada724e720823fc37ee7c51b322c3269559ae932bb2ea07e50d7ada88ede788839dc8f -911a333e2f7578a0ff6533284176cf235036047a11534acb649a0043a326723662bccddaf1970b7c37b5146977277b88 -a4be2104cc5d6fce4a46de5de8d210559a6b743b6347b8d9990315bb56cbf80695ff936afadfdcc415d88b23ce6863ce -87ec5877ea8f1123371c49263dd9fedfbde41846a23e12073ef80f7afddf5a0ddab298cc02e861a90188ef1282139ecf -a3f1dae70745b8284b1353aa6902ebe3cf5580e24e02490d42b2f509ffec7e8e777fdce4f1a92d83bbb23cbaeaddac57 -8ed5a0733b42482d88da7c24e85a841ece65f6066dec060bb267a8d1f1ec165ad5f7964c2908d3fbdc2999c580eb8990 -b124a1db23f4875e0caff1c7f4b9a411564b93a9ec3ad8143bc7a70b8305d380b934c194de8201f7e3699e905a1f0115 -8af58886d4ac5578a29c2e309a68f19a62edef5285d0757c42f0ec2550c633c0e991c4cd7a60df4523cdde40c3909345 -a63fbdbde883f54667c6cacb356db1fb976bad147b790064ff25ae72be53bb6f4d74b22ca803996e0d95d216caa3fa81 -b99fc9012ad938b36246a4471d29f0a2b37b2a3be6fbfae7ec9fdccbfd14d48fdbede0d88ef3b6cc273f2488f4cab55f -acb6cd4e1672eabf530d38f50ae651db8bc4025c2557c59ac4f1a278b4741f1e2cda978e5d1337f9e5aae77c95ccb872 -8f8f6964534e4a9294c61c76206674d836d4d56970e9c14ad6835adc6b0d256402742d8a4879764569d9082ea6a750cb -969607ac6ca9bbef4fbc2fac22b12714a31f5d6103dfb998c3b6f2776283ebc7346e81a22da168af40752f28ff60d97b -b633f60cf6eb8ed588c545c04972ff156cee767edf31720c9715be3cda8c8de0290b623b22cb8fadb1690bf3665a7be6 -8235bc2e818e4d259bf2c9fcc9646ccf83b7e238044e26be417d1d0dd5283d7b38c86e8c88a5447645be191516e2993c -b503052246ea840a4083bb4a8978029af3e242e831518bcca015f2c2df504e98a48c9002b6b9fbb97e861a0a3c5b4b5c -a145ac57d7c028c3cbd2a2bfea25caa35a9b5d69cb491b13eaadc2b0d927a590decb7c4995541f8f29089a2cbde6429a -80b4c0938058fa5d03c948777f13c70f46fc025d4d6c2f2051915b476eb0c0bef902374d784df57ac368c01e1fd51c00 -92eb253e3b1770b36c4b2869a944caeed7b5c8a5b8356b25dcd4102df79fab8dd2c9d01e3253070f1206d149c43f64e2 -b7979ad6187f7921e725787b0a99050f4c98762c63fa64a467f7f110932f6d07556453a95e3a2c0162bf1c9c41424c90 -8808ae4c7cb38202c8c8bca0321e827580155197a700fa54b6a15b0f14b001327d4c9a0923168bb5afdd1b45d6a78367 -b16a4ceee9de5f49a99430e18aefc192f3c1ffdc4b41392069f690893bccdca760e6dadf4127539a763e4f60aef37dde -8ac113da7ca59ca97d6bf7d6e03f1e9570867bed27230515475f965ce9ce0b424c85810e18a584ae5a3d5c2c80c6d4a0 -847ae1b0ef5cb11be37320f3ab5e30f59d7910ba3d7cbf8265c74df25f4b8f56f1ac96cf49fd166c3b6985d1e8091e6f -aaa9b04f50ed6778e2481842cda30c7dbc7d462b40c7602a438ca9f2c1599e83fe6423f30d7789fd240d2e3166836f5d -8c18492569faa8cfa1c2a05a0edeea3f63d003e38d9ce23c4a5b31cde993a4ec88c9db83011ae15b578e0d0f6b72ddb8 -838b400217af9241755032c21a3ac4610f77f3ad76abc43f0c59a59f9bd52f2251e46fcf1552b6ee0220f4f2902e54e5 -8675f8de084c6c05644deeed1ff45090096c72c0db6bb2ceaf1c0d070bd10ff1e83b2dcd89b6f99bf132d3e131ef6d0f -89611bc63c83d56131bc2a8653278b234b4635aa7a05033d71a8377a5d188ffed7506a50a5c37a33d199a42b9e55fea4 -90c290c17f1687a87023fadf74b1e10ad0c0414cf08629b2a313347f0f6913bbe511e5d18d1c3264b47f65dee7887d4a -a590bcb6391506035466dea82617f11dd9417c9f379d32b4c3bbf723840e1a3124d2327deb28849aacac278470d7ae20 -97c55f459ebdf94ade7bc3bb18b329bbe2bccea345f0b4dc38cfff2839749b8f9365e8a1cf31722649c165e265344c35 -8159d02fd03c1d0b3c928658b3df1a27a57699ed8a573e0c3a179e97f50b6c1a6467b7055e42f9f9c6c858459eed517f -84d4f009c052f3bf76b2b972b3d8f7a4b2d78605a566478670c33016aab06828a1737a36d3c9173583e7bed0aee84fcc -b99d7558944ac2d61f5a800c24ee47fca719e69f7284956be94596623cf434a214c042aa46d54019de3556540ea53236 -8d1efbad46f69b80efc5776d8afe95dc0a8182d57318b9f2d6fb5b7d5c48e7181e6bd61a8446a553c58f7899ea7a7c78 -84a9cf6a9d64cee7e7d8f0b678d3606c9080ab3ecf62fe0d6f994a681de68b30534ded61db1445a257b2c5427e97b36c -b6a5d2c55a23841a4263b10cdf784be6fdfe1b25350a4af510ca294949716711363ca19f9c44ab1c347aa3fcd60f0573 -b1b5b6dbe6945db539fe7e2de07d222c88d7b91753118593ad9890c55c4c3d83b4194f886ea7f66ccbb348f5a23a2a22 -a8a58169edd3e58f87fe8529f5cf7da7679807467ec707ab96faedf75085185a78f2ef912d9180a5e820adfad32ae4ae -874c1f416f866756ae3e93360342848afdea0048a575f977fb1f8a57325e50da122d3e9f423e308f0acb1b28fd47a6eb -95cbe8b47ec42a5c72ef7b1f91e3de0b1f648ae8069416c48d5529c9cffb104ba4dcbe87cc06e4e798a1b23bf1595f9a -a1b6e9c5d63ab1262559727872d1140b74a4f01c12366ed2d401c64007faf7917ec591b631c6bb4dd44b39aa43c7f965 -89e6f4a05679c95d45b54e760056378a5eeacc72624eec8b5f19aecf8ef0d8acfb2d807d3b88c6b1206827203f219905 -b7f7b30cdea6377d5f16d200b987e3b4a6f28387faa701dc579cf7b3c6887d74ca43609c5bc36414a6dfd0317ec75448 -83474b58135f3e2c5e8355e31ae44a77721db71cb2919c3f3403f44903622d4116e812ea9ee9ca073938dee780f4aa22 -a3e4cbbec770630c5e2f3b67059a55b1217435bb70ba5b5010244e241ad6a3e6b8d9261d8a0765c4b42bf795fa4e96d4 -87d3ebf0fc03ad67299f3b9cf9c9ff0890b1d0d2d1a0ca2a62147444922d207663329e49898d79bd8e09ee48a1560fa5 -a1d33282cb17c7a4c5cfeab4dee8875d324aca8d0513567c4e5eae180d1e8ac98b2ef16b31afa7c3f2ec25cf3e8bbd11 -b10b6cfe3ba563b41ae0d66813105948416ce0848ba3b34b8e96547e8842086b632a52904e56eb61d93e0cbdd402d305 -84c4feb35c8d3583ca17245e6f7e73cb488aed515c2ef671b09a04d8eebe6b7579e5b1fc8634fcd4c3bf8100d2cb98de -918d8fa2f52a9b3957ba412c24cc579dbd1f0b0834b909a6ac0da5dc602ceec17046f61b3d4a2658f724757ca8041fb9 -87296e4775fb887bb00dd3265f202f31a8fdeae5c6ad8ec63508476cc57d330827d0d241c68091bb724a2ba921694a7a -a8908019d96c506b314c84b22c475157daa36016a9b94feecc4571e869918e4e5a9e39fb7c9ae0f73f9f868bdc50e2af -abedfabf75a93e7521eb339ce2e22e0e887f94ea28d3adfa42d1e0523686c6cbee4c96b2bbab3b8393feda1099b24d4b -a464d6bb17386cb431520cdbb3818beb3951b0255d72f58c300fd780aea1fe4dbce5532f5321e80e16db2f9b9bfe8a1b -8cb8fe0df930e1e19446ff0183c7034e35e33442da346df8a802160120a5f4d8abac236763114a650dcb1a1d38bafb37 -975c47ea6412bfa97db9cf12c2b4c07ebbda436716aaa7253b2343138b36de6c897386833849f539bad7659d9319abce -8cf94457a5a708cc91bca9615e599b0c0afa92a7f2d9c83704e05a3dba56a90c4eedebb6d2d25b3080786e16c27194c6 -950d02a5e41c8f704184c7c59715fdf3b48d86b53b04dff7c21738c7c38c9f4f75349ac1e70ca18a0744b01fb8b13504 -9458faad893db4458b330ee283d6a90f68346332c99cbe8e121c890bfca908f0c91168072aa221c3c078d7fd5e4b44d9 -b0262948c113fa2a122dc6208250b62ff35b12d3aa1e5735e95198424cf16a4829e9211c9edad83989c537572c5b41ad -abed7125de7dc52b0b42cd34fb350d4c6c45016319ab776b52289bc8c2b341a15d48165c0eb09511a1a5a5ed7ff39e4e -b4c352b4a127afb5b0833d210dc2c216bea666e7c5a940a3372988c0b02dfd236e4ac7c124664bcbf353132d6f061f3f -a334c5919909dadca50f3124de06400df660082b527f1f32b386b9216d021d38685f1839bafbaa7950eea6c1cb14bf53 -a52f4534e9de29f91039af3fce055f2f6726fd9b10595a43ae41f7b466cc4ea6314487081e867ff4b5e35cd622fb428a -a68c6ba9673896bf49ed145935773fa50d95ec0103f97a6f1ed698d93b4dd78111325f797e47fe153fb3852f4590ee89 -a5c456d516a557aaca80441705cda63d081181199097e83b22e9cf7b9947a8bb78cc476642f04a5ca3b13032319591eb -8a359a3dacc7b45da2b826dc27700178553f6a52e9705451f24c6d6026a0c597328acaa10b3b5a883b6353eee4eca594 -807217b435d73c1374bca84d2d3e069db756176220a01607b81438a70f69232b82099c676fff361dd909271be8d5d555 -965d0f46eb0804f19dd700d8721349287335c70e992efdfe89058ec424b87acccb3fbb18d84b727ff5ccb6f6783e9065 -aeb5f2a0bff1e6115bc2fa73093019f8c679efec91d03398e24651be187265f7ca80369a1dfa61e8701385dc0ce9a0a8 -85732f872228dd5d691f1507ba00cc94e054baa59a764565401e9e9b3287d2d0cd0f2af290b28b5e3c80da9cf23ded63 -8e9a315c5b40e7cdb866b8a7e6ec01eeb27a52a76a88d5956ac3e66fd9ade3ec954acce816227b57fea6ae9244f1303c -80436457879607efd008f959cfd7507fbe22e417c701f59b5a36e878a04e51e87eb38c48c0992333656b24a4e671bfb3 -a012f6d166cd1d98098544bcddfbdfa956ce60011694b640b012da3a0a22ac8a054a9e205aa9fae4df764ad60c65a6f2 -b8225afd6e4d45520678e243d97bf48f87c2b8d2cbc24b43f94bf6e7f60b7768d4c3b30d28a490e7c8a1c3a104ac8317 -8437fc2ab6d90716419f544a1d16c607173fae5bdc242d8224d7714c115cc54f2246d1062ecd77d5a9cd3ebed3a8adc9 -b113c6c63125930882c18f548c1baa69a26f9f3dcfbedf5be41aecd61adb896ff9622ce038f0ed27a5ac602b6020740e -b893aee6291a3962fe17ea41322de7edbea6ebd51d2c564fe23ba8a4cf4b6270b7ac72c87f2cbca209be1ba607ecab75 -92e6a7494114cb4dcf2b86ba61f57f6db7e4d52895ba6c896433139eb2ec9c9604f3e9100c690e1949e32f5b7e29de93 -881a323e772a639553cbb401e2b6a255094412addcece2c99ec9e1346aea2f4e9eb247552435eab74799ee4c7a927b6b -8d5d3ec378922311374fcb998fe5a42176448b629a6475abe494fa56abd5faa5835af37624c138beeba649f7803a4855 -b1a082ba449e93cc15fb4dc5114351437599fbd4d28eb6b4746d1bd242172518f94b2ca8b1f76c08d9f6ef260d9cfbb2 -8fd2b7728a3c61cd8e0c607cf40e935dc45d52d040ef1259f62e3eeb30bd3a6cd030fcf407fa0b21423b23a795a02b90 -9214aee5787f4666c3e2aff70949dd679d4203a2c3e7b6f88c548b80a3e52d7763f2bc2b7df714eef053f60eda4db331 -b15df25b62c6f4ac9edc414ecacfe8eec055bb07a1220e327bf35c5e452da7620df03416a449197bfc8d948445c5f734 -b41ff69731e7f4308fa18ad286d3ecd7be21afef3d32f5133a0bae877a347f8773c6e9d9b3b850d054236a6f186e6913 -8d9d13d1b7d9df41cf5d30dd62b9d1d2c4933d62b6cf8d1830bd1ae4dd5fa3de36bfa1fc4d57681ae13996f85ad2551e -8011a7fd7534b248db40050edd9752c960ffd89b0300a91520759ad51da1698454affb4aa8907946605a02ca09a7f340 -9159054fbc10164fa19f68736c2a683d374681e6e9d5e56f7496aeebb0969b8eb1a91e377b3a2928879147a7fb60b3e2 -afd4980aa4661fe05bf9040f6551d980af562da69ec5072104d8ea34a8ebd28baa0b70e0fe3c11f631005693fb99213e -a92879cac7940c6d363ab3d0ba7f7f24bad0b16142c78969a737c27ebb09a62071540bec1822ae6224d943d02804da50 -89338d27ba29343279dd83827ae17a53e7d634bc77bbd848f3b6a352fe92f6021dc1c81ea6693b3cbcb1f24188edc757 -a2490a856c273b6eb5242672f817e60a157a1dfdf25b1d32e0f4836a9c2371fae72c93b94d78267b3cb142b4f4d7148b -8efcf5d06107554f896084e32e8dc95c49fc5da3f8c4be4ef6f2ed89914233eaacfea886040bfff14759ce28a1eeaf3b -a3516280b169a6832e997a4a45daf46aeaec1d8953387f493cacc2835a5791d4dcb24a0c0ad5de79988d76f843d79994 -95eb7531a46bdc51acacf7fd9e7210bf6d5ca59b0efe58f79422394447adcca6f4ea991600e8558da8e19e029701c5d7 -b1fcb4177f16187c76b421c29f715f1551ff365bdce9fe17b74425f76dd90fb4ebe828ffff3d20f75ac620abeb9381a8 -886246027be4062258b232926cc82b6a51591138561ddd0173ec6e4b7ff750e15d9ba175f569c266148c653ac905d498 -952c089dd09dbe531f2fd4137c971622fc1d85a78ff07de634f63853f62110dbae3646564addef8f2a070f5a16396ef4 -812ed85f4559fb28732d17c8fd7c6b09a70da454a2318a0276949df0a5dd2714b14096656b7b5b6398f54c74eb9ca49a -9340db62e43e43144e1afb1da748e81a1b00f7b0600e8eed117e92ffcf801b9d89b494ffb003b4ebd5bb4e0eb96c9374 -9287c0745b4bbe24b56784ac28bec43ed2abb6bb15bf11ba2b18b01801da7d162aef88e967d2f10fb9f52f6645d7702e -9615bc232ba6053fe86c6328eead899bd62c4f975273f72595407fe36ea43e30eeac7524bc17dbe78b4692d42ae81c04 -a387899b521b1a89e860756bd0986b302f3c06271ece653425d6c697e0b330a3ed7789efe0e5a1b32e60257a12fa0147 -b4c99909fbb92b1f39e9b2fabe05abf58af834b6c15ab0f62304ccfc5047f187a3ce35388ef293d2857b777f9938bd55 -97dcb90d2dd9291366b557936931550d665cd05bb1b19a7a53a31c2a39d264789477a47ae14f6bdeb171e78941a9d9e2 -81417b4a3e61ab9b48e0ff1afa8b523bf63ef95a6d6980092408b61f4293fb202395b10a5d12dcc54961370c134d5b0d -9135da893ef0a9d45a719207659cad4a0590218303d0e02016bcc5d14f54de5fb8de642efc7826b3b3212f714114600e -a00d0f8e2ea06b13f5a75a6dbd1f2ba7ce3f3bb3e62cd3b53f8b6ab39431fd2ce156a1aa4a1988613d4a2b6d91550147 -a3f8f17dfdda07166a7e5503366dbef45ea6b6eaa1dbe02b8051dff58453f1ac24762c82f6db6de4370869f9b25d6d51 -847c2b79076f9284d9a866a72f74f62fd73cccbe2df18c0fe34a35416d4825d364e24f95f728bc0e6a5215b08b6f0d2a -9816284cd6b8b35e1f5409d3a5899af5f4524a4826470fd164fcfe863994ee3aac77cbc16831f0866b9f0ae561903d61 -8ab1f9feaa8ba2e1691acbfbd5460a4bab531344ce4accbabdbe5ba8cedb5d5fc0967def4365d755ecb62d83b7ffa4bc -b0cb477aee9bd113959ff7b7675f81ef251b76cccbb67cf68ba571fc08561736e32c18aae93fc8d1912e7eb2fc0ecca2 -8cc41304caf0357d13a25ecf66336bece67d5d319bc5a50328a96199d7ca4fad05dbd7b5edda58be73141bb06e269c8e -a7b4d91a884abad5337925c34d7fd5f2aea5a09ff3c027cac98c646b5058f7fe2cbf47208930509e2a4eef1468f64c89 -97d942e97efe46594e8fc86828ad3ed1c9133a8067f9b11bc0f4ee3815affbc0c7c46a91c40f989d50f1d8df96982ada -95a7d369f3ce7f7ad7ddf85bc994667ca25a0c2f11b9312d06654599410d5325ca3ea74f33f21b5aeedfb582a9e40c62 -b0a05b564a754b46fc7aa4f5289f02bd9f19708b5ecb9db5c36bb7505c8b56ec22b53fedefc1df289c0f636c97e8ec47 -ab6e2801ea8bc600f9159d05a3b39e8b0973fb9c2696b3f2685424757a6953a9f8ddf5e29c97399c4821b8d7fd9f1bc4 -a6fbbad2ad3ce8e4f9b939080e9e7049eba9f76b8ffb57f7cac2aa46793a064743239ce287e156d49cf4936517632290 -a606632b62194aec737403ce5a9b6316178c1d27baffdac83981baab63e75d51caa414ea92465ef37d6d687b4fd90141 -a5a99b7bf8f4c109af04c31af9b5f3148370319c8483796cbb5ef555ee1d4858b2c1acb82ab5e26180254399fd7a0625 -ab2b00f64355ad294436339636e7764403b821d4dd4fd74a6bbdc2aae450f14d7dbe8423336e793a393f4580f1b9e35b -a6c98a6ad7f36f16633fc216c12ca34e596b292524753ca1067eb75ab52facd28ed3a7c55e0a0cf1d3c9115a2a0d6524 -84acda31e618eaf0424a37cb3c386585a3870b2c24020550a16134ad8802d427c918e2854c98e5def58a2363a8e1a314 -9911ec15af39af1a18003ae120da8d909ad4bd43ff03078091d54de71de70e19786b2aaebaa5d55d9b2877004da2c271 -8cb5a148f065e36b67a219bdb347a625a7a4be8f20dfb1cffbb38fd4d843c2b1b1886c1f015793bbcb02af04ed91b170 -815d9adf22a36533fd4a3efae3c4326213ba2aad48724ef958cdd6f0dd5059b519e12d91ed5d92f1418a07b62b108bfe -ae5c244f309467ada13e2fcd8942886f563bd996a5c65aee73a364c2ecab49be3ba6bc8a387f3baad44776f4f1042eb8 -a47d93b35f57ad890239a6f2f69ef8760268adbe614d5877802db4b6cc75cc093baf101f75be0f7b4d71ad8724dbb9f7 -a0d089701b965df9fea938e337016ab20e0e567e736e6652955f1a93760b4a9f128be5a594e71df8e7db47c3f88c2fa7 -a9d9a7170a860e2860f785edbe18ad909ecfa489cd3a2abc580869c7eb8e9a2db93c1c473a5f1474ec0d51dfdedf95e1 -b665abdd084abd292548c336e3e6fa1c5ed1a53d2e61a10ad6a4c66487d8a9e101632ff468b012506135907f0896156e -a10ccb363b26beb9622e1d91021d08a3bf02bec96a059ead01961ad51610992ef03558c5f77e074442836c9d2ff44e0a -96d6476066264eb3090ba3544dbfec7c8a0d90985a1697985db0d04773f6d37d5899a9d4fb5a3207c320ca78c37492e6 -b4290ff9213e2ecd30d303b2b4ecc66c2614b8df246e70ece4e55bea9a1f5a0bae9df6dcbd8efdcf8c4b0f2f4cb44d48 -8ef10b2e53e6770a36b6403678ffb86f5d85e3e87bb1b3ce9f1f0cb0cf32f1fe991c565595389ad83d8c8d54a47dcc82 -91f950ef60014e3dd28f7661e6275ab6f085c803988b7d6dbb2cab25f10b0372e271267245761e1af97da6f48c230205 -97c626e7114396daa337ada4f08da5129464d8e8c68a407c8798949817337578733fbcabf454a22b57926485c28d9d62 -b596984b609a9858b1adefd15a546d4b8a417c8b54504efadffcc805caf8935b9c7f55d9e6b34592241195f513453572 -a3fdd36f3eefffe0cd2a9e6cbfc4eb9c3a499eec25230df8786b23f5eb71efddde062940ac23d5b2885081da48d3c1c1 -aa1822db9ee136d0a51910f0a59bf0d2af6819e4ec0b859b790e01bb08c1def87e9613b355525d4ab7d088b520a6a3dc -a9089edfa96fdb7204a68c4ffcb7e0a875106886a0c589dbc57a6709e7822747affb07035b99d056baf11d0852720489 -85664ab9d32ab0cc2d2e61901b2682f88a7259c2da4ae6263b917ae8afc232614b4ee56539a868a24940eab74142198f -b90e06a1a117659b52b364359e2265daaa8981954e9a9c37e3256cbabf133dd4900974a895dde6ec6b394fb36b5bc1c8 -b414aefaa4833283dce85add23d1cfd776567735f2ba9018cd791d652bab55bb0cc0cb38b88fe47e3b4b877e63edbd75 -ae579eae9c0b09c906cc2824eeebe5b4ea031547055c8ad635194f3e864c7a184dc21a3eca9c43c01d9a2f272cb2ce81 -a7b1d13997c283c13f770d5203cb09b5d3ca7d45324ec89c069928e1ed1a17c57510e0ebaaf54a21d27b0f9f057bccec -b15d4555520565b76ec21d87e094ece2e04c7c4bbbf560264da37604f1a484ecc3ce8143b04759fe716411293876d0a6 -810bb0773c06caae8cc06ffc92303d51eadca1e1b0acd57ed23f5feda70378e180619f68b8db98e61d792568f49a8316 -87dee32807e2e5f2c884822b31098e5be2a4d950ae728e3281a39e661937c4b7e9fc025b50f437f01d69e5c33dd751a0 -b46810bd73d077a6b73757d22b5939c02a3632e81287073b00ebee30cdd402e89c318e0b03d01fa331193842f3a1ae53 -95a136a7bdca77f764d2c2d4795a8fc9e5b9097d73bb3956b7a45b42185a99c949db8ac5627ca263206cab9cbecbc31c -967eee3c3afc138a482bd120050dcb9b45a9fe258e5e4b678b1d67b4691f4c5d89cd260210fb50f9cf2d3e2e2802968b -b2d59a9ed0448b88f8eb26d8017a129ebaf27f11e0a031130266796e5f777bce93cf2c7e0fba8f8ccc997315db9aeb9a -aec708d3093b12caf29efbd8afe3ace1de24496cee72270223aeaefe4f0ba3a7acea7f2f5f85c1f274aaf5188616133f -8563ec52704c1c7ab515451a8f89f87201d30a12c95812ac95fde2af033e5019615a07f28b540a92781ed35786b5614b -b1c8f819a4ceb17d35ab997c14f81ae2af9d4510caffc61d4a19e9129e0bf7264482a10f329054908f99909999b6f538 -8a65668637ba24358800076d8edc90979d6e614e6a683dff7859ce7d686014e6de85298f523ab060c9a9a4c4b8862cfd -b4df02dd6f4d3908142654a42af60fef034379b1526c12be66afcfc4f1177991811646495aa85702f3461060732cce80 -8991bef253f0bb9b86e68e81f78116c51097004b0309e199025e45ac7ea55f8f6b2bdc58886899d275424ebd405ffac0 -a74f1048548fb41e57f679d632280fd2e4cc6ab88c81675c59fe143b74dc7ccf050db53dac5611ed6b45b6a0b1b7f3dc -92011c668bff7ea995a71e4774e3fb5d521ee2552bdc33d9a65afd9677572c2a303a940751ffea470af898b01b9285ad -881a0e6042771492633b46b6101f96a48a93aa3860533dc207cdc90783fbe52b4a9ade1eea9117cea004bae802cd3fbd -b3e578bfd77a3a13368ecf8139b69f729cc720aab25853cc9e2f505c2e03e75cb779d685698af8cc4aba8d1c17f5ec29 -a025b6e8dbeb68e7ac4a595b34089fed0d24eb29a7be235048205e35a97634d6015ab24c21a017b5012c3175677fd0bb -b751acd86ead936ed0f22d770872cdb5aeca3b1ec75a5a1e65748b665f8d1c859b5620d761d5f0a2a86331188e82b2a7 -a05faf0bdb81caada6c662ed2fd145eff5db5c423258d6609bfd4c467edf3ddba6480ab95ac9f4dbc932f4887b070c82 -8fd1faccaa7cf1d59be37bad69b7a99b7641cbfe930d778e0f712ae1fe9e78d53f37d7d5d3aafde48452eaeb65d980b8 -86042bc710953f0042940625d8b69ef57c615f9631fc49aae169ca595446e9d55e149c92994d4bce7b544877d7b6f22a -b396047f716c5fa8ca9234c7026f1772d83f41be03410b4a32a376e5a038d252b8f36cb813bc3684f1b50326994c31cb -a2eece2d76db005f5d95f5f480bb3353ec67a9c27896fe54a2cd5cc7f802507d8d518596601bb3d2798842b96fc03df2 -b738c1264d094f7b7edd27b0ddd8e29716c73bcf7b450ad7715fd21e1052998675873ccbec486fe45a8f72d9b006f239 -826c4c5fea1596e353f6c15d91a9bbacd9ea592aba4d22e735263062eac44f073e5defb794f8ae4afb7d4dbcd1ace959 -a8f1d170f63ae3b05ca9996347a1b3987136e7bafd02774698829986d48da3d421d269d31743bfd3e7917c5ace7ce729 -ae6871a8278f24d816657889ccdef509df0fb941fe6c5839cbfb704e81b942ea2a324fe0ac9881b385bc97410fd94b0f -8aa6bb564b6a0354be89c4ac10309f941162fb3a546259c5d789d4608cc628f69ecf814b59bb8bce364162f7552e628e -8ed85481cdc58fc540384213dd1b86f80af8908683d7d2c63ef5f8c4ac2e90f0e5f4e07b1b841eaecaab1f7e091423bf -88741d9c9d875e2c1ee5b95bafa4d8a22d72a728260297d048e4f0cd1c5f1eaa94fc233be3fa15a69163f218d62ab17a -8a99655974ad5c0f27b49d88a9c52a5375e16b9ac4f22b1e1bde53ce0a21589022c0ea926a4c2d7c432a53656ccffa37 -8e2628878858764824471fd613cf40d1bbb3fa84ed081a762da0d6d491d54688723273d87a587ed1d3067976ab74fe1b -8f1a6162bd6cbd2353265bb348311073bcfca5a86f41cd0c63ab91b14aabbeffade5ae8a94f8e91faa386223fc2bf849 -aabe8cd92f0193d12b032a9bab4bf4f02ebc0b24d1ac09f8ca8906621d6c7d4bb436b2dd879a1a1cca2b44ebb5642995 -91cd27988ae8100d48ace10ac9cac4cf1cc8539bb492521a8a6489f8575a737f2a1d37fcdbe88dd651179145a59af920 -8baefbda554bc0a0b425f2e132c7de061fdd120ebd452ecff0d78cc5bc5b15401997231727a37e9bc4abf1a553a4cbd8 -971b12e25b989511477c04602f48f584485a0a0773b46643190263c0288c2434969bdddb1e55dc1f5b1b028c1c53eb32 -a0e47f42444a16e51323af6f519c0dd2271a85746882818d02373ba33c2e2f7bd6a1c321497377e4781f72427fa34224 -b52bc02de867d7b20cd247cbf496e03d940be2d7ca5755145e9a0168889db345fa9ab17c41635ab275a459fc9d02ff16 -b01db7077e9f01e675c62f5095400cdc68a059e1a5005027033ac535a0505f45f89faae4fb9831f7ff9cbad3b55db02d -81ae065f1d55f4643a2ee120bc1245b9730455ad9e5402df8d6fcbb1bec71e40f1bfe7b8e67f96fff76d1478cd3973ca -a1be3723920044be80f398279e2f8432aaed45a36cc4fc71c87f5dbfd52225379e94600793f40aedaac2391caa57d155 -b682f74fe46d4b647196b7c14804dc0b35e36cdff59671d7164ece874107964ff9f76c29b23c190796a9a3aa2df822fb -b8152e458970ab53f6b5bf6101008c5c31d2f58993474eed6bccda074555f7ad2351810d78676b62612e7eba2d86247d -9132a8fab2010360ca80adcc08b3a01658dc8ba8f60bbc45e1144c1219f69b985436c36c65cd7910a8aebd91ea1d3d38 -805cd373a0919de801b6bb7a6ebf55530037fa41a1993c159e90213c492165c42b5642dda5fe7283ac4e3ade6e63a155 -91f20d77fb7a8276174989faed41fa6da841d35b074c4a756c2b4730a7efb9b124ea6c7d5eb150a8b1126636cdb2ff0b -8cda3ffbd0ab6846dbee6cb8c0360842837a65f83b6ba17085161a7371a4466172354e494a8614cf2f1f4726d0a7262b -adc603e61dc36ee605dd7f2761ed568bf91b9dd3d40903eb7d77b11d10e4f762694fbbbcece72a7ec26976054139c768 -a6accdb3df5029f19273a39bc30cb622f87522ca5a63372dfe61d993dd783ca5e918218b5c519d25e535d8b8238339a2 -a188897269053f2494bd0de8cf098e41010fdd01f5a49d7ddd7b294ea748f1139e0d92fa7841dda9f8dc923ed6f02615 -b26ad5dde632259293d91109fad4f742ab74de91f68ed2416ff53c060d1ea4377a875b2ce960cb7962c37a5fd47e85c8 -82cfa86a17b27f375172d66b389df727734480a224b91585fb4782401d6c49d4dd347b8d1e8df6b9c0c1d2f8ae658de6 -82911748e1471bf5d7fe3ff111ac06dcaf5b8a43c76f6583ca491e0aa845b61cdd443613c5728863c163952d86bfd482 -b7b0d4ff87df02b5481183066f6ac0d1636718fbddc19889e92a71a168fbe338ffe780a792ec5642aaa4024d0964db69 -8ec21f08594ad38e9ac365e5246aa5c2c8e34ae66382ac483b47771c33390ccace4d906695b1ac0f1c9204c46576946b -b9617d746596b26b84f2709a03b64fe77e9a10d0c85535d92d28dae9de3bbf6455a247f775dd9f67061792cb924e3925 -abb2ff3f16309fcfe0a3b1bc928ca5cf618706cad3645b029bd54e5305682754e6ca47e364ff21b1750f45041eeeb358 -867abcb8029b35a54552c57346024ae7eea38e9ae4bdbd68bb3c1de3935126880f237d9aa95d6644dba8ddce67e343e7 -86eb4283147a9e595d639f29a967310acbed9ff09d9043868fd18f0b735d8619eb4ee0250764f35a51e00b58543bcc66 -af1779d2115ca7021533bcf55a100b4d3ff4e45f8ce6a6d98df22881526a429d97818fa1867ede09918a438957a03534 -b10b36d0b69b0dbecb6f7efb6c612b0462c346079109970a26541a21aa2b5b81c1e121ed0d5c81af00ea8eb709a83dfd -911f81ed75fed55f1fabc5f86f9f38490e006820e5380963a739ebc0f87a1dd3b7da8c69dff1e580c5ad2246bc08e2cc -8379449499da9159cac2c09c61777955e61c63378d051bd28b59c78409ee5d09c43e7a6c246572bf34233a314511bbdf -84b48ec8895049bd03dc3256bd0d63f6e9abb178221f7d47703b447c709fc5fda47b19a3439f30f10d2670194f390915 -ab3bb5afe824d8aa20f97ead4c40aaa93350f33d980b5783cf56c8552a4298c989b7b188d023711a2eb79631f3a8c317 -ababba2722186a3b2272feebaf2ff46c93883b7265a6a4fba039d5fc0e7fe81b7d4dc2cef7738406f156f693ba3a55eb -ad50302a51eeebe63085d3c1705eee9142bf8717d07c5d87e0e4ef5a12207dd5432994c72b9493f9ceb558a20929c9f6 -8bcc3d83a6b8998e1a1066347c647ab122eac80c9c505d5cfbc370f466349671d8da4d500201226c15c1f62162efc62f -aad6946b5d5df34ee6f7422fbefc6de33dcf4461868ed7ee7f47fe9b8eb2f7a89759c73b7a029d422b02afd0f550e722 -b0fe1d9a30759d83084b4c567b586e5a8f5a080bfa93b4a3feba59edaec33b6a2ebc98ccd82aa9d8cf0bd254d5f03baa -b993c4c2b77fcfbdb213bfd5f8d655d1d41a52583de63b432e2732df2f9d88c4c6779f314848417c06a089fcb970c0f2 -842ea3aa645e5852695405b6ff2184e55bdfcf50be2319761e717b7b52d904ec47ad3abf986850c643003442e302ef30 -8093b0ef1f6c84a8253d086a6fda6be8376f925f416a9d1f44ea72489f60fbd8b53cee616cc5ece43e2a202653c0640d -8c75f10b6aa848d84baa4120e75d3edb7f8471473851326cbd9ed7b29b22c5403028f49430bfe4320c3f4227827e667c -b4fde4f20ab98f76f55afd533f1b09ee4ffbac9486399714514fd694fecd0ad1fdafe13b2b80721829c7a59e4c951a76 -843b2ed867cd8edc2eee84497dbd49f3dc481e7ece69310d06225325ef032a4e72907e16e7b6215ca775f88983d55e5c -9881e5caa9706e4d7ba6ab81525090e29ecdf1808931f3f2b11ff9ff5cc97f83f3e14fcf18abf18159c3fcf4cbc27042 -b6c4acc868c05c955eb36a24652314be37004bfc14283600523729d466c56018c99a45a41ec0389449fcc3f8aa745638 -b6820864d07715dcf4a9ece336464aeef9ce381ca7dba25acd48f60af056a3405c22792cdc57c641e782896c0ea05b25 -a1bb482e35f71772486675cb4ee0fa5709b757083d18a29d4f4344e6ce901b2edb2889b7eac92c498b90c7d3844c450c -8cd8d8d47de859d0c68bdbe1834a1c9a34e92636600fc592a08f96d66426c5f41f388138f42c9b8ad72c596f4bf85496 -801cc0631310656864b25d980c9e99a98fec2316414819afeaf182d3e7ff93b32a989e2ce63f5ea9301745080854188c -8fcc6b2b656f7960d9ad48c091c1ea71b6f0f61553f7695049c770afd509ee58ca8e1dcb403aa2c5acfbbba58676bd44 -b997b9a6b994e3eb2de8723ec485d8181fd674de19ac9c2f50704785d9f5a28fe3ad194eb052b5ce122ab5e6e6968a70 -a909e7002b82b371952ca9d0832f531db15882180e97c12c56da649fd65334904fbbc3f097b6a954469221d181e718bf -acfc712e1a61504814e37b3aad0d7a5cafce5901ffa43c13bc5f70507800ff03ed261367ccd09db7429cc5dbb892a7e6 -8d634a07b69ad87e41d941aca08550ae9cd72fe31f3075511d030c364fd6578a36f3f0f3785d19305a1e772486ca097a -9746ce2d890248002c1bfb755e06f4f4570cefa7636e10319bf491c654b83608766e95fe9c77f1a6a630f5add77b71f8 -a9dfa56bf82297f709f1b4bdbe4bc194bf22c0424815bafa6c1a536f2d15f35bfdebe0867ff20781a49274075622861e -a723af2702c6b473caa4a64142464f201bd1e2f765454fb0236082fe3ad77f22b4353e5981e6bc37e974c7ef797f875e -a42a1a0c50befa6864fa35c25a17f5309684c53257376f8111fe96c84a5e09376fad9c8545e1946f360e16e1e4c941e3 -84231f6bc3038320dc13f3ac014977326dd13e5b2ba112c084d366b5255729b2abe665aca8a41d7aa6645412765887ca -a64e21d651bed6dce8dcfcb4caa60791b9345cd7b6a100f5bb78f7423fba5ea0d0cb3668f3415c27af29ac35e5dab0ae -b8eeb2128ea14d81fec5b1103d8511a3dfdab925212363c75c5cc01515fd94be8db2335bb84e221654380e58e9f2be67 -a92e9cb287981b33a5e697eb1e757bd44f45efdda1759122fb27dd4bd4ce3694f1b6b2082ce4e6e3919d9d7a0b7c8a12 -88f22b83fd9dad63e800b0bef709759f380c6dd9af7058100413e7b09c7517eba258d6367e0cb1a41b7762b86b2ef137 -8353d45a2096fb4bde82ca22381bd2ed93fb58b236b16e68bb37df3024672067c4378d7f04a4da4d116e7d57a2211f7d -9076205bf231de091fcba7f5a4fe1d4a359f07236efa39f5715f206e5cb7eb3d9adb56af8181f63a9d3e965dc909556c -93ab7f56e8d37b47d3a8cbd222f2dab4bdbf94a1152302752f0a731294f4dc214fdba17977f11aaff2eea9517fdd5789 -96d9883ee108c88342befc358325356dfe5d72c521d71e4b3a58d6773ea3d1a1de1a20572aa96ca0e8483eba62466504 -950e0d61ce4e76fe0cdc3d59c5bf23d8e1cfa9d6ee13b9fe41e6ddc0fd52081bb16bcdd973d319c20709ec517fe15626 -88809c1e272b552d46137165e5396917d107547b65059fa646b742489e8892acebeccbb3eb8f2d676e3836c985cb1756 -945f13ff081b74403a19dbb04173780f04766f7624ac6b77f46464df5f4f3b547c459f41fb1842164d8f1c126ad6be65 -abfbadc599bcab1c2b7cf1fc5aac7798d9f617d6afa0469ee23230c0d004fcd3de0ea645feddc74e676ecab1fcdcd8a2 -83ea1571b064d05e1b7f4527b20ada121024a4b2dd8f7d551945488ccfddd671ed2ed3895578afcb3cf958f9a2c75c29 -8fa75050bda001409f2bc0a275d8dc0fefaa47b3a0ae132758bd711eaed0851d6bf3e4b7f355377a93fb8eb02b3ac6f5 -b2fff49083bb30e2661e2d8978149e0d0588dc972222f46d5d120d01dc5c9978830c442827c8fa295f6b8e6d8c786198 -a352c2dbe4f18b311bf0690d77fbc9439a1b8088c806a9d89071b3ea04ff387325cdc04a091d2bde5fd087bcd0f4f482 -948ea89408826ded81549cce823dfd7605ffc2279ca7d0964b1ab3d5f35f4b174e81575291edeb9eaa4baad3610ba3a4 -998073b618140b04ec394ffe4af02df044d923a5cbc8f06f26c9eb4ece17abedd4f72e10c9738bd16863327c0f6ee20b -b3bfdda0d6960af897ab508bd9312d9c166157f78b45157b46fd2e38ab2e430e8a19335d8a611366cf74642bda77bc78 -b8dae3e2ec5eb97ce3b5e9be719bb747e6e8f28dfb1a6b7bf5063822b502a5422cd586bacd87ef83c0af081ea4d30a57 -859713ddf0ae843ba690fd8177ce6c08e2fe5fc1c8893d829d39a199e04758719bd3046034926de40973a992ecbfeda2 -866f150d4b6a015b03ce8ad93a70644b55ca1818a0f50d24795698c62f3abe59d3b8abe4c11ffcbef20127d3b7afb970 -9145367ce9e2a5a6140db58cb097767b5a6e19eb36d1c03acadef612af95eba80048f2b02c6fb46eaf38c75288e3e4eb -8c298aee778f4af13329975754e9b428e127680f26be139307d43268dc63892ac98284d78ced0ecd384301e26d5b63e2 -b4c2cc9256fc33ed09531abd7c3e34f8f24830a8a2cf2d684cdde46155f43ff2715c94e7dfc7377765ec0cdefb21cd2d -b9193113b81bba4ebfe40e97be436515254bc67a94939220e5e69a197765bba40dac3369e5cde115d1bbb65e1c826038 -8474d72b7cb52768c484ff92d014d7733003b511c0c915649f65dfceced47ecd933ce876eae254cdf2f6357ea865580e -808e9a59f947b2b39af51deab4c164878e02d95773dddf1123091e27de87cfffc07aecd7c9cf3e08c0b9f525bd87fff8 -a8e0049eec8eb70c12446596ba5c8a29823704be3753312c34cb271000b6c154b1022812dd02d1352cd263b655437d6d -ab7894a75e40d888a4d0539582cfd6b458da009a5017e561c14d312335a75745ce134b57466fd30c250ca07e0529c8a4 -b30c5c0abfd35ded7a3da8f9c95e3e1c320857be1af317f6ff5e35101d3f31de3735ff8741f6460ae1e63cee543081fc -b15557ec268b4eba9628ccec0a5f3c947e624b61edc876e2ad8c36ada061fda76f69c8afb95270b85f4672171678d078 -b7ec103d6695fa64107f66622148902019ff3acbff7b77ad80993bdf209b73990b0fef92dddc5fb66aed77cdb59af9d3 -b3d002f0a35808e3785d58d0074be620416ee9381bdbdc889805ec2acfd169e1ccb60045d87cae3e90d5da94cd58bf80 -a17c44ade6eca0942742edd237661ed406a129a968fdab28a58d19308d207a1e7853099a4a3c1c181695fcf265107a55 -91fe5c0d672fce368e229e735eef43868e31265502e2876e54aa44470a257d1c126ed73d6df860f42d8e1dd425d8987c -8434fa331278fcdff2c8c07596a051847425fd7cf09af31bb235d208ef6e282cae173d6ffb73c0475307453d6133ae7e -940188d6c20924edf1d9343ea85ef9e08d9d87d2a188f8b69514a22cae10aa2d3ea8e662d43d60b8b77183b3c6e8cb1e -a89f57a730437fc511e1873830b300df7a417493a468afeed2f837f31641cba04924effe11be92d3bfabbad0bbb7d04c -a561550cb347fc9178c875ebd8dbf5d14c0afbefa79f7b93b893a25ca8fcdeb0293de5a350ef63413aa70745cbce9a5e -89fe7dcaa6a10cdbeee9d0d3bc8dfeacd47e1490a6c3b591f66d3a64ed668e6034381e0ea9f5f04fd2a5d9ad5044b8b4 -aac54b334514d41665b80b2cf18285391f47be820446e2272d69edce022f6d7689c8e137e2e9579d0846bf5440d768c8 -a231a04b942d471b32cdd12eac3eba00b8910fca0812c9470802246c479050d6c860f64bcdc6b6e39ed0e9609df9239c -a6bf6eca52b5f3ffd89b79be6edc4f517fe9c9bc67051179157734689fd63649e321d1fabda916a9c4666b64ed60bb4c -a7c4f791a1d77cfcdf34c3b73ec7a43aa1c8ec81c39ce81d12c51973ddb0bfacc79e1a128ce17afc5838982f66cede6a -a1644b337c4398f00e9ebfed20d9b2c900ccb667be036abba0c4d372939f881df2bdb5d40b64354f65c8f2ad9ffcd656 -84f6e86481d3322de791ad01d8c1556e5480534e52970fa601b295a40270882476779301d78bc2ebc323323ad0b62253 -b32eb2beaaeab27e190c9d381b9f3446038391da552db5ded0f5b58d070694f07c737315a465175da29e2a236c539e9b -857029d97cb9fcbb67e194d9aeadf5b25cf8184b3b704ff5da424fb4b39abdf3f7f317b3f79c762605bd9bdd5823e7aa -883926170997ba84cf45691c117912f6be5c691abab77fd18fe114577e6dcba18f8c0a6641ef59affcba1b2c92e093cf -945be3febcff77b4238500054a053c983add7a96ef43cd91921dad908c20d4ae08857fb93a5bb588e9b441aa9a536567 -b9efb8be322722302d1c06640f772596fc362586d8f2e49c41810f4bd2b59e8e9abf3d5369b2421e1ce6949c067f07be -920ad6d5cacbdb46af424141391817da2fe3d463bab8db760026f98e50bb51aa4f3668520c133ccf9622d66eb8a60e86 -a1a9ca07d8d3a44fe372aceda194f15a2dc3d29267aedcfc3fdbadff0bab1c4397da1049bc0feb9097afdcf1cd1ab603 -935eb5fe97d580c10766bfc2fbff71d8584e00e1a321018540c25f6b04791b63a0d6992257fe110b0d17712f334c9b49 -9530bde6dc33e48e05d98b77844766afc0d5581922e382a2fc1c183adf998c8137df29e56b868c7892b2c1af56edeeac -a8cd3698276c2bb8d39ebf7fb5fec139580755adbf81bf362e1cc19f4a8be750707bdf4e1fde3064873495cce5cf5171 -ac5a83c82004728b34677bc6b1fa507687992b5b78745e5820de08f3fd99e35c905608936ccab62ae39f0408334b3c6c -927b0077386a5055b499cb5a597ec3c9934767343fd91214fbbb5487faa4339837eab52c75a627d7addc5cda5ee35108 -a8acc2ea4a548d9a2fc2738abcf75cc0efa189b92a99296c0635d53f2c0d7ee40ccc8ae410d2779f95ac6f2027c81d06 -a74c24b8c695920b12a86ed6da6ecff72f8e19fb06fdfee9cd1c1e8e5f1c202d26fbf2fbedc9a5deaeb2d986425477ce -871251e8d69de5c3117f364bb95d876fb89974428bc167666088d5ff1b83328b675ac2efa2d0e215831e69ee254623fa -946f7a6d3d6700f65088c817636ed3c1349e4f5122fbc22723d131d8ccd055931dec977cd0cb8dd888c6abc51a5f4194 -82f7c1dc3f133725570c7b64e31b0397fc3a82cb4966948803de210182b9716ccd19e59c0e0382c0c970d05c5e13509e -8bc45b43102e0df4767156b1e8ec635cc07fd629793d289be1f2470297e8a084bc9af0d76566cc485a8ac898c0493fc5 -85000f8c8130abca642ae94b4feb3448390745decb1f443c34fd06575f1d0de35bbe649b46251df0a4bdc7a8bc133b2b -ad1ef07d34c59afa37fd5147646c24c03622ae4884c163b80d45ebfb5fa994699ad9166ce1ef727c22be3c28e0838cbf -8d1dd5500229f463f94c611bb2674640d20f2d34dd40b28c4d2a21d3e64ba7355fae55228f1c70095d1b288828a1950e -834cf56a4f2c2eb04b89383213b84bc6ba554a4715c3c1547278e5501102f6ff2af27cce0f876a2aa2da57b5ac6f3b3f -a468d06083d770bb4e484718d1c147b49770757b5b296fc6d6035ecb3c2f5c4155176f12ccbe6616184789350403f387 -8abe730d80ea895705bf67ac4f6b6a36fef7403702d8458a383d04e4859b4c8c7a75598721cc75793d29276afea27ccc -a3890145fa43e6b5c7b8aa0a73a62c39d623c9a75d17c5a05bdddec08d114ab5b0a865c9edb2be6ef31c3dc9544119ea -b2b7c1cd0aed6b776515a12a0f3a86353fa3d3a3b6027422bf7f2c21e6917dab543e189e860c8fd3aab65484b77efbe5 -95215b7d3d504ff83ae2bff789feb6b5919287d354d567141bae68a0f0d27b3e898edd8a9be5a51c04dd28ce9d4ab937 -a93a3da0e101797c690c38a5bf5bc14e10842e48a18c9888807b2233809ea8a34a76d20a8ece0b682d36c086853cee40 -849a7fee901a9279dcc36fe8f276ea6dfc37c30f75b679ddca2cae9c283de19c4df56790e6ae12c4bde33e837fcbc324 -b5c1587d84b0826e64438d8ee7c103119b164bede8d243a0256b5b798240259dd63281b81bfc613a4874a6732d05e143 -97600c536388c942e0a72ba3bc33b3af48045994a3ad0948fe0741391c1eb99693d072d1efdb644abcb08e10474b7885 -94c2120a5b4743496e7ab9bb2e474580ed27d7cf5b6fb132efcdd7bf934434d2be8d6f0af009c637b31727b3ad5d2280 -8a5ff1e7f552fa8b34b22a220eb1cb018c9c9430f0f14a634121923497cdb4a69fbb8b60eb33e5fdf9b0feb3e9f5afe6 -8b4c9032f25181e6fb9f60eb07e3d6cfa2b14ffdd6a0fc1b309b078f8290901e229a5a6ed96dda74e1a9a894224ff588 -a5e04e164ffc46da1dfe026ffdcd99332874a110cd168c44762c461a5560b5c098ec71673d509fc053f6d9064d4ba255 -97d21cf8327a81385fd3915c7e8efac7662f4b39a9785b4a936fe1b581d630678f42a3e9ea7e02bb4413da7ca9a6f35f -806d8462bbf148eb4cff812cab11b3d819669ef5f0d76b228fa166b83727c92fdac98ff3afe946855685b050d9d4c6aa -8a9899b0ddbcf4ba3f16bb006218022efca867a5b32e1de9c7efe1d7039c8e200a406bfd09ebb8921bf1997185e9266c -8fad2d8629c546c5de443b36927b068cfa333c8c4c1328e1221a1f6af7be5363ab8981fee54307532f239eda7656e6f2 -930146a1f6c3decf40198955059f70c98de7c5bb1b25bdc97fc72de3a84db1b121430cf7a7456a692d8bbb6b325b6001 -82987887016fdb90f79f045c16629c5b2b17b1b4702cd89d06b70086e5922cd10c5763cba6f3d30a2c33bc84be36c6f5 -a6fd7e4834f7f29da41170c13d29acbba86c74d5924cd361588cdda26a3ea7f11ec34c31869537ff7ee0b57a24555e9c -97b2474cbfb632148869a6b911c2ab91e4af9eff6c181566a1eb34a05d2ef3fa9da4fdf14e8fd8746a7c3123e20d572e -99ea177bb7d98dce25d300b09bf6ce08a7061360c4ed9a54e30c1aa5a467be6225737b62ae921e91547b5b9d39b800d9 -b9dae836e37d51c9611e6522aa6aa8bccf2644f23113584c74c963d79af0a7ae533af823215fdcbbd8df62f00ec1505a -b1a7165aa1ac480b4eb1f0b3d4284c69907d1b5056a343a2da84b3863c9a2ec4d757493f5daf9ef252a253bb3b2b6745 -a1322eec41b38b8bf3f4566bd12f9c230dd04d085e0526218489e986d59895d471bd8bb08351edf40021efab1d29b2d7 -96d559df46015e62d8876f4d8679f9a9867dff31eb151238cd75b3a10bbb2ab0f51c804a2f5adec1decbfa355042a6c6 -ab55e38cd273bffaa94400bf4913ce0ec1c1c848e8c53be1808d4ce5338ec92b4a4160b8faf0d1d8ee8b71ae751d0ae7 -b61c2987e2b402a52670abe305f8a9976efa9720ad0d7c5c1d0d6d9ec6f1569f51621b6edae84d9bb3fef32bae31a088 -b5234aa19fd9e714c7a9f3ea33d39a5c49f42e7a8edabd8f306083669df4898711d4b50b049dfb91815588ca60052673 -8e98a7b90baa4693c6a1e1c2e556d018c3408bbbb5dcf2c32d120f797fd8ed1373f1f112dbca114863801ec6efc1a5d0 -a7e1e77cbd6274f8c74b37a607cc20596bb7fc35ff1ab4358de15b07952aea397e409b30188c8516676cdd05d4919f3b -a5f2336ed9338772b71e490b1b3916d33df8b013e4d38dd57185b7314ec9aedaa34eda2733c38e06e656a8cec74080ab -b5de079ec867af3a3910fe47628c7d793c7d70b79e25a9a436e0a75405e2c58b740c1b86e1b073842d475e0b717d0bd9 -abcadb7a09173f1eda179ab7e3a5722f020402eaeafb9d604641645c21f1e009b758f2a6fd262f115d80e23f8baf7328 -8694ad59d4cc328b064884d147f66095605d9bf339d09e45652d68de765f2b09d45558d45daf9b4b36dcf881df8d4fb8 -a2cc7b2e812041f17b450b5fa7429cf62e2da06a7bb3c08a63d6f802ddf13e8b73d2056bcd6407476dd322fa35b9b065 -a97b0e7e22214f329fc57b6d7ba882ca563f863c06f1afcb60c0bbc81ef08ec866d39c81a80a7843889fc957d532cc0e -a8a809392dbf35911df8566dc20e2373e2fb3272bd9eaf9f474588a9132f06b5a1433ba9f36a738c6cd3fee403188fca -a3fb0038f83116eef1d6b023e2e17ba2795f7f90ed7c857d9f04337cb4e0c2e7d691bcea54aa72ac5e4383125b74b755 -a80ada835fede8d121162aabfc8c349f685775406693d599e3c288364097b02d96c10ddc20e72fd308fc882e5b70c064 -b6e6c4b24731a2895b7513ad97c0928efeeb0c645dac9fc8cbb0a6419221807073f6996f2b778e1dcdde63acc3a6b2cd -880a2e8fc2eb57f44b08cf4db5cf1751bf9f4aa688708039007d2a198f4e7f0f808aa566b36b15b971e804835102400c -8b3baeb4e1c1d7493bd885dde7873afdc235b58e45b515cf51ebcd02a9b81911c5ca182a9e340575585186c99e71d2bd -a6248e1bef3c6c6ddc155dfe95631a3f00308fa77b1c1779935e76401e750f151b7377f9376c08e8273680e924382af1 -800133df4ea65de3935d98b0249e335a918c44167a34a16c0a4adaa4654f458c376eaa76ef088672d39aec4c7d951833 -8317a6e0667fb524f35672e070f047db29450b06348604319765e4db09f966ad995098cf38acd30346c7fef5dd62528a -81fc2ef2ee0e6f21f406c51f02b9b7be8d99d30a054df918cf89c708d64c34d8b0dd060dff4383de858c0dbff25d71d3 -a28611f96138fe6974e3e1925b582cba76166259c32b39e95702fa0c4957ef2ca32d575b1c08cc8dbe96ddc0eb56a9f2 -86c6773f4e0261413d6d3944e0f7e498a6dae518120e3940d2f45054a912e706b3b615fd160e6143a7e54942406f9af5 -ae91e3db099d165b198d80b6d9af894203949d87cb980f4db97dd43ee55fbe1a45df156b72e3c3e9306975f9e5e62d77 -ad00ceaea52dcef616be9f9815548f8e9b800bc9c1a8832a4d8acca6c8779317d1951e5700e54db070a23db41266c934 -94426f78470aea2d82eded320b45bea09b7cbdf02a3d7c2af4ae4567a3493b352b36f43c3669237879910dcefcc82fe0 -8aad924eb1a30d2844654c9829d82c65fefe964d815572b6c9f902c6a826c247257a7d0d4967e2bae331d52fb3b7c0ed -ac9489ec928e4f43f8d194b8f3ab83382b66b045f18efdfcb05c1d4e67af7b3745ffbb7f52cab4b8895550d10132e2a8 -af8f390c7cc40a08c0143b467634c10e8046ce40466006a4b4297c76a6c16309b50f41a4a022fc838738c4c72edfb34e -923b0384e87a2ddfb7a2c47f628172e8dee76fe812c44a756c67cb20527d8e9029a561bd4ef446a013d4be7db7259f6b -856316b53f09a90af770bafb5c9ea7deb921687fdfcf512840e96fb83df08820c42263c9ccf51465da33f1b03db04d09 -92e8823b523f90ab75ac6e30869dcb257d232b55a3e167769ab5b54cbb83be94cf5d84eed4b1653db17f3f1350ab5e53 -8d0d05fac92079a3df86a72fa399e606fec7e56f81d3443cdf0cd373b3330235b76890197ae61f24d17de39dd1aadd06 -8a801fc71b9b6988a829044060679a7cc3d40630fba81f72bcd15c0e5728867f4bfe938066e68cbb54b042a39600fde2 -b40a6a786ca1a21159b72990b4d3ae8729722cdace4e8124f8cbcc3fa96005563535d28e9d92cda02e91d979d27f8f97 -914f30250d79829919c8ed184c2e471c0d9835f2348e628164dbfe39a51dcdc3f8bf99c945b1f413e65fc5424014e5c2 -8ab8b347b7846fbc7ffe69c89ff67dafd522bec708b7ffea312b3a7eac47fb9d6006cb9038962a07dd89d4688ee6a18b -8e755f8cde0750700252e41f6d16b825e7f02748a13744c004a52b19e52d58c42d1ac32cd5ed1d6ad14cee5174b4ddf4 -88d6192d72e1fefbbc9ab400e5b0018bd300839cf604cfc1034657f62fe8fcfc52acd86c207dad0fa6383361d338b2bc -971fa2ab593578b341076d98c49c71dc7d9eb4ca706efe252441499037cc86fea49af681d8a4d324d302526b2a3e5c18 -b2deac648501d7e284a85c19f514f8744c48d2b5516c993c2111128a9fa042aed34dc371a0cc3f00e918531dbf16c0fb -b63fab8600fa531d7f48f8d207298544d2e03d4da23cfb43d99b0612f1a20441526de63b7609f5969429e763147ee5e2 -a8f30d9b4ac3675d61199e8e624f88b9dc52658a2ba26a2bda5f9cd3780f0b1e32b56c825d9dbc3a059d6c61fd37e261 -8a6f8e963dccbf1db9c839c21a4e832c7a218b00fc31400346b5379fdb8394142bf8f8b981fca3f4d3c43d4e34dd3e31 -b4883e6a4213c799abb2a9b6998ebd4c89aeadfbabbe4c363b22beaff46939dfbe4dd20d113688a293a41daf5cd82c8d -aedb55058fb467ee9556a3b601af86962f99fc06f7eaf837b4deda030b1899f565da07ddc7108e9f5e7024e11c723ed0 -a8185aafdbd22a2df2ea0f0cf67fc88c4c3f8e64040da08cfa9e8075b792406c20d3155d6ea6fdcbe9f5502c44125545 -b2b27ff20d24cff756e8edbd6f8686d202d687016c561e56dcffebc78f404ff544c4d3ae8802b91bed0487792d6dfd05 -b6fba06a70d8b1000555b8c6d791b1db3fb7f57a0f8b1fa8dd00b2ee14242877e1e836cef89be3f9e0565e61a6b4c275 -92b3dd6e18600ab856c276bc787429d42b8c02abf5243f7919625aa1f4e8cc3eca61cbe106b81d0e4909393a5efc021a -a508e1a1d4375f5130c95a169fd1d4df51cecd84822dc28b18e464c2189d464e6dc6a5855e0cbb94500d041319749ef7 -84b3e9a6b5d1a7bc7df44ce760b5b686fba006945f6e1f3f67ea2c90dfa6ed70bc1f021828a0461fe158ece87deb1e30 -add83e686118fc5eb56d79199d33cf0c90fb2a5996c6f453fcd9b9eb3a273a466776adba1cccd6be62a4ea154480fe17 -a1fb58d9a323dcd7862ad4bc6359ab2bae35a608276a3053d40bb3abdaf3e8827027284d964e51ae7b61dbf299f2bea3 -ac901ece7cf087c782f75f1c61371f77ba061bb752ad680c9b1012768e5ebb6241b492bafd9e016e989cea1ff51aaf5c -961b9ef616b7faa3befd807772893c7c66ab6990a9405cf4345ec29cf13d75dbb6da41ec87af5b5c4bddc8787b88b480 -b386f7ba0b94ced118691d883549d70ecd28d1c0d1b718cb82a92a246e61de4ba80b6a76d6039c261e342f9ac136941c -b6415848092dd93da62b5a5307d356d968bd7c935d3626f40e9446573e5794f37a23ca072fe8af2a9355a4b04ad35e58 -843b3e3221bb08122a1e649e81759297d985c7f393c36cc3bc707a7aaf2f53b9cdd449e7a4384981c5976fb3955871d4 -94083ab99a73dc5cd463b5259a0f4e99847bf32ae03739a440f8f48e12f078602c76b3fe4e7ecd31d52a7aa31168c5ee -b6f994b5482aabe833e388b24b9445c01e47fd6e354c3684094237189001290aa77a327181e7e7e756682a04b8b3c56a -8366f418a3fb2dbc9ffb5b798adb968aab991fa689ec24a4c4bde6f046989b1815e1bce5e846f3554028e16799e17281 -b8e5680915eb37153daa9a3a977b47c88b4f30fd358901888a1056e07d2a7070d28a47acac7aa7856ede16bd0c93ff2a -871cc7a122cd7b9ae2199801e6a0974ba8cea64e5866a5130ee0ec926adda24f91b3ff2785932cb55537030bb5ad811e -9370ff1ba27d33080efb22836147f766c60f0a8ca250ac6b2a82bb464ffa543da056284b712dc3cac53dfd1680a4cf87 -8614d8029df5058f5a072716489f734131b228972ea9b2b952ab1150bc50b6637543aec1c35763f8dc578275f7c9df3d -b8efd01dd0016a27a0e2df65b571d405be4dc8e0df5dc0d8354fb187b96589e95847ba0c2856613924125d21193753ca -a86e524431247115ee497c07ca2a73387eb820d293e8bb74e1ef1ae7ffdb21a9dd8ef1a6e3f391e6f02ee0b51fae2a06 -9151e2dcc0b928573421ffbe43b1761b6ccefa4ecd58be7fbc8ea8e975e18d52c264f682104480d590e6f8c0b8b9f63d -85ac8cb79fb8916f7eb5431b7e81606b38afba15895909873f85d9577c87ed2c1d0fd489fe058362f20ac05626681346 -a076dd75ed807bb7afcae8bb9821ed46758c1a8d00e7f3d3c91a18e6b95dff3958ed70441a1f4691ac3268d95e243614 -89d8dbe170b9804de3fff5b6512d04643ea0041c3f9bedd7432b171ced1577b0c0a7bb911852c6bafe154ba36cd30320 -809a63ba788e618a281804ef97a75df39c7115900078a6bdb203bd79d3df87e863c631e934dcee62e28a16cb8735acfd -9727e6720f8b73b6ccad519d8ca1d4f90c2db33ab536f399e2c4ce269be15d99e22504ef153aa26c40d4cfbc450f25f6 -83e77918ba6e28ee01ba6b8dbdd84c53faf65446a90bcef46f262f341dace2e237b1ff8f8d566fdfefc6973deafde716 -b5a4d3fff76905bbb229d579b8433e76f2f070108230f20a30e4f974f12f29ed017aa66e9b298a4de0fd535a0e1a44dd -876d3a0bb439e7da26539b98abd0f7e0b7e8035eafed08df623a77fdac30ac85ab4d58984396319a88e072dd7a5149a9 -98923e83be5b2877ac18415f9391ea792933db718b29b6970001682cc8434ae9fc640427c0a27f6d62af5f78f3901bcc -805c675a34443a14c0098613d11b4c015264e038a8d1adf083844f2e3e3f2414689788423dd0ff77c02130331d511068 -8d8cd51d4146bfa48492e9d3f3e4b845d4ad1442ce6bbd95979f9778ffeb108c641c9ffc2ebbba532f922237e5849222 -839862454707a99eef931335e5c5ed80805ba06bab0337c5301fe9fb92fd59c9ff6620e66de7369352b079dc52bf2113 -b3cf3bd867f60b345a0b91314b34ce1c02e64dfbaabd70782614208d32fcb5d4448102bd54728fb05d1ed18a750e88e1 -8207a421d010e1c5854b8e41460c6a13035ee77f7add0df83c5c31bb00d7acdbb676478a7dfc738b9aef5c29d345ab63 -ad2b14f87281ad6e1d2b713e6e8303f1a45cefe097820d6a1bdf4652364e70d28ca92193e2bc3d0a1e69da5a51c90ff2 -98025be2d7e59ffd3f6c3c2b28b27ec42206968c0f96d09330598fe17a207baa6574aa22cc26555139766cc284224fe7 -8e80fe898b7fee849f7dc8e5eac668c76f1fe18d159c51eaf4ddd8d4d600c852dbf6c2abcb878c64f37db7fba3d56968 -871c0e2dd929ba4e157ed606741a6301aef759e10a3f919166faab23e599d3409b232240e3afe9c0e1622a11cd453c1a -919f7e465b399e2819ec17aacc199421d267ff2979ea8dc8962542ddbae51e2bbdf6cac92f8a35e05e4d95a4a8315cd4 -a6e6667e6127ee4f0224a9a94be3c22831a1ab3b16f57462562b11473c425e7112b33bbbb6af860c81bd6e84bdbd3b86 -87eaa9e3515f2d94acf113d77dc085609d06cb038f5e8e90ed29bd04bd4814e95ed0d6db5a1d65572dfaf73ab2e50ba9 -90b30c66ebc16f767f3f0bc1d8bb17ca1951a616292297ca8dd06d54cc53e5fb5fd6321ce158c04cb4c91a04c01f7fbb -b5fda3715566188630f96207c4253315a9cd166ef96651afa0ae1d6f0aa8856e7642e2f8ef3b1fb1eb2c14a7331f6592 -a54143f662a6946da901ddaa9e514a0e96bd6397020cf5d88084a1e1edc092b94facc150b1c029a508fb3995acee50b7 -8dfdb813296bd105d5813657c98337a24c8bea19bf0d119efca052c018ff5c88f31e05e110fa12f306ae4b0a8498f113 -8b7429599915ffec755060d9cfc2c445df9184ba6bf298bfff5b54c2ec8747a9b65bdc6c73746a94a54b0a62d93b6a28 -8a1d1108174d383465a57ab4b1a6811ab86dc007de4f342d37f4cd311650382e0352d3664ef09cf1626c0b74e2f21ace -98cb860aee0b7251da2d114b2253daf977badf82027a018c956fd59c6c93b716bfe69a132a4778ee4b7168fbfe390ad2 -94d5a0d33a0aa590fe76c71e80b21246dd9bd8c2f5ecc647e47a423c2dddd743010484cf2fa363ea73bb217247429066 -a082b7a109fad08e2c01dd7322625c18f47497b32269ae4e529b1681aeeb3c4a813cc6088ebb4427b486320fbc4b7872 -86c23e2d3b23244c7763c123ad67a41a2dad8e4556cac23696906d1acf5f4cd7f661281b8ab2027d268405b08eee6771 -801522a5c211e49eb96294a9113022d86c84bb8741e44fa7328122836a39ba7e11e27d0d6773550b234531400ba1e7eb -9683d154b18ed641867fe67b2dc70e8b8afba79f73fdeafdf9015d85aa0c74d270b290952683c3667c0202a83626687e -994febc16f8d216a20774955523262966e955cf964950b4b2831a3483f818c20ee6f51cd24f499dda0d3191910a9fd35 -aaa8f12184525e89ce980468fd24e1a9af846246297546655763ecabf0b5b5047394543f1791ba1c70e21637cd815877 -9193a37d5692ff1bacb0265bd7825c479624d2adf33a419b0a71c8a744ca1b0c9828127831302ffea4fcceb1a53ccd54 -b9f3213d5d588ad73b86365cbcf0fabcec5c30cddad418281ff2408dc140e3f6a25afcb6bb569605191665706c675e35 -96aa280b2f0ae5c3ac51edaea4435ecff8ecf8f2536a3400d8c4c9b12c64d16418838dd7ffc1b815656109ca63261050 -8486373d67804e9832bddca04a0084d1976d324d85c22a52ce2bcf7518f014ad00e4795e61c71e0dcad1f23316288dcc -b4f2e7f7e2ed7917e7c5036681e1ceff18b688c1abbd203c2bda0731ab56701a847cef4f753f68119110680913c2dd4c -87dc2336d88edd81b94ef78e7bcb6d3876257c326d28b3f4484465d6c65faa6c17aa7a2f85c6b94ddece39f6736751aa -b4b3502ebe175820f53da8e3fa28160579c4150d79d932923739aab545af537b3301d5b21f5138ab4100e737fb61a084 -88063af42d5845267d979df07be0735cbb42d9b57d3625eb5d0aa7e4ee90ca88fa52aed480a4d60eaf0ab8dbc4f444fe -85cb81247c09e21de6deec42e668b72f513c7b105f60ed478b08b85fdc8a886a97bb7e39eca0cab09b294e4b1490b0c1 -9920fcfcf836faafd211fa1ca78302aa6feffcda98aadb6302300c250fe8621b60d9c214ea92087c44996ae0999eae78 -a1f91af5b378d61ea277e5dac81cb71d71a4ac35322aaf42b3a8aab1641fd51d8da1783bae0e8ccb66d73db8e1003478 -87507b427d381ce3906e372a12f4e61514ad7a102334826266df14542adcbc8bb7c8450a1fe110069d9dc2e9bf0687c7 -b7581b0cb549d71201583e0987e9e9bc6cd36585c96664f836e1b7326e5375ce8d0a450343fe0b106dcc581b77de88f9 -b26504a6a7a64c44d7f97d0402bf752740934ea4c6e101ec131666deaf574d55fd7f96c8807473722b6629dbda2ca3b5 -b90accb5c6b78322ef88d017fee2ae1cf87194f4b3f6f4ba6510c0adf4c11b20870043cdaf45372844f5e801464bb682 -a904dfa6e1f813b4aa0b242f3eaaf893da7ea854efe514487a237a01fe244721482476b81ed75ef1a951fc54802b29a1 -a00373aa8d98f4dedf9cec4d227b5fab00f3af2a7bb4c8b0dcedecb5a04244321d5f25a81d57ed0ddcf293c701d290f5 -91bedcb316698e73f43e9dbe0229772c856f34901fa4c1e018e96eb898e4ae02b19d900e87d01501099163be56db57ae -b84dd6b9a61cfc0817da422380b0dcc5221deb600b4b6a6f6c5ad934110a3b66c59f7407ad68bf8642b2bcb5427e8050 -8507c172e499856675ba69fc1b0389a08e58f8e5658c9268172b926dabb4a67b7c836a44d865f736e8fcb14aa2809529 -86609a1d82d90a971786da9ad342035ae4865136e513559069b6dc8ba82ec0bd1ac695fe8afa5f61f85c2310194014ed -94914f127a645594ed372855550ec0817663224208c127a08bff3d5c4f463b7939cf13a45dee68586b678ae453c6d60d -80b55565972213814afd6ad9b1884a4d8143ae90c148ba730ca77b0937c2faabb23a6f985dd0bbbe05705fada4cb1a00 -930f5fe58dabae91c26c6fcbb61c3e336678dcc35d028e5c958d2ee7d50b80e1693c0693b82d719dfd9fbe2c03b52c10 -a45053c493da932896d95d5fb158869c1051e1bf99658b183c9cf4415fc8d4fa1b6a8752b8bb26e8b706a03a57fc05d2 -af7434b48d2ebe639c8082be09060422f662317bdc136d534b76ee3e3aba5ea8f234cd4936aa2b928f6eafdbe5165a6b -a57a073bbbb3020a92497f0ce854666997a182f2b437e7b06c9888db8acb2fd2128e3959f45c391f0548a3de49e37e76 -a0ea8131b2d8cfb799e806d8cb92cb02d32de37869cf2ac3c82f7c5d9a963d562755b16d25c4b60f4ca214e323790a9c -82f920aed42eb630281919b9c1fa4acc02b05ef34020cad3583a29375bdaee167a47ca3366ef065cd8e658301942dbfd -8415ef32a93820618abb91329224bc46d478ee8749ef42e372ae4ea29b6c05a65d5ef515ffc7d720b2f41ccbc040f176 -a0fbbb0113daceaa05478163fa835b070be5898dd9bbfa9abc582409a7b671c0e41a5070de4cb6dd2072888b11825acf -adfc99221d7f044b57ed40f4ef8a9e47e57265ef8eac654043cf5e777950af6fbdc2c2d5a5b916048fab1c19acd69dbb -b3d8e85fccf623fb3848e4886d580469bd41ec0533975298bfbedc7a1a9b4e554714991ec4238d8ff976a83cab6383b7 -8b09702f3789ae1f7799ce58a0ffc2327b3ebf2b56cd870f2be66c0d6781cc1f34c2d721d0de63e0fe9db85bee842fbe -a935864851b73676cb49f509a198caab467e5dfe4358e7088d2a76e9b8c13e5d20b01eb7c0cb9e51ee98c90cfc393c71 -b5035d76a5a8251bcb18f33968b077d43403c69492b809eaa3e202eef174a5649aee30f701ef0be050ba5026957093ab -b1cedb563cfb09713009b2263975a56abb9932b8cdebf10f7836c5c34785149e9875ff590fe1414ad2d21da977b7ba26 -98a718c23d44b24ac295b328d91ab7a40b23ffbccaa90bc5888efbd32b6a95c530bf5e999ccbd4f1c85263104f336ce9 -8d9d2ee952d5b135eac2f06f0478faaac175f23cb3789144f3a490f2ed34c885ae4d8ad7ed48db85cc6c2bd70b38c6c2 -8155763582ff6c68d7071ba842b6543361cd5f65b7c70d5bb838da2dab2c02f3363e2324307e7d2149b12700d96bde38 -b18b277334ef7f24706b7d48fb764a487bc4e21fcbfb01627b7524e9a5d3253be99d84c417084fea769b550b3ecb4574 -b80db9d83cb1ae861a3f61197a1f14b6c5004a2b3d031fb207adda94d725f3e265535ed7b69b9c801f2e95e1d64c1901 -82cb673ac9c0c124fc546c59505fe4fdbc05a1fece0fa579f6a6df96f74bfa877ad82b6fa768cb678ff04ae4cec58d1e -b2e190b785a4a882939489b86d0a06cb637b7be8b14204645bdd9d6c37626e8623e35e1e4eab5c8fdec0f8349ede8918 -a82237c64f15d306365be19085e1c725cd148702fb66658c7974b02051b685715fb9e35fd4a596ec24d532df4711f82d -ad6f7e3992518ba04b510b705fa6b28e3733e0000a5480e8a3c30fe71394de2bfa43333c69e750bdc3e7092b9e0f7ffe -8c0ee358f37c28f3b80cb9ad5487c342fab734886e31e30c667e616f3aba737a3a07bac4da552d8405ad8b00c03e09f0 -b7851e0b88486b0a858a218f4307e0c0c8c314fc69e2b90cce8ba86d3fdb796b572e50eb4e82f83f73c7f048484b45ac -a7c35abc2e15723a9f395d16d2484b798d098be5414ddef083c8283b0c29823226fbc4727d9cccf96e33b27fc40e032a -8ec5ff2ba7c3ca8a2d18df81d46e93a3bc94ceca88134ea75cc8ec2ec4b1ba3d0de49dcd4d385083c648a63483377fdd -80ca7ee722c3253e7b534b42a8947e38741c542dee1d671b603a9a743f5ba2fa95f193ace46c01000ed20ea05ad0639b -ac14edc2d803b28a169154364dac5360cf0926d911a615077a94858fb4cbbe31bae2f30a6a68b248cd8bed015e0f3b29 -a4bdb63e91fa72995316d03cd117347cbefd14eb1b19a0adea1c9d39f49d82ca1ceeb2a4184187e1dade109d10b83090 -ac8f528e9e8fafde00e66a75d4bb68c99029456ae9b3b7cc76ea4816e89aca2b8b7d094db214bad1e87dd4e84d1c1a5e -8a8d090a01aff14383419735840fc5286e71a5feefb98c563b2d7ee593b518c3aef6654f10da8a77f40feb52e1d31fac -ac4259562982b355fe5e57e1cef574a6a40a7144598c13a6bf07cdd8000bfda95b0b0b44f215e9dbc71be114a1857441 -b53741dc30b11fdc6c9778555c1f714fde60890c191a0effe419fe2b6100228d07cd0738d0dd73057cfc7e340c75f0c4 -80ff52fdfae53dd2410ea556ea6504696439919687d2dcce1e952d9d17b6e3699816ee623b0153bb0e0588e36b6f56b1 -a92b34d785a71d10e6796ad07df788c6878717cef4f1f0623898370725006d46fa00a0a22a3934fc5cf323be85fc7767 -ac1cc08cd1a8fd6c946bbe14662b18e89725933a79965c663b73ae3cf5f5ab87e794559ed579564884e430e108385e18 -88b8b2264d84106d38c321c3a4927b9b41cac172ae27f6292ea44cd9ce11d185d0061a59148e50474d4dad3c9e940476 -b7ac9f257b4f676d69899a181b45f40358dcaa70fa2dad38870d52838aad9001f3a3145f6550fa2826018952431e4cd4 -ade67b3d1602ab0af6a256f25a65b621dded7a0adca65c526ab34c5ca3088a549b7ccf76c586993cef0d2d38af541617 -8fcd8bdc44ab42a70c174682a1e8b929004834d4962a902de460eaf8649883c868cde1cd660d14d7d3ce589fe3aa83ab -b914f6ec60f1767a12fa34a4b400ce102564dac4c1c42f1497c7bb824bfb9000c9e23ed7cadaa16ad79d5ac906070710 -abb1683b313612b583e87228384eddc3e2e7539e0aa26e825f5c27da222941b6a37ec47127cb0f11b6b8e0d02a6f66e9 -b01efb31962345a2fc71b7c370e7d3117bb1d1e1a9b6984ce11bd83c898dc127fec2e821669deca7c74d406e4678a736 -92439394c6c811d908b05c626f1afeda3a0f8c925747bedf66a4a5895ee76e7445a1982e99d8658117128df5866eb64e -956bfdcb00837be56d44f159bab9bcc2292295ec1ca7424615e3b163b5d14f7143e214609c0b65ab74a0dbddbed4d782 -880b9a8dc9bf6499f1f71828e6c906e2ae59660c9aaa824a6f36116746406351b4e364b6fa26c45e9d90018555bc7dd4 -83f4a0dcf523d414e023075ce0dde10161d65c0abdba522c811f0e446980cbc21eb0bb42737136bce30fcaae3c673b6a -abfc5593e02dff15161c4da67a806af3170bb2bbc65e3a0457b4bd994ecf5e001d02bdd417655c2b4433dec270a6273c -99c6d8bab7d937a4cb5c272c4bc3856a3cb8295cd77ec9e2fcc6a50e0545999cac4c413c3ca8e5408afdb60388c82ae9 -b08f5d230713639ec98a7afcb2a25b9b2d1c48820447d28b6a3ef448aedc4b9a90b6c5ffc6613a70ff1766b51992074f -99d4b54e35dd3f844088155f114ef93507372ed32a6898b9954d5a6d0743e55d8e7de20d67671454d26561ed5e4fb05c -b7cad70deba1622c79f1ecfdb2612e380e9048fb6146760ba61cb62e98cef129d3944c5f442b15fc11c102fcc6e2adb4 -95feea870c86525ed214e3e0ecca9f66c5e0babf6da8473e5cc5e2f305c26939f6afda0207bf5855b6a6c928815577ea -ad6e77ec226053ab331f3f871d7fb770ae78227a85096d263bb42915299147a7a7b57a4f8f929765cfb323267b94865d -82339f53ab7344f8dad554fd0270c2aedb34f7b0c630f0a56ca9217c04f0e4a38781eec769354a44fa90f556b388ad01 -837d4672d73588f19b872d81b7993e5e0628139f5685d0520b1b766d40e71b9d83a8d2bd65a03987eef89b3d5c254683 -b3c27e19f579133f1ded8c066dbc3e4edaf449a1edcb1aaf215939d63a7f2b250b9b7afb62d4cd7cf37c28da81898a67 -91f669f9db8fbc6d7a5ee92cb67c2fc1ccef6dde622efa455dd7535b11f506f4e309a8878b859d6605a3917f6d7d67e8 -8332dc636222829a83501a8312904096c2984cc0c5dc077e067d8962bd87666226e3324a9e5057c1cbc3ba700a3b22f3 -97e81e20bf33baa4412d6b81c5fbd406dccbe70973bd73e956d8ce85c99d2199daee5fa6e99fc6d40071b352b5044865 -b716066fb9e470cca4546a401048c0e6c6408c8c9f4cd80aca6778d3f4121378e11cccf8a005845fcc8dea2e1b9f16df -a7b340eb603da43f2aa542dfad1ef3d3357f583c46040f2dab234c8246d7c55d6885f9f7a14f319e22355ad498c22a04 -8281ea97a28ade9a0cdc73a077c72a92810b70912006611a00df8e7d2ee1036af73c0f062b367f3d4d75be4b9bf78aa4 -a481ffa0813a4f2110c6ac535fb446282dce73c182eb99baf786ad42b804ef12df078b2f534e3cd8210973880bba6a63 -b71a581ae08eda0437f9e9274c1f9431d6b357e4866e40d4c2470252f0888978497af823dbf464785479e5f35eb89aa8 -a07c9010308bcfb0c97a1059d5213980000841ca0565697d45aa46e82fb36494e4940aa435ede417856d24f73d374757 -8fc353fa8733947ba067ca2bf5e14a6c334e4ff30efdfa67829dc86f49424f4548e879b153e79dc75f1ec00afd6693c6 -a663faca50e1fe5d00f62abb0b7828d6b761fde9f5a54f27c0b726d8d53281f83ac165b3d3db87f970913350a7dd07f2 -970535269744905640d6ab238930dff375ea7efb2f391db324724166f0c436e7a3eab7ef6eb2e5d6724c58d588a4c592 -800f33f5936498e16fd0f58210a5a5c104074039db7d9d5d92dc62cc00d796ea0a3a22e5d368fe269cedcf30bf6149fd -b4b921cc901a7775df7ae73e97cdd108d98c54534015a1469f0ca6b07989827e0d3f9bea2ec015fabe9d309054aef802 -93295c8a7e5c0bd9decd99ee2d704d814cb6bd0061404fe00984a8afc337e78af11965a8560288529c2a722e8b54b488 -af43d382ff7951bea94f4540a3a2dbb53ed527e966d0dcd117d5212f36112976e1fa00a47bb9870d3841cb01621c5d7e -b4d106b21e4676556bedc6e7f5a7eb5c2ad0d5fe8004a1d968bc7806ba871e241d38892b1fa73e9648b23158802ab57b -a96cbe38f86165288a365efa796b0e2076ae9fa94bb6377cb80c7d5db9d376e9c18164a8a3667dddb3f5b847f52fd319 -a0bde83e1f3e925561c481ceb58c7575027f9641e69f14242b886e7fbc532a2bc54aeeb94ca39bd7da3ac984bfe8cced -8211c4a70d08fe052246d3ccda60c9e9677910a93d9262d572606d99e273c1ade353eeeadf5b1e3c1ac3c4b9019d5f61 -954ba6744e3f991580b6633e5d184550e44400f20f00149d899d97bc4b51b01d09bb4f82ad975cd55189320523fd60f6 -b7e3f17ae79c2faaf5f3cbe0dc528c6aab0035eb3f38954820556bdf7c3546585fb9814717302c5f45fde7170748ff63 -880446589f33ffe7ff5e105fa1c380d401d6c46e80526948fbf4edcb779753a594f3891461f52eeb3f5f2f6051c361b2 -a26c06cf79c412d49f39e0e27e37c82c4cf0c8648638ee66a97d22d822e064a9a7cbb0b1ede46806ea0430639769cb88 -a968341c5e4a3e6d2a2116222e3c58c2e558f5bb0a2877a27c69fdbd38dc3892f9ed7d7c114f557e52a351c73614fedb -ae9b8bf4774ce3b84185be77723ec62b9a415e21cd60e86513c1500916c96d62519ee8cc061d81ac9db9709d6e191649 -83a30c1ebc046c9a1ba911ecf6f147644f58f54e32357dc395388e6bab66d71fb9b691754b11bf414d43816af8058828 -ab5b804fcfb68b6439f311d0420005b083a84da15a8415cc4013898806e67c47698a9d594263fd9be42bf48efdfbe2fd -a41c18185f8111ddd551ecc8f6dcb87036cebb6eabbce7faba40c6c5c8af2ab59ef027c6fb2dc523eb0159335a1ab189 -b24cd94b7c6e161e651107769d863fe5a3d7a847b9c60c7c803846bd782cec0bd54e6278a318ed23b90cd7ad25933fa2 -a5ba23ead78d1678414d4e986b448e7a24b23a5c0f529ba604a51e4ee0f87baee450fd121b43a954be50bff6c0d7908a -b89c17de4809e722527832b90b810d9691b437f19db9cb88ca5cdb67bbc6946ec1d454dc0990b66093ebeb6eeb6896a6 -914f436fe0ac7540129c3deb04d51bc61192ab5d0d16eda77ef70ecf8cab5f55a13492f54e8052f2f214186a113d8949 -8e0b3d1dd756a9008894028d0443083c21e99de69b8d8f4e7eb3ca7fc52ad540355d4a1081774a6d51a093110f4bc838 -a9c1730eb5c0a42deda9d9b39390661717479e29007f5f8499d0645b8b85bc0ff12cea2ac4328f6588a12126f56284ee -a2318a42c99f7613ac78cb110656c6e470cac6903a5bfdc1bb182af21e0f0f409bd39324a13e2790f0facba04459d3c0 -a11ba34521434cb718f1b2015bbf451ba1a7c60e59b1620ea843835c7e75bb42b6ad29263cd3705f7f6f1e40a0ebdfe7 -90705112b625973e1cb35e30f9e15e3c752b2e972231b4caf53518f44b4a40b8a6bd15c4af2adbce5dc194169b860cba -828035b0e70af8db1294379b4b70e56624e1138ef49f7be81d938e8b25aa5dcc03655e045a95a79e0143c23a77407004 -a7abb1836282917d1eb9886c79b6a36d720612e3b823d9420a4a705e8add6c6bfff2f682e6f992a6af10ae2f71ca8828 -81e97c7f980dbbe93df9efdd9c0a8172ba0f00378e9375c926b9e24758e8b827037ba67e06e994fa9d05942320353d71 -afa640b2a7fb997cffc5db74a91dece901be4a36415786190dfd17a77ac837a2fb2d73e973b8e60582e71824c57104cc -ae860a6850068f2b0e1e5a03afbd08b667f44c4f06e431f1f83269e754f37e18a764b00e100dcdbd1c1d18af9d6304a5 -9443fd7e1263d5ab9baa8b1a3c893765da1dbed0bdf62ac9c886425ea9f05876df1920889b707a2cf248e7a029883588 -acb38feff88de8db3477ea9ae3b33e0c5715cfc91cc71926dce26f4f290dc4f437461a186cf1bdcfcd6d121e087bba33 -942882666a9f49ac24d9099facbf1e65484ee76cfdd2eacef25e0f30260654a7b5c0cb7dc37aa1601980877f945c51dc -ab2c9035b2ee9c5e57d8de70b24329cfbd247324309eb30ac78c404ced268dbe2aaea8d417300c90d87924a48702b793 -80aedcea9c5a9911731ebb444500eb95b519e2d4650c1d465afc61f4997879d60750ae3fe049e54654a06eaa2db7d8c2 -a63e1ba5fac918c8bc0f4364b5fc8d26214deee825aa1bff111e03c0ed43baad47e8bae154ad580b851a0f66be85c88e -aea7f5f8c387c21cf671246803cd5baac61cd6359848ad4fd685b1350ed6298a129ed74dace279fe7846001bd6577dfb -906ad36bbec72813b368bd2b79c1c9624966dcbe94ca9dbacc297d0d8af86edbd80cd702ed04f0adebb913a6a7bc1a62 -a46201c20560ef2ded1ed3047fc196bfaef445c4a716890d9235f3a06d6993a8ab29e816eba54c6a2e2590dc8dd61216 -b37eb2c0d765b044ed2fa2923160a19e11509e764025e43a62b4ccbe38e534ab59e68c2cc92cc5aff9d97154b8210c50 -91f93b1404a4bfd3fc8ea019d76230637ceee315da0faf366c712c3ba19088cd3efa2dd30172dcdac11e636f8473a26d -b6b905abc4a795bf95d055ea09c3f9d0a8a9ba0014e288492a3751d2aef60cd3b7846e1ca8366635a94988b2e197191f -847529bf842d7623150a3bb91fc4ccbdc66010bf008179a32359f98bd007330bbfabfdc487f4b98691ad65680af67a8e -b3d37a8098d02b5ee69ed060527f3d924c727016fd92b21d6a52fb1c1ca18c7eaf0caf8144e9e6bb5b6a039ca85cb1e8 -98cef893dbcec865cceae01138613de146d563f13853ae34bed5f142da716673c105ecbf4f2aa7d187bdee20702d8582 -97f60078d18928c4d7dee1ab244b2b7540928e20cf7ccbbf6684148611afdd9cce60dbf412c1fc544ab8c356fda8fe11 -872a6758004e6c87c3788c5c11bcc74db78f076efaeb75127f0baec28febd02528c65b227b7619fb8c29cc92d7c8e799 -8d72cf1191629440d7af8daf3b76b6b1bcdaa8d6ddcde52603dc8b092c2ac78d6e24bec32e1223eeda15dd17ba2c26d5 -89dcc8c10be08277a1e394de336bb1b135bcc5131dee5eece80973ef364a305235936a3b6dc40f2eeec2aaf227a86376 -972c4ee3b4b3b028ab683415bdfecb2454d326a19d274f499e48bb2cfd55165b928bdfa7f97c4fb6d27082cb88b73dd5 -ab5438a8af3acf2eb75bea0ae71d8aeae363d6644c54e3b020082c80809ef86faf5811808adc8240c7693515ed8bf199 -b594133dc9f71f72e448796316ff3ce2f8a03c21ef9c54e551d23723d5f197f7fb0bf1c33e9cb3f51188db7dca51bf49 -aee981b45d570a666d0d0b2c7aeaca3cc22d4873812b4424d1f91144142393fd64c49401dfb970c7d5ae91233676cacd -8f978d21de1e264178f88cad7213463a5efd139c30dfce81a7eecb46942870a3c1971f6e6e6a50e0a8b20c379ac084e6 -9153701c8b82ab43fa4635cf677789c9c9911efcf23250bd393301c0be51f14fd0acc4e467ec9682acc89085b94641d7 -8681989a1be217d77cc8e012c95128557de70b362442e7f1e6162bd52ec6e4ebb0ab28f9ad3f67c1d35ff00216ceeb74 -8e85421256fc71a82d35de9645a6da9cbe4dabb9670758c4eafbcf42b26fb99866bb2b4c374601749738ad34e51dba6a -976774296281bbe1e8dabaee7453613d0a615cc6abaeffd8e15ca4484b5a743e298522b2dfbdcaa697e1eea2b2bff736 -a585501faf955b6acfb328d801cfec5b59be8ff2fe46ef0bd73b86ba4c19c1dbfcc1df844d61a5acc64bb5e8a68f6cc5 -a776217e5073714b36bd2ff0621246a48799eb5ae3ca438d1efff6f9f9beb13779bc18ae5ddb77c838732e8925018118 -992d726bd4889f4e7565bcdc31c7b4a58ba44da5f361e3b46e0a67a6e4f00c25e3503c94e7b2bece737d7efd47ff9beb -b277f124d5dd8dd669ef1f6840276c0bb0b60379ca3a0aaf00ca337c40f478d511b1a73e73df6c3b600e6bfaf37a8fa9 -b037e78617c235e6528e535bf13bf5e82c70588d1d0bd08de754d089bd47a4fdcfee79b5666b95698cd98c0e32164afb -aefef9e398e0edb60615713d7c1334005b21844d3f1401903e09af2db20d7b342b8d80796fccab583c8607c533c9b735 -aad20eec7cf4f0b518007ec1df7dbf4935f6f9ecb36a11d148dbf9e5281aab43feebcc8ce9001374be40776c5ffde825 -a4ebd6018e004ac8b5d022cfbb7c5b3833456faff4f198a3d9dbbd077c8752087bda1ea060466fde4a5f31cb8a50a7b0 -a56ebb8ac9901915400234c1c6c8502905765a7224de56b084f9b0a3468a065e78b4daea27d9887b4f44a72fa61a15fa -b0269890863c63203dd4da3a08a1bf06621cca212acb49799bfc48be7e41c951d807f85dd4171ed57c372914dbd2ffee -ae11fc0f5fd5ba488104bfc07fed50799f51ceab4768afdab300325e9a913b1f257fea067d357e54950c8d08af5ecf59 -aefce65396c61e835ffa38857df426f64508de6e93f966cc46b54dcbc5e2bfd72df927b00489fc4460414569ce99e610 -a5a1fed75677dc956c000b9135c4b6138e0cff53770399ffbc3b12ff0c1677ace264aef2058aea535ee1a7195afb034d -8071def0890d01f0d10dab3afb13125f0194e79608b9ff129572b5daffb49cde5bf6d9f24da3f84483612aaac3cb8eb1 -b5e5bb8c0be22349ea51e249cf2159189fb9aee615dd62c5f67cc9f43745676e703abfa6561df4f5f1d79b86c459b11c -978dfc57cf0d3538ef336a25ca7a2cf373f84b71bc06d1c74907464e3e816d834087ee126bbbbd5090a09ed063f87a46 -a2ff4b59b3e7fef169835e67d47218eff5368aed3e6e2f1cacd29a5efe6c1c2e7e1839d87759bad8ad1871b39c481bf3 -96de49b44bcd2f5ac3d07d6f5270af081776d8631fefbaf9fec6771e13d40a4e5158767067297029bd38e8c6847971b6 -8f2f820e8e3645f2ab9a27b3c23b5f656b681264d08e298ec546c5aaf51119893e0dc8e04d6f64fef48d3cece89692f0 -8de2eeac7dd4b53119d02f0ec99f127cbd8f6a57120d94a9a554c04467fa74ecbdfebbb111d9f15cdc1be2be8c2396db -b6616f68b00ea0fb78a25ecd51d3018b9ef13664a7da42663d1bfd6fe71fab615624af863f3b41e625b36a607bb42dc4 -abab5be2ab033afd6d110a340c658fb512bb53368886d8a5ea29e3c916a6b1bc46decb2cd0f508b5667f9dd88033ef7d -8872d0cb09df44c2a75895d46588316a4c9c743080f7a03a384bf4d4be80d341f8dcf0e208383bf3587a3509f3324fe5 -a3f57fda2e8c06fa7ce9de223f5ff56d53ce9fbc48486d88d2845e7011dc038b6f2f270dcfd46ef5222ae9a1557070f8 -a82c4e46f0d1962cb48d6c3d8ed3976c4fd4c174d119470479d9770619a45e6e16e30693b2804a82b516ccdd400508c5 -b53188c6b2907abcfe47fab98f23ac602525e05a5ac6b4421c437025819c80529e9d2d63f8a3c10cb9dced196e572506 -951934cad4c2772aa0ffdfc4f12a55f490824e104f669e4dffc70d9c14239570c87eb998dbb2a6d423bdfe1ab50f4377 -a276bddb27d86e1e70ebb96103a239ae4848ad20c4c5b7de85f480c3f293c934ebe35792361d9767de4333ac6de11643 -b9c8eccc03d7270779a87dd7c52a42c7bd632b9bdf94274b1dc864bc7a59e13eb30870ab740066040aff0beeefe14d2a -8e0908e4d15aaa582dc028e015c4b2bd97c82b8086737cdd1f2820641e65d88166d1fc763bc483f8fb4643339182473a -810c6c46945ad5b4f699c51130bf204e47c62066fbe54fd099c3567ca79aa8aa8b04dc5321c09e03df4bb7c9b93857ad -916d4b23adf202ccfaea7dd124d28573c73b39ebd74bf4dfe32a366f9dd48f4160b8cb0e687e7dca887c4b4f19570cb8 -b1b8fff52dbbd5b9bc6915ba20f3185fa8e23fe52c026a41cdedea5301dfcf6c79c4fe1058f3abf280a00c7b2cbb20a0 -95f9623510e12ddc6f4ae59d06448f496cc911c99a4d5f5c6ff7e434b807fcd4b35ec1ec976a40208ee1a505a892e38d -ac7217596d42d40380fddef22e83db9e6d6b2d0d2e912f868d7fc07bacfb83e8e6f01af544e8f450d31db014fb094c9a -b10855b8ff1a81ac32d81773ce8a6391169902290af0637038b58ab59fc84e3403d515ba7c99e26b7382c2e2d0edcedc -89eebe9789a333f5db0aa9e8604798b15a934ff45e19699c2e7fdb46b6863ce02defcef9f6dbd0cb799ffe2b669428c8 -b9cc540b405c5ec78a2d8fc17ee4a08690e347cc1d860885205bc19cba09e62f25b94ffc2cab1f638c87caf217f7b6e3 -b16d06b120906f085cb183a96a2b635334afda4272ac650259f23059407fdcc8b83e91f2521223f79769ba45428c04bb -83e0a2d9d9f6654d916a822ab1725d58a10efd64e889a17f44860db4d2c77ec1bdde7d0ec8deabc12f8ffa5af879d4e5 -98cef31d7ee167d9c4248e29402ea8d5546288d1b7ca54a5370e80a9ce371bc4aa3f5c7a24c2e4805d8c99af059b4156 -8fd55a0dc38b65c2b0b45c9127c14b9396db4898f14e1559e428a2951cb5076bff9e3f202a83236f15c1d2530539e5ad -b3252594c3060118acb12eb91d002a74c068c0b8f9bd735a9ecb082f787c7e046dd6e40ddf4b3ba56bf89f223bb5d76b -a88446262600f605fc4f067dca855ebc56990a9ea050c708961e486fe685707d9e9ca734068b92778a144c0f3c23b4bf -97beed96ba821515996045a40f17ad46f8f4d927cd9a2c7ce134a60d19ec4a5819a19aab1bb0df886d9cafcff872bcea -98ce98dc7908161ceefa0ac132b63c860ec2e53f7ba28e66c6c5e45c5945e459797c65668e58c0a5b8a26811f17c3f41 -b0419cef96d4d44fff0338132d53d2c03e7e9b4618dc2c6b9f4475368e21700fc08b844a2f140158fff81f56aef83b7e -ae1eba4a4a715f6d077e90e9efb59852b7025adced47fd9f705c2745e6734f2fd2f2f86f07ce24695a06e24e63f00b03 -86db2fd15dd3cef1e504fb057136f0405758f6fcadc391e6f64b3080f92bfbd4537a0d8f59cd1a0e913b2b188093feb6 -b418cff26800f8793b083a879c8b1823285f7a3cac6fa34cf48ac5355f04f6ba74255eaf436739c4d26d0d80d2607129 -8eda3c25b5699569c03b85bc585acf25bc3f9539e9dc3e8707b34520ae5ac53920f45528f0870d93f84647cae36b6aeb -a2622af11642fb6cd60cddcd4c242cf13045f4ce20539d11727e8942b4f9a7fd1ea2192e83596a35c096fec3658c0c2a -80735f92d09dc0af19f593ea118bf52146143c1d2a7343f6e2ab95e00debfbd329d4e887f7421e4a361d815dc1a27973 -a7eff30a31db635e239c8632f7f84263c9a9d82511422f49077823aeb124e6ee3c995ceb846902fcd2cff0f5f219db51 -99129aedaac32b3ec18d689a2589e35fc9715fb3f1a72d28a09ad95e39a68ea939ec5721c501a9e35c60cecb3f4379df -b9995d65636ce1e70967a8ffdf45e50eb264eb64f15ee887781455c5472459cbb309ab58b1645bd6e8f2bd29e69d81b0 -b8049f4c3ddc22405880bf55b5d5d94a6dbb071485f25a49a6457db0446663f8d4fabcf14106b9cabb1b3222d8786773 -b581027c7d9bf7b97f6eb085934b9caa43a46368cc6740139e33e4cb2c94683411710a52d5933a27c9d12a43e75163ae -b5dfce672e670158c259f36fa549aaacb0699da2f13702c81f5a93afb00361f9ca22d02dcebeaceaee6813a3c9bf7aa5 -b8184f3eb809be1986530dffd7464d84750df02196274955769a0afa02b65e87686d915ecdc7e75a0a76be8b7ad8d064 -b7ab837f300f4aa2ebd2d770f7a36dedaaa68e1d601eb36a28fada4dc73dbd55e7f31c88ab2835aeb57ff113a14c5f32 -a72013c811ca674c3e909064777df1484190fffb0643b6b1435892f5dd0f1d09579189fe00c862bcd18d03309b958b72 -87fb528e03f1b6a000141f4a6ee24a9738d9d2efa795cc262203fec10d76adcd0f89968a46fdebac99af8d048300b8ee -b2a1ca5d5d16c7addb73341ebed1f8e832250c2f8e03915a417064750d7deec3289e646c06a09c6a3ae40ea2817636a4 -a90cba4d0928da2a5d8c6935790e1a1f026073632a4c1460fe686d06c3f2933661c2b3c49bb0bbeef386f2bcc4d08485 -a5b684d544500be25136b0b5b95d9f363103a6d08cf49f4934d6c96d43720a79cdffe66698de0ffe5b02bb3c2e30286f -b246952dcdc38a500e64ccf4f312bc7c690d33a3a951fde5f839f6eec77ac78147f1fcf26ff7b990e8868f5cefe1c4eb -981ed33458e8ead67d4adeb884153bb0fee0ad98ebd9010ee706ea1da7975c290f82c492cf16fb42d1b739632e66e50e -88bdec223786c894fbd8f964ab2c92c5ad7fa7ed2b97a6bf31423a6ad5bbb5a946ae3cebccce8cc97af9e788d03f547b -ae852b074e5716e3190593e11fb17f1135d7a5d888986d2be53973fa14c1d4a9887381e648a10a4725291ff062c9d88b -b87050f914c4f09e2dfef845ace5a06504b6fdb815f685921710c7e82a9fac11f864e3e6023ed5807256d6269271d051 -8cbd11617ab819680cfa68e70e205f3ffecf6e469d88dbdb1d9b0c9c7c38746dd6e64bd526306a8ab59cb7e66841a757 -a1c51cbc1a91618b1ede5cdd77fce26b04971081e5cbf83be20c22b9b30cc9197b9bfd5998fd9ade9b665c8218afe94c -b5cdb2091d114847dc14a4c922bfe944021549df2d75cfc08ccacc2d740726e90e20a0bc2bb73303e9f0bbb5192fb982 -8e60327955c5de97f56838cdebd24c2ed4021d9e3d74ab9eefd4543a286c1be82a1e8455f8cfc0a17f03358c4648683b -87f9c1c0987493c631279112fbc79c5f5d7dbf46544119492785f444d063fcb0da4f2d1129735ab77663a9000d9e18ee -a970df3d50c4ef3d76d53dd2b887e9274fdedced7a83560eb1950fed2075879d9fe1d5af811f04ec92d557a0be0380f7 -95a69bf4092567f5b55a401329d5a08220ae65825f05d56043974fb7b7090372e941a85e2d197c46c9165031b3bd36fd -8e62c98171e54ff549ccac5d6d381291d0861439dd24e584d356a862d22942e0ff17cdc0d1faab07e496374a547ee812 -ab62d0eed8422a3172269de0e325eae9294914fa67f1ed8e5d0609afa2991a26b1e1b9a04ccda8436d04ec085957b110 -a3292bc88e2a9dec7b55ae4c27a3a8ea46a7b2dfe3a817675eb3712f95264c08668703771b65afcdf6d305e396d5f005 -afbaf9cc19adf63a0716cb868a970a372d7a1e24a4c78718a114ced412a12fda6fdf42f701ca1492a8f8c1ef0466f7a3 -b41a5f064f9d900d1534a68c74796927e4018e23f949d86eb76dd5b26e5b686115d63d858a49b545924b3941bcec2341 -b4e1ef520119f9a238fc4988ab2f1266606f53079744b92c1039541aee78b67ac570d7839fc9b2331244d734ad4637ed -b0ce754a33a506174d5feaff4e9a79295c743b2a122c8a1788c1427482585b398a750b7bd93cc53c38bd3e557caed172 -9842cd13ee9490d9ca7ddc83d1f7d79495afb7301d1f51f4b007dd2b2eaf15abbff18666126adc25df5ae26b98a80f41 -a976af142268d20a248c4b71304a878efec29b5022199cfc88bf82c081f55d06a89f178606d50bd3f8576f0c5c01a6ad -985ac6f315ab1d2db1b4f2b107eb1652810e63e36b8c14e8852f072d2c8b14922f20d1374a57d75cec62db0d050a0c7c -8c1be9e8317fdf847a8131ac14cedda922bbfbe15cf95537493c4e7eccc7f2f1a56ddd1a8832e6300734d6019d8b128b -b55d129c88d252556fe688f84982becce253736ef3b1fb88328e41300ed0713465c8bd15918386844c725fe7a94e8364 -a96384d2d81cf6a79614c7fd6bb68fec6e74064435a1a79dd8b1533e9c7e578da5ecf03e979969d983da893f42adcd84 -8c2b3c06b7249ef5ecedeb4f2c65c0925cda8877bb4b672afb7a15bb5a7b5818748d6b022c6ab8fe9c5a1499e2037c69 -91c8b2b8b204897741124a37f85ddc45c3ef94ceb5dff681b13771e712f2ba5ac95cb1bd2d3e94a84625d384b51b099b -8bf852945910e9a773120c5ad975f080c07c8fa37c2158e1138162a82983211da70f27e22876741d58c20a6c9dd770da -b9e907d9176a0fcba87a2797651765c814df756bbd1d0a86a9b7b06d9d886d1908d4e74ab27d618129dcde81e7d969d1 -ac4d3b156db2570c349e21f07fd17df935872f9687842035b533c6e4773ad5752f4ba8f9ea4501953f6b8c4232a4562d -ad91c4a7ea0a314d7d1ed7a69a74adf6ad810586c1bf907ae9878ee5f6528437c048c6ae785cc255707ea3e58a4b452b -8013b76604bda0c429e37006b01750999414100d0ff59ff5ab7b233399adaacb34906ee65054abb94db80fc92ac6d2e8 -b26a2a660af34a4b9b8910463d0dd439a3dc563494f5ec280dd5eec0b14b0e9426a0422f3c75370201299d394c4d90ad -8e1c7ea11dd513fb8527fa99b899444bf89a1188089d3bb65e3eb87025de9a48e8b4a3068a955fe752f2416de282ca20 -b6cbdbf2b143330db09841aa0e7d22d32772ee62006e7cee13d8c4ac911ff4a59a9dba3d84bc46ace1760353d847bbd3 -b8f5aa3ee213a44c41f63c11f685e754997cac37b27e91d07bcb69947344d94f3b86284b3b1655e168befc01c880d550 -89f93b37bda703494263b10768118ce998ac1f395d422c0ae840e47c6d649a3ec59b404c164a1ad5ed14ccc2408fc662 -97255607a1aaae89530a3bdbb7f2b7ba3fb9d5dc93509991021152dde08a638bb3152503cf0c896c9c19d61f8eea36d7 -909c7ecafb798e6aa45867976f59cdc9d219aca6fd0881f82f296a83a2a3cc5ed47f08794e6e3009f8847f16345f5f4b -9560fbc2c531571eee5b7389855117644f156ddb00b23a7c2189205d4cc613ec83952b96e941cc1e725c2b574c46ee9c -aaa69f68b6086bd369fd92355f3a0bc632c1b1b4284529c18a7cd4d71d827291bc997ce74bc92dcd6900419be68efb37 -af9ab7e6a27e61a99f37b89fc816974ff916b6a24ec3aa31d76579204bdd5ff01a2eea26e76188976c033db4af167db5 -b026dc8850af970d2ffd300dce6ae07db0ca2d21978e4f3a6797b6e3e81f1d9680465080a983c31d473a77ffb62acb5c -8f82f92ca992ac352ed1e8fe31d24f8090ce6a7f02d6086720422b9bab20f3e3c38a5f63c7fdb193e30d63f08e53c900 -8b896a2ae84c66109c8501cf6070c4da65c43ca8ef9b6b06fc85b6cd92bf2e5397d492796c528c7b2cf29ba93341a87b -961bf4c0b8068c8406a864595e156004d427138e06b390519cef53af8eb00c748bdfdd480521c6aa0d53a78e8f806217 -a6fa456250d20c6842dde55d3884eaecfe8a39f546cc5e4a77f57907192e849a956a33a81369b0f2633c55bd6608eb63 -b1d1d2f3e3e058ee97c9b6246cf073236438ed5e782bb21c68cd0d77b44f29745dc24d01edbce4437d93071b6fa6e0a4 -81a0bec80ecd1b1e72256ed5be7de8deb11046ead7a96e1d150573f4d896e642b4af095735343f6831bb6b7f4037cfca -b48d8e15fa8e0b46937637de3c727157f8073eb8a9a04bf127e68977758385a791da2e9c69fedb89b334fc638ece78d3 -afdee0774369653bf371b8820e285e1b48b40745a44d22cf2098b630b8ac95796a74f79337cb97fc60b6d6b903a61321 -8fcd9ff2991902149db29cd4674d60387d4f65397891fbf91b7699a42f579f6b0afdaccec70e5e82d1abd81de859183a -8af5c73367a8439b2e3e5f1b65e00ebef2eda640bfba2eae48582cdfb244e1b1cc540bc0ef72f9e24399affce1c3e222 -b58cad4da101363bb8d6e8cd0ec7c078f7719462856d7ea573e2bf95e00cc23020031901bd1f2112ffb90d847241e5a1 -a671f7fe2ad81e9e0d5e3260a9dd7808125dcebd970877b000bdaa3207ca45ae1e5458d5ab7bd69b2adfca8b6abd88d0 -a8411cde9eefe73fbceec3e5e3628b159ca4e4c19385ab50b8d7a482f4258f405c47051a89f11dbedb2b15e84d8bfcc9 -b5dd09d5ebb26e341b6df80e836c6de2305ce4941238e3e96da549857ec314b1658f8b03ef069633625b6e4bc13b531c -81bc9bc924039fcca8892b40aa9fe8f5d6f305343f6054e36647d5f14cad3e4d754dd6ce9ded67ae65825adb4e16df31 -935ec74c2dba94b1c5ef2060c31bb5c1426965f68d9f4125cdd891f20495da9d5dca513f65bf3e8c599f1562e81a0c1b -b9581e11f361097620130e753d134cce6d40ddc7c516388fe4c881fceadf738f314d241dc14d4f87be8ff0481e898c4b -b7be50ea49e09d10cbcf21b6f717e0cdca582d57935d72d17e62cdd7bf2071e5d5c91ad7bea79476537e515f0d2fa5af -ab467b7fd32a795411e991417be57af8b62ca199983efc1f744799136ae5339173111465e91083dbce60e77f9f2c0fc6 -b99afb338f747ae89e7cebf069612e22f9704f247d66548d305aacdfae395609a57d4d5405ff0f1eb1045dca4c3827ce -99a5e52374e1c55f65e44951f68cc3d607157e60d52cd088125a81bc60f2009d1b894eff8e1efb175509aa4b57af7276 -87e3323cf6f11b595ed745a9475a6d99d11333043d512bb61d5f9d8c3f0cb6957aa8c3f041688f63ac13a51df29fa061 -96a5f9ed28056138439eedba186b754f5f7693c09422f42ef82a315b7413b418c4971112f4261e1b9793ec9066c3641c -b9b5fd36d2d861d40b947c3c879a42fff24b9ee346163e544ce6c3301d0003cdb47218644fd5f1f7f0d6f19bf647ceed -a8899296b58e5d56d7da438ea48bd76310364ffe666d698c86f20683343663d742a0b3f8c1255e33f1d424cbf61bf1e6 -ac4be82ca78df2a367f13c8bd1cb73a28015853f2745e025626c325a10b778cf4bd9942439e35015cb38504bc02993c8 -ae5d6b99ef56cebd5e25a9c002e9e80c1d3e8e5fb5dcefc8ea7b7798c7e09b02147da2ba14e42e2b6db2b2a6a738f598 -8c94abefc71d245b0bf04f34085da0a9b8d4d798ee7441596c5166ac353425175dfcab0f76bdabab8f0ef5a2b453255d -960ab6939b1185806e9f985c9381206c7032ea8a7a99eae5a66f276ad5cf450e654a6f1e956a2a63f33d6f715064d051 -a4c7c7d0fce514db07bae5582f5e4f7a05d79f7605b33fe2a1ae980bc388b31c056438616bc8391ddc7dd5f98810c74e -ad5df00f96ee6e9e1ee65b562d6311c38bc2a0a25aa9ee36f39766a2a03141e95285dd2850a598385f45b9935d63b78c -b051de656e37ccdf3844a6e095d3b42ea9c5a545e0dc2a5234e2016570375bff6b55ee0dff04ece5713ba8e85629a7da -ac01fad1ac299567a22da6949a011f429bd9775de956dcdc247d5c186ec577fbc12a482ebff3a4ab18a8e35f3e2218c2 -9654db9c6b5e58e0b68fc49718773d44129a0e77bfeee3fb56d27c282de6b75fe9c10f4f3b5d3374443a9fad45c400ce -a556631390e6cecc2ebe390e605e6fd754f1961e4bbc063c31c08812e0993eff5b5b7449b9732bfd3a22c87f9c528743 -b41b7abb971e253dfec3aaec4443e875d73373c70c33e9ea19c1176f8cf1278c7716a76a4eeb641c142b2c6c1ace5db7 -8bf37cbe29245c5e217a48140d7f0374f46596f2e82c1144ceb41c9801211869b96d7f1d0f7345233abcfead0309cc3e -a380a799b80f1309ba326f26ee46ba3081b12b5a1143f8289b2fa067aa3ba80c3690fcefded8534a80368799b71ee9c1 -93dce0a2aee4d67efec1b284142d890d1e0d7abdbbfac82f90dcbaea94eef829645675cf17050af7b2e504a46d1bd288 -b8e90f54bc57ff52b84fa3fc3c3047f379c5587ca18d9988c613a3bfe614fd5fc381106729bd62eda298faaf17b10210 -8d8e4f508c284c52a6f907ec39950235c9443c5c6046762911f4818b98293d7d60a2c3f94c5cf60ccfeaeb8f283d8ce1 -a513b66299ba5104ba633cd68121b9ec848e0c8c5252d04a0bdbab5e3bfe6ceac93ebb1ee6f0274920d84eae27df1520 -80e2db8b919dd2ca33e833270738b1f437ae312b1c53a73106b6d12672a395fc3b941292fbb019d40e31b8e96bcb85c5 -a4c28fba416985d47c947b0669cc22153ce887ec54535a18cf457622d03120b6aca71a45fd8704166f6f7a9ea2e9d608 -850b05b9c7e168a83b0e0e77d16181a52d78aa96f4026c4420824cbd44dea9f27f3336b1736bd545bfdf548eb3f4276c -8efabbd63f3b9ae6111dceb1cffe45dd23f1500f87382816d4192161a77dd0776da2a4463d32da85b802ba7299fa726b -9426e75c6f7fb77072773a2ee03e1e3f1d90878fdb5d8c294265262f5c1cdd74a7aca339b46af8a5c43823dac7e57edd -a1c4d2ed335a3c92d867c5cb999b2b807dfb1d45e35b3960dfab19da43e2d1ca9a8748738380cefd137088d8b80d3006 -987a7e22092931f39f05f5a6b38f419750370a71157d4443510b61fe07ac5aa31cd7f88ea04121947b1c0d0419d2a25f -ae73cbce7cda7cd90404302388d41b49ed7d7f505a9a406f0317fccb29e32a5be61a6eb0951657f2d93abbb497be62ad -a1c7cb4056984c22a57ce76272428a50fd33f0f7a68c29c9438af05a87bec23d8de72062fb4829adafe597a278de0c01 -b72c81a9a747a83a650b58ee01015a8882789983b67ac4f2fbedbbf47dbe30f04f686877d8f118b4634289866aecf9da -91ba1797d6913270ac1cb9c87d9d8440a651e294c45b2301ff8c40416e58126318f0f2d411b7d9c09c8e19f4da8ca0ef -864107657717124339cb2ec06cdfa75fb9c4a7ad5155cbdd03d155a7f9e9026e237d7cf5f4cbf07239e7bfbd79900957 -87af853a334b8cdd10bf5f78753b27a0c9aac9f55db7570e2d9d42f13d0e2f8bfc4ca64b77b21e478f23385f17eb4f6d -8658227bb8733d6c7608d66a748caba761f28da4d95e70506dcfdc18300a559b4a84d11a9a048e82b292eb1b5d88bbf9 -b078413570ead3243b9666c109a17678fe60dd1240caf01d1d344de09e346015cba7a40560b0d68b18df82a0a37ca529 -af6dd12875a891eea9d846aa660a207a527d08f5959976f6cb7585a98b1133f341f4ae29157f6ea8e0500fb6b49fb9c1 -abc0fb42239fa531cf09f7288fb00f1d1587f2a86503593d481bb19b1159a6a9d6f4794565fe923a545d45b058d3a74b -b95966d42c59bb12029aef1da7fd50e9e8aa9ea287649ec3ba44247b185b485260af077e0d755f322ee4ecf8e2c8137b -8b1a2350f9bb0d6de377c00f0897081bfbaac5d47cac852a22dd8a427fd2e3029a1708f452e958a07236c7f35ddeb565 -acaff21e9740b831fee42d80a9a80cffa6673e39f85b815b4f546f538dcd803320f90f4f25436796721c8a11f5a1b25e -a0dd42f019eedba19f4345553965508aa9d2eb1499a363056d95e27f7083c2343e74a0e7dfb101567250148ee1bec1d7 -a08d1b1863e594bfcfa2e21ef4edee8535c8ee69490a4113787899ad8cf2f2ebbdea54de193ded85af82fde074ccd0fc -960912b621ff08e27781a4f9b80ef1014a4064fa3c96f534b67e5a094a5c11d9cadb2b69cd2011cdddb463f2936c7ff5 -b3437f1e0872f6b9ec071a951f26120f27425789e00c1a8d3183879ed02e3b017406c051f32580b78b4d0f090474b42a -a90e6d1b11ebd1f1dec54d7b3fb336b9a53c821f295a592e147d5fd453d66e63295a96ce827c4ad64c37d4bc0df2c7e7 -b357a785f3dc1f9bc1034da77033c0c64b29b78c7381ca59ef81e24ab14448d67dbf84756ea233b9e3539b5ed517d9c3 -9360adb42210abb9d7644bb95532e1f461464446e94cb5047bf8ed5513398414130630866b6980b6afec5401e608f6f5 -9145a7f8b2cf1bdd90b9a860051eacdb937189e8d68793e52bed202fa1e23a87db9c51a18f0bc050dfc3c600780099c3 -ae086e289e16608f02281bbde5a6fb2479e3151a2464b86ea737f8a43e15af4fe781312d0e5620a42a096cfbec885b0a -92b57fb14a0c567a16567f83e72b03b8b564ff6d830a5776014167cea06205579dd10715071097710dbf50b660b9143b -83e6a3f027163e635c2a1a397d2661a2d6c72c25082df129572082db29b1587c78dc3d2e5999112983a040ca46bc983c -b1667d022c8099dac5af4ce3b4ed6f524819240275725c7580a2386f067fdc9b3a49b74195cc6f661212fb07ff133463 -aa2eb0c44df0a80047eec28a80440ed5f363e3d42908506bf8418bf04e9c17a5e9f550bec9c8ab8dc9979736ce325780 -a2c1d257de1a55e4c10879eadd49af8950b0cf25121e8d7de30049360470aeecfbef263739262bf1f97020c6b025f9cd -af29d1afc9f76417e4396c54300773fd283f1bc2cb00308da5e6b1deac7a48cb117c0e8c87b03076c7a1b8414d25dc97 -a44d4f2186f5d728fdb224f10b496c9b57d96204325c452842423cbd29bbb2d07e98013a3880c7dfd63ede725d15953a -a30c45d1cdc68a5d5ab65b57d60c8b386be836c5bfda7e2f0347229b7807f6a97b632bf54ba3711066bcbd5e0831e5bb -a8c3c93d6a3526270ae47bc2628da82bbdb8b2c8e4d6a4cb5e9cf70b49999a963f3e856ff9db12cfd2575187bec668c7 -a03566f1a99f5b82e8243678d0bb033441cb8a2f160c0c66dcebd0b6922a56f895a69b94a9c65f4adc9ed73420fd30dd -a4e3c839a6f4f4317e7bd06f25c5236e42fb0e54bb975f18f0240bdc214780049f0258dae24fba6301aad508ef9abf69 -b7e0349d89616156679d06d1626f45dbc9683ad73ed91f0d92f8f82cb0ea2ae8d3ba3a752e73a39da70569d41e84015e -8c9ec5ff6be4b0d9337c5336b467c6d4f552af691bf083a23f1f9856e18b5a13852143dabf03869009febc443b2edbef -a12ff782575aca7b48844f0402a311bcb3e19514dd4d2ba5b39694c66846b22dc9ba25ea39c3c1bc325eda3afa1f00b1 -b55bb586ebf5c9a3c83a04bae254e22547f37b9090151d96f5d8aa81be17bb38d2763a08cf0519a91878633ced6ce0f4 -b3957203932032fe180ba9cb5347c2c1865a3094d03f6611148af4094fa6a8eae522f2651780d9bc49b41f5c36054eab -a0c865b498e30180c48fcab93342a50ca1cddd8759d6e0bb54e9f92e7b60c51c373f7ab1432aeb5e5c2d3ffcd79e8180 -9503ffb3529c3415c07247211c2a4f35d8ecef98ce9f921e67438ffd538caa54520fc6d248a081f46221a0f1165011bb -906deaabf6e8dd0c24a4b22757b7681bf88268d9b4ff97f2844f9de825af511155d0bbc48dc4c03b87007be94f835d92 -96c2a7f48990ecffccbefe128a28cd5b26c664b8dc9bbae16d857f7efc1b7711c734ba7d1476945d09ace569297ea96b -a37ea083b0a61f400b498ac5ba2360c22e40b688428ff4a02e3cc80206b61061bde037cd52d97eeca175394dc675e216 -89b15c3af439769829ca930fa83c47afe070f6e2d7a7df88e5a4f3a2c0630f9d143bb3cc43ebf9bbc1b91be03d35ffda -8eca6996ba407886d3b9d2e4b1aae1983023dbb1c9ae47b6637458c73ffb7f422b0a893eb0b07fea2c5172ba335595b4 -81df4d7f576930b2865af5ee1525718a09b65d9a013feafd19cad335e4e425485531807078b9564c8db3bad95d23bb0f -b6635aa3ca31c851a0283c0c6356235a5d8de9d1db9780e62087be32089c1c081bdc642f067224e88c14252efb960e3d -a0120e81025ba07848ef24ca9a94699db5274a8c85eb9c2f3b41a81f630d09d100127154ddc3270525961613a41ed81e -aaa8dd063f9f4f73f5a7c440671e1375ca8c224f8f869af736edcc435329487902249c68ef646fbf71c33a8bd1a04d9d -a36bfb14bbf3956c317e01fe744bd9c6c6f526a3881f6800592501ca1d9caba7f81b3b54f53b2ee1b13aa6de42ba06ec -819cd123fd793c0c9aba75aa96293268a4731c68c0a26a52561a695fc4acc409752de84ebd19494bae70849ce538138a -ad4e50ce325477621b6eb4d453b087c3d7df6e3d019ab41239f2ad0615c6030aeaf85e0e020f3e6c89e46b8586b4a347 -a4327072fbcf33be1e57ee4bd5db4c079c5ec11694a25fa2fb30932f8a2a35a63183b24d3ded7f6c8a8d0ad111586dbf -9454f17aa8fbdd2b15dfa6600ad305936a37b205eb554c915adc43aceb4dff6b0d1414e61584d5b15265f2ec0c85abea -80eed3725282c83dde575620bc0d86e50412df5dac3b3556d1e3bd9e7ef6f56dab202f4dfe4ce542babd49c1fa7dea5a -b90d1a07ff760daa23b7408b067c322f126023389beb7bf373f0c68b85ba0ea8a2c03e77e6d3339a01ed3ff8ba51f1f6 -92789ad894995ba07f36a0814fc3289810136f9dbc6c70c57ea80db464772d760b57d5b059d4ed458f256af7603fa2c3 -96a4ae1ca46d3b26029767e02fcf2f623d32c952712badf2a2af721226473f4875c40d5b14e66bf961a5a56aaced3aeb -8c5073f4846df9a0e057f52fdefe01a9b8c9ace91ef5ac253e823e165ae698e733eb936ad9cb04d2c54cd8570f328c4e -a9f36450b5ca66a20e52bc196620852a41f1f40262a2e12c278818b6071e6972c3cc6fdf83a9ccf586db6cc177173cae -8f101df23aa7e353ac1034c38adab8f20b8753aacabd10d70acb41d0fd0b1f34277546b30f64d0a861f448f112e38acf -b45b0779ef1ffbfa86d7e02e89bba0316c5ce60742b350296eff0d04246f1c8b1bf5bff68bc97792c85f1e5d4dcabacf -b7e89d015f6c7122a2f35f1c48b43eb0076ac4269158d52e38bf2a11de11cf2928175f717ee5c1bf543ea38945658558 -ade2a57ebd7600929dcdacc290168443437bc288371ef40580df515012350f3453b09aad8ae9e64bbc3fe6a3456f2c31 -91c2f8de02bd8dfed1eeebc40a422d444e3459f9c33476b55de3e950d2c38d8463c4edf4d4f95347b0599a48cb2d47e5 -8f6e77d9ceec539e0407a8d75d4e855e376838c0f886b36615a9c7715bce56a8669586f6d7cef75812d84b8be91380bd -87637da91b051ad92081e682e289bb904c51d95ee1a6ae2b8956982093a7bb4f8a66d91874265dc32229f9db5bd51ba0 -94691811eb74f2970a95e9a2d64435952145f1d0caa76040f9811c9ea1ed7327750d57d6e8dd63c6378f336421d11093 -884cff4ebea1bb48c0d651bcf0a710ebccab9062c96364aa64aa1275e9364a4c261e40a4b9f7e1e135572681a5a7a965 -93f21d4b6b53cdc1dd41cb1b80ff73c0f1620db41c35aeccc059128704e9d1d7da5fd3240e7d075a2503273e7525664c -b9afe0a9b64dc43fa78f607cdcfe337ac952fccfde41c2e88abe3a8dbb36a51b3445d724908e552ba74bf67ea2cab56d -910280ba145bcb6a99d89d1526f10632206d2ca9e1a8596e5d181dfa37e5f407e1264b9c71c39530caa59894c10b371b -a5f583c9fbed59f99cf5e21b9a734de6d5685b9c33931325dd4b581bcf5aa4764c2a250924e7b6f7931dc5278bd17152 -a87267f2ad292572a1cfc89308c96aec0d12e5f0fc2b4135ff8df7cf83bb1e71d619906d415db5841bbbeb173868ca82 -899d7ff8d7f8d0daf62ec8d28adbfe4e7856582a23e62dee175e3bb9461f38bf8e4f73dffe10654a046573896f6de690 -a8f3601e6787e788d46a9d7592dd4bdd8ea8b5136e3c897d79ce560e9511f6236e67a85a35c59295428c1f9c019a0841 -b180a16448f085227a6f3e363b0dbcab285bf419d438a13be2cac1ac9f97973ff6b8aee38294f70a8d72bb4ff474577f -869038341a2f68ba85f5b2de58d2d794584a3c00a76ad0dda5aec31d4e3ee433be20c197b40618f89f7c8f1692ea3cc9 -8366f825dabdf4f7714c5d089443d0de315198e23fb93c3ed063c4b8fca0727b05665c04beca145dc4c02f333e300c18 -93291da32b501cdfa3624b39f6e38ed982c75c1209cd85630cf83288204032c0a90f013f1dfb4dcedee7aaf0fd95566a -96c95a1e73016fecc3483fc94dfaceea376ac700fd4804b24e9eda7135048e521daf96f8f63d5a1439950a64296d8124 -866429fba47fb691a4c39460031a7e614096abbca3073e9246babd23075e8e5f6051e424e47d860296ac8ac646f8a283 -b817f3d9985cf9f9657fa800ebd36a9622566697ce68f91c509d9ad7df8146532e24ad85c07f399908f87d1206c7642c -8761c3755cf5440775fe00081f79dbf59829f8d400adf7448188b97f756ad35658295649294ac9626c2569ab21a5df86 -aad65ace72ef89783507c9feb5555275d70a421a95f306b7613c894bc24e978be809410b519e9314ac56fdae0c71d326 -8ed16ed07d0e989061db5087d50cebfcd6983fd54be5062e333bfb8f6f609bf1b7b840c91ffe4b66fd674eeae2dd1558 -af3919bbc0df42b1e2e8f62e931701f7c35cfefe3ac3f1985ddb70212476112e8a19d51c673da931777ffa28944306f2 -99a364d8819b5ea0f6d900167b60063f40f9afcf291ded7adaa2d0e46f344751cb312df1c2113bad8d84a028f680b41b -8d970bad8f95ced0b0323f4b7b087efd0624ce21834b3c9ed435dc0a394cc2c7ce58f1741c1a64265c81654eeb6801ee -a5f96a4d794f6f844b38f9b82ee15c2441cce293b6b2ba26b25643165236db05ffa918ebbe20aa89ed2a8ffc8df393fa -8ca69e0006f6a72e5abcc32c3961aeeebb8c0a76d877fdd8a093467485c19662b75f2ad8c750acc9cc12c8fcbfbe9b0c -b5378b855f6ed3eec19546cc21c947dd12e98783164d95a95d3cac36c89a840bcb9f7c99b191fa7730ec28d57e7326dc -884e50d5e20bebca96dda539daeb0e15edaac7fc88bca254a7239f30aaec47a64f29b69fb2d90041b82f8ad8e3f13d3c -abcce1f6149037ac8d27497831acb867cd5e05f637b7579736ba5c384b8145f127c56b82b1876881b782b94a84d32d04 -8747985d53fac369c4a23224d50bdc556c00f406e7ab3e38427aec317ae7c0feee5b48b9386c5764de883cf296ed1daa -a153c77887f271316d5a7185fe0d2bb7359cad86ba80b03434bee8f21b3a5e52263d28cb9d3d2e6d5b7443196e03cf80 -a77b16b2b7b6e999144af6c919e0a74b9a6ff70de41a133f7f820befc1261bf261142717133dd4a99e168a5cca4791e5 -b89beb83489db9fb62fa32d1a8ecb66fe9ed41d318820d13c3e07e1c97802dfd7b05d34652a478a1deb3b17b4243a499 -a80200902da696d0d3974ab29676f0eb67d15166b173fd63b247a17cc49f56b6ffa28d9690841ed4865229248650601f -8210103eccfd1f4be55e33991a831c50260bbabc1f311564fc1c52c3b2755d3e4a11ad69cd95e398dffdb9a0f5b77df0 -9958745d00d8f29d05d97875746d863007b1c05d3ae920794e6c65adb47ec208734fdaed1b49982c4f4cdd1d3043c369 -94a4f28dc7a9d2dd01ebc2f3ed11a5bb01a2095e7c772d2753c022d991da7b2e4c80c2170209bcc4771d68ef8cf007c0 -a6b5c5543ae3de57e074fac82221590a8d771e93e22fffc2029b44e8a1c2c8c9cb0362416de54d00fd5420e5b1375eb3 -875e801265871509c71dce38005ad6423fd027206e6ab4c58d2978ab4812d5720401c1310b56ce9ecd95241a17ce0e7a -b6819bc6497ed57feb41bd82f56216b513085b6d1a560a958adcc06a6da304424ee34ab2580604b0e59f6b0091ffe6ad -93bef0806f21f8bac88a5d6e2e6d1adda06f9daad5cc3c8de61162495d8fcc3889b767a3e2f3380f162166ce40a0ce80 -a1f699cd7446cdb1321a05f970bc70cc98593aaf0145a0d097e60e5897aa311b00d019e09cd533d0c0b7cc5c00a753e5 -89ae140ad75a83db2903a93a3711be90986d08dcfe962aec5ea4ee69656026dce77821993c1defc4464442bfe7d44734 -a4110c80ba92f545a1a7545cbeef997d6c0242fd4d771977192269d626b35c88c361df53bb36dfa8ea7e40da68e45f81 -906786f38eb7e98c431fa2464048ac3f1f1df8f908a25262978327224bc82168f564b2f3e6da77f49457ce49c1a72c2b -b28d92b3228547f03a3f489e09070ad9a1e20a73e49f7ada96ce41c19cd6416ad809b3a3a01f141b3698e85c641d795d -a25b9df9b377baafc8c735a772e0ed9ac007c0b6ebac2cc0f8f2e799e5e6038a616968c9896cea862e99b1750224ffe7 -8085eaabc79a2faf1ed0b9fdd017fba1e46c671c6d8ed78fb089494f792765b0617f790016d8f55697dd0f45d17de4b1 -a0e81b557af74efb95cf94054264d30396121312c643052070ab53eac8e75075f1fd0b384cdf1d96bd39cc98681b2d92 -b8e0ffc7548969ae28beaa9d8bd65872840a03150e2140dd799d9924249f92d962a0089171bf4b311520ab527198668f -a6188827a500b99af6eb91094a0e464e394c8c0a6d80cfcc5d8be89e8810732a03ca75b2befd00d07d1dfbe7dbe89be5 -a4e5a47c656e74107e6007199b940d8381f706d5bb4226a0b2fb13eda725a556530b8d4876dc49c5f9631dc6bfcc4c9f -90330a50442db9a9c459e06d42cf7a69e009332976c3950ae7d9981d99066fd2af22f22ac429850b998f1ec929c82bfd -89dcc51fb717212b2dcbd0fa0da189e194b4ad5bf7f43ab2cc2c96f11c186d0872bd930aeaae01661ce2dd9f94eefce9 -adee914ece15575cc34ab485f2dbdf3979406ce7cd8cd82197f156f373beee6d80e5e3623d79a2fef14b0b4ed1678a51 -87e97e8866002364bbe9b49c5f2b5eb729c7018ec61dff7b8bcee1c1ea349e5e04a3f3781617d46d8fe0e62afe55d62b -b6b7bd0bc652a0bf79aeeea1767f0f17dd543b9de582531bb3e14ba2bfe1b720a6c6b613cfc295372eab9202f5e2d340 -a6f9cd96d8e422d9897d50bf36288bf4c09d28cb0f5c4e13ef7f76cef6c75bb594d0ca954ff7339590cdece16414fdba -b9bc319dc5e55630d1ee8cb48978a256b69c96aaabb5269bed8c5366add03a2c38da11cb03a44e150a5c7f34bb49bcd5 -868c36924f0056b3464bff8831543a280ced62be748d60f82ac860c32025c4589e9354984e1cedf24678374c959383a8 -a6244602362c09b382926dabae5793ca4fc50600193c69e645fe229a471f7cf9e58c4a59124d6d2dabaecf50f1e1fd1d -b42df58ee9e20fce589837d5ed8a938eb83a00c6ffe2f6afc973f6ce26559b8d220976ea1fc18ffbafe739c92dda6618 -90c0b2ed8ed7cd6f6ff812c84ed297b3231f6e2106f2df6d5e4b4bbf5378231025582cf39f35dc9344d9fad3adf04685 -a968386bf1221425cee0d0b926689426fd77e8e8bca5ad3bd07298fbbeef4fc676e0cf7a4f29cf981c682a78a54a2d1e -a3a46bb7db36e0294b509036a40875850ea5ce4e8853cc0a7d85e8455fc2bd7d5b593879408ef2f3b2b2bfa44aca2276 -af825963207f046b23534896086a3e56247d752982417047f850bf306d0cce285b537508747afc700dff6472fe3b5569 -8022af88981249b5da08ccc19e4ffbc35feb2cb5308b34064de4d5bfc8ff2b933363988c833ec70723e3b5107f8fbd67 -89687fe6e424c7f0d2751e5f7838e9a3fca4c0bca043806fe511442bbf41cb67d01165ecb662b1ece1b2adede5a9537e -99c925763420fdac4149a02131831449c1df8be4867a6d2d09e6b14abb821d46bc1fc4fc9aacfa4e9de1a93f9b56fbcc -b819ee6a0724de9c944ce2ca51ffd3f1d93c77ff25e39de8be2a612abe732dddbf2219e839686a4373609a560041291f -b5eabf12513e91139025f1236c7ec235368eb8586522dce04d370acd3d854c1e6676d92014b60ea3e4e21e9d6f063f2a -b82e94f1013db6cc682032c7760aca2a1082826d280801aad9c6564704362e61a61cb52c6f35f769bd8ca191e68e0b0a -95dcb02a676b17f20b75632c7a9060f990e44b0c1fba84ec8e633554f875ebcf6e54caeb9816267e84a11808d68728af -b0c7c401dcc019d2108eab7e87d6494e06399f6eb4fd95b8ff9ba4a56e549a3d3a4aff13771229f4c456283fc3cbc53c -b1a8e3e500e3ed74bacf91a82b39f2b870963dec0b98b7d5ccefa3212fc9f3ef923101887572e14d08145aaafa8da5ba -b2caf72c47870ce9f0524c4b3df6ab3eb3695765c010a27c0f3cda0ee1c1f5bee64e5392ef8b3f0f11e66bd8c9d4630d -a8fb4864bce5f1c48d681eb37efe7d9ed1a83ed36bdc1f2627539b92c90e100d4dd64ab664e404b0eb7b645a8f95642e -a1b6164a4f0467444fd56a1f4668c8d1f295f6e6f5191355dcfd004c34153317202823d72162b621f677c970a3f0bfd0 -b2cc59a2f6f3b7e18064720f93b28801fb684d98ee808ec5c04a5235dc40372aa0e0521410d8f736161470443bd97ed7 -b5d9a823649c09151b214406189d75d7f1ca150cc7431d79b7d60348b6d7405014a44bb7840e35f9c0a634b4c6785561 -af6b8229fe035cbd6a5da3a3aad93e7ca5ed233dea5fe4477dce46ed17bac9243ebf25a8439ac2896c41baa671c0fdfc -b42d9023551d999d2be3ee51f6ca82c3b2d41fce51e1dab52095af6d4b59edcad70a1f9b1e71eddff894e3fe35a1f11c -b868543c09fa9b9b990b276ddc5b68a2415965d3de71b9ac538c26a6333543a7c33d0b432f57756ac0077d0021878944 -846577a8c877461a58a94c5829f2ed9d7ed107fa63a48ee77a1ef1f1d1f940b2605fc742cb5ef849e3cbfc86942488fc -967ca22cc8c21382b15d73b4dd4f6f0a0bdb2056c21e3c75eb3d9c13dd41336672ceca03065d8cd1062389afa4726974 -8e0b872d766c439f3f868f18ef0c173896eac883783dcc58917f76d5a2e8c291967a032d254450fa7f9a12fa7d7a4cf9 -a0236eb36a4ce3b7d649ff02de9279d364ecd5059932328230314ecdce3278c42cb836f547bb9da9de0fc96cda2fbc7c -92eac5a5a88648e6d821d3bb51b280fc106f751d85a1742a6a1ceed071eaaa215a0a0238492ddbefbdcdf2e38e4149fc -88e1036f9b20a2c4b3534175c93d59c1ade3fa6652a4c5c490f21f6c3340769c7f8147d53a92fbfd84c23d7c4295cdd2 -8b094165ad429a339f12696bc8967ca89ec47a4778f387e42e273a1863a38199dd795d120d198d3cbd93203604c6914c -8f8013229eb6bc6a8f93c17d3b4a1b206c258f14091c6dc39cb1ec492d403cdf5f696070ef5a6c0ab9ed4ec141b08d73 -81c7ad27bd7a48b444b2be3d4b5d4845743d6ac4857b061e659d7ed48ebacdeac29cabd0cd163f3fe6c5cc28753148cc -91c8a92749183e3e6f3499d3b0e9b080109d5e88ce8acb03b35f3d04591e13b4c489ae323a149def1edaaf62f93bbbe4 -a6a2d69f012d877460c33095924771065fdcdddc30670ea84576b72dd3f7769f90d1735f8914b6841c7d938a2046ff4d -a8ad4b976a5e4477a97d48a3cfcce16b358fd3dc1ed1df301fad6d6f0e188782c518796faf1465e52312b47bd713e2d4 -afa2bab9363187473a85f7020106b176903bc3a3e3df1f4938feed5145b79b66db8aa608cdda554166ec47e60fb34b95 -af691bf473160cfb84ea517702f3c01daa6155f31393d807c897b39523448c5af09be581ad713c76aba194f90895cd9e -b74f3cbc198c9e4b2c7316fffd57fc749e367b7d1cf81b3f5311d266c9a3ab9598075ffb9230dceee230d5f1bbe3f796 -8c28d21c49a15299f7ff3eff7568b8450e6404a168554b8965a291c03fdbbd3dae9ea6b9760869cb1f2e8c7206183195 -a496a0df4e79827cf3bec117b92b5b248dfe129d783841935363362aee4822399974e6c03a92797b3ecde80b207fd7c0 -b39fa07fc8f4be41588ff5560ed68a33c3020bceaf172fd11e0c1288ea885c6dcfb56a151e4773e57d864dce06fdbea0 -990cd050ab056ea447c114217219d9c0c7526803f63952e22ae60a3996608bfa3c6119a56befc597592761e3a90ef448 -b6f02dff3dc330daf82d1edbd4e6964d2e9c38481e74cde8d9d85a9e602ed22c4fe6c9b6f41ec76582f0a4e4414bf300 -84440e4a7146ec2f34e8099e85c09b8d7bf505a15638aa34cd2b42a20f1f335cbc9f0e4fdaf2e53fa0ebb2dcb00519e7 -af389aed116fe58580810fc474eb15518dcd9746f04a7efd2de44c9774824db79f8ce4c4fa108e7396e1fc016132a402 -b202985e01c62d0de1f6807fe600a3b81fd11f30f5aa033b1e7baf7a62f34fa5342d42ad6a6e309560e3e9ebc662920c -8a07641140db9701c676b2c094c24cd663a5a34d3534fd4f5f1e38ca0c46772d141679730b5d0cd71d056c257d9a125c -99dc01e76174370a741e8e9ef5654a3a7769a010da85de41dd315b674ba8786e6a697b74a79ea782a1fcf74a48e51775 -93fc897841609670a1eb88d4e4498c54e286e25238309fc95389b16e4edfb82b8ee8447a436893c7180827a996b9a0f7 -8e2dd561acc8954a53635c0108ff964774fe98d12b28a0c6ea8b5ec5ea3523a45b81ec642c1453e3b2a1c0e0749562be -a95b0b7f9e53720f4b0394bb6ae8222aa5be00a2050f59ccb595d50e0dd9100e397af9ea77b0335be02d1713c361357c -8e21dcb67da3eaff5b950f989939237e3735a31e346e1bec8e6ca11edff5223e33c1c6f2f79da975de2fd86dea286e1c -ac02cadeba36143767bdb8cd4e1caf8cb287296b53955f33ed07f771a1fea521fd64b7e153c90d5e270c12ab959cfd24 -af95bca4016b2ddbca61c9c854cf999ed59ab4b5d619dd55460f20cde5ecc86081a2586a7eb37f15c20280dd06b65809 -b7d7c81261e8c6a8983442e1e801f5072bbada1eb2e49b8e90759dcad653c52c0afdff9cbec41bf21cfe832e49ef8db8 -97fe8c6d071dc80355bf2a74c15ecb16c59bc042eff323e999f4fdc39e1209803d32622c642ad25673c84761f0d357bf -b37da716119c00a0955a7fee59b93185a6e325bc5cb2a7fb35681fca0688d0ad2d25a0e40dfdbec1a11deadb1cc69d47 -afb8091548179fd2a17d95ca47909d97866e4fe54099736e6414682ad083fce300e0a20dfe3a017c1ee4ee7d271bc470 -9306ba1f3f2f74964dfcbcf9b87bafa44b5e013853c46cb501e10409f3c2af7269aa17c8cab261fe82e52a188ce0d18a -82430e3c25970411f40aa72ef1cda5b2b51bbc7e243a1b4951e92cb56a2f5b200a039f5554d0d1bb44330d89d1ef8840 -aabfccb8f3dfbd4012b9d196448e83f17bd1ddb8c857dbf98e80ffc60c1af3493ac5c70e3a2f1f26352b1ead143dee87 -832cd6dc83380d068c068d815ad0f4677de0ef602890835b8d32b73223490a6f753092d651968cb3d798cbf2a227960d -80e3e7f0c46fe5d962322f3fb2535de40dc078db80e7ef57923d46b742a8e4d6dd35ef74234f2b1637a317364d57abbf -9306bcc29d6f8a478ec085b144161850afa29d282cec756d0d3fcce6f4860f4a4b8c8a5952cce54ea893cf84abd6c4fb -9234c03bebfe6b47aedc7c5452058ca6a8def3c368bdbc9019ef121ad44171d6b31d9bda9c82300b5b396187324684ec -abc2ec6016ee252f5693558b694eeeddeabf4579b7e03d37504c26ecc29263e455ce8f0158fbfc54135600b72dc54315 -b46fe7b51df64cf46888a810365f891d43db5b34ac4d3505f0692603adef04b1d08eadb3e31d039817e7b89bf0789802 -988e0dd101bba7d7e4094cde99eeeb6d4411341e684fc06ae78d163d30c4b585375a868eda7ba1e5495ee7f0a7d509e1 -94d3033ee1926aef656b31192653d3da96d5c533ac2436d68fcbaebf827475778689ecf14fc53042a523e4652fb9d713 -993b598555bd2a35e9a03f99950d09f55a48ba63f9e0e65802ecb95602d045001f82f25c3bb60221adcb8ab4e2709ba1 -a0acd921ea7db9870716acb595c65a934a5a06a07c6e54cd26efc86c97eadaae1522a4a26c8f93b7b7cbc4746ecfc21d -8dbd8f492764bee920e0224dbe39d650be6732b56976a5e1b636b2e7371c1509431175b66c6ca879ba8f915f9df8fa36 -a01b24c1e3aa044cd2598032950755763345534f95f6f71d50565d25cbbbdf9c42e35253e35b683f6c3156f5c998ca4d -b895522dee1ec9c5289e6fec652093519cbbdca7a2936fd1df3ef956eb404f1a24272c9ae6ce58eceeceff36d76d34d5 -b91cea120e200858457a64a60aa876f167b1b88c1dacd9988700b9f0f0d1bd1dfdd8dab56c2e7197a174b7b8bb8422e0 -8406767e4f7cee2e12431b093ce82f633ffc76b451ac8414716fc74fbadff30c52a22869607d5de465d0f4df8a740343 -a2cf431d18b2fa526291c7027d59b18cbd73a9b48d68cfd6e4b745d27774941af809edba06c8534b1864045d6fc1bc20 -ab3fe23aa8c45ab2efb2ca0c593c8644d3f47f748c2f753626289b0b9c761add755e3b52521ef37fd609429b2f8770ff -af4530dfc5b3f37888900d9fd08554bef4e47c4c09a8c82bb48c4b9c6c9089465f98762d81ba4272b6861121b65f3c5d -80f61d086511b9b8b2033921336a68adde99cd25fac71d8f8fd0e476dd30cdfba49363784f0d0578c1f648f93ae23f8f -82ca682cc254952330d1be8c0e53da24aa943ffe0209b00bbf046e1e4f9425886a01d6582e2853137a9c256316e6f737 -ad1d508d2ea2806c351d5bd1098c46ae7ef83f4e49e4e87f83fa2c63f715ec56109996284a541c2005693687b4813623 -9061817ee94bd2895064f4af04777b499a1fedd9688ed64bdba848202c3cf9286b699c92400ed456db926ee23a34f90a -a8bda55cf6f3f9edb78b43a52b7fe76e5cc2cde21e08487ea597cc266e54700ddcea1a287ec6d8f16b738b67caa27152 -b605576e55d1fa4fd9d7fac2ce549dfe23fd6ade41fa859bf809baa3f1497d078cab06a257ccfd6cd59f67f17eb22f5f -a92d22ff5b5ec6dbb1d57db1b740521e82b4bef84dec3e130cab63d0641c3a8fec1f6f86141fb1918dc0f3fcfcbd8cb6 -a0165df8dfd7b3cb58883768471cf485b886ece529d5bb78b26acf9ef6c44314cf9f34914233c93b10b1918533dcb8c7 -88b79c9c721c1936fdbe22d68459d1033fdc986d3e52f39341ab06cc85a3f230ecf0965ee8d2dd54496981fd08a02657 -939b77fcd53a523240bee730c2d7b8dae0b32bc3dbbd31428c7b5fdb4c3d34afe7f2a377b2918497574606bc06cac750 -abbf82d0156439761b36a913b661e3d452dfa57e443ddb61613f80e110acf52765139fe3d1dd59c9e7773b262140cb90 -aba28324844cd19b2d5d07a87e6f3180a3c02c7326bca846c1e7a7c131c7ddbefeabbd6787b4e1e910449f3cd1249ed6 -ab2f71af8596c10351f7ce9c3a9bec08a5c7837cee92a7400826284752c98531a0199e2a7f9ba7ccccc8fa0a2207aa43 -a71d5a4f8af3a16ec9c3c110ca2135c68103109d4384a299cb7ed09d96231c90b04ce34ce12de02a40924d84947f7f31 -b9dd79bf3286ea08c9b779910c84fdd02a33dbff7adc2d6612cd58e81aaff3f64ba021f875ea9e1201243ce353510350 -9838fce2f70e7c47dca7239883229c1573ea97d469f120e4af659b18bca31cb68d12220fbd6e4e9e952b28eb29c1e5ee -8dd341e67e4c567a4ea95252854cfff8a7631c228ac852b33b2ea9211b2a6c606e4b0db28afec61a1a55e6b5f0a6604f -ae9b02d60441859e3e6f3866a9bab8895f0cd6168f8e84dda7c9b1cd7917f1c454f10aff9a8de39909e36576bc0b4828 -89fba7834469a06cb0da39c39a288245e577fd956c241707c432c2590e18e956e8ea3f67e4bee5a5562377617af53334 -b7ab26d79ee65eb9612e54f41f75e22abd83db45010e1a94ce5026a24675bdf670e806c71f0964a33d6ed277d464732b -8a25bae10ef86d7e91a7d686965d17fe16ed635d787d4d6ca337b10ea32082938f4354620a72b5aa43ae62c7a0e751b9 -b18fd9213bf3b2d7d191266c7bc1c31f683fc7da7dc5ddb4c600e1ebf5fa80a399af9e31b4ae747581a07ccb736b4b32 -9968346d8a867eb57f628e2ba00f69e9d6aa8e713377a69413323b1b9b26218f527c0e719dcc1027daf10c3392f59733 -831ee266686776eae4e3de1f2bc37761a5e1b918d4bf0bbeeb20b490902ae97722bcb1c98c485407491f248eecb841fd -b0e949d7c50b852055f38f3542a974bbfe7a33409d67c557d70c1204f87265bd7478e1751251792435fa22097d1762e4 -8b0bee83715e20f2ef832347c926249b5b168e4ad87b2e5a9149ea4e07513e4790f60b1769ddd1816d7126a0f6fdbac3 -84edc35061dbe8f3de90c2f9ace94be5ab4170b66c42583a0643ff776256217bbc6fa31612e68bfb9ab678f8e8e49457 -afb4ca7a4781dd31a7d81ba8a739eb65c43f3374e76b4ffeb2c7048b055f837e6853b14ed2d3224a40dea35799f0e4a4 -9945fd5ecdda5ac952785310e87917126917fd4f504fc5565c236db9b96f9666934766f46a1989c1aa176e543c6e33af -a6d4466b53c48d7facb9cc33ced1bec98897e545b10586857e896d35c850f2cdda65e19bb934a8c74f6def805b1df4f2 -81e3fe4330948c279d99a8a1a4e4e141a039b3ccb7287aaba6f9041c3a8a41db1a4763fe04a36bdadd3d3295becb9d41 -b6be2ef16b60a78b17991d27463e401eca731129843021e302830c2fd665726547240ec3a3240586b01a05ca8206dba1 -b9d7fe5671b220a3da83bfccdc16c0b6f5e9e5c87810db14f070dfee582fa190a360c62acff13cd877c818d705a8a872 -86867f22bf6b859e7f0ae7724a1174a65c4902cdcf74bdb22415875d72b67f49c62ea8bf9ed0d6883ab76512ebb951f1 -ab728a8167b9e82d608d4939a0712f82843f624d08d4013dfd3de41bc526e9d495cbfd40c443f67ac59dc4b5f30ff217 -a5c4d10a04452c1ad12c18ce8ed7eadea1f3cdb34fa5ce0cbd804f5dd92eae2551b771523e711e8037770cb66d1951e4 -8808f69b975f363bc08f8578729a6e68445138dada78d5818d33fb83a7af6cc6e7030f7b76286829861a4534e0b30248 -a280773d32e1ce3544d3ba5025896d21e358592504737de72ae76d164009fdad05c8a1e5e1f8658ca6374b347d47c29b -ace91a3971be87b1ca8e737802918d86375088e74380c444751c65978afba2b017cbd8fdcd3f9a0c19c0782b0034a589 -b5445d816d65ea36c9bc6a3d5ec44ce6b76dcc18343d7084567dcf2603d2af93fa8469a1c493e19f1853c96f89621fce -a238867fce5b09e8695240f936a3f3cb12a715511b7516de995543b2e15aed8860a12754ac8d1c5ca2364e4471a9c5ac -9467528341f5b93b89c7f37c5dac8bafd0af620230a9f7de3e809f01cf73b8ddf70c38c5023a631a1978ac05ca35c318 -8e5f1c3c411f0939ce4b6a5ced42172fc5c3774f596a114e7c5c8ba433c4efd94ca84affc0bfa89a1c5ace5090276a43 -a6351818f7553d446cbe8d3a318841b0607d1f1890ebf9c6220a092bad3ece9ef8acad4d17935e437377af8f9309606e -86630d0fb2bc104d8cf840b0e545c0c149c1a8e4dd6d460dd15a52a5935c8ea5c934ef099653d783894a6d1f68414a84 -b357b5d9cc645b645fbce2020db583cdb68772751d6d11d635f1e3ecf995a55bc374be7750b6e8bd4968a55600ca9806 -a9b659b8cacb73a81093eeec42dd7f4fc5d955f9fc543037f31bbcf456af6476f303aaf0ef960a2df88365c2704bb61a -8b6ff5201c15cffe64bdeb818422fa10dc503ef2a6a4d686364afd0f35b6473e4463719173550d234639f6077e19542d -98efe45bca5ac679cadc25ad0bdb1f8deffba13d2d7eb14c6149d5addfac06b82fbba6d24b323d615eeee1465b3cc30d -8c2329c976d78f1d5e30ac34a3fab1f96436947d85f0dd190301a1868e5dcbe4ce60f48fdeffc3e6a05ee34a461d7dd9 -aec012ad25d99ce014101d7da512fe032673399526435f6e1faca4b63759e8f6694a46ad01672da9eaaa4634f61ce89b -b8d52e530c942c3c7a67bbd0366f4cfdc6a1a075471878516b7a2258aa073eba50a113cf433879a0e15462e82087d17b -b40c5ce16f94837c86e81d98e2130a9e1dd229da5aea52e79cb42217d3b5908a53d76782cbe3934fa8769db58b00dee8 -877300304eb69720f7cfb4f907b4a7e238920fda129a38516dffcbdaae2e46633d31080590d6df05756781224d532fe8 -973632dc791a5214516c3e59b2b48169470678b7dab66d513e35a0fd1df86b992e27ffe6050a5233af20b5d4998d283c -a8ae0e723a8ea6e95d721337465a388b60b92b1d9b1deb0b9f59ea30842de356184fd55d9b8331d8a29ef473c1ac2315 -92ed6cca30f76135c4b7e7893c3460501e92592f7d2d6409c1e1d80074120243a5b9ec14d801991204f5ec4f94ff1daa -a9f575b8518dacdbc5cae766389ab2ec01c876038414b7796f640f633367a5281cb49b48b5e80f6416a33b401c21309a -b9793588283cfdd47cc4547cecfd987f9f8f92c2b408725f39c1d879199d695e87675fa7e5a190ab3bbc97683a0b9587 -8329a844dd67dfd48546791c4330af65501baf9524ecf8ed4fec9ea87067d0afbd33099052c1c2df819ca1afcf25dfc6 -b908eba1b40edc300b63ff6e20e87b17e6dfe975c37ca63c92e8866968070a2c07204264646bbc9318145fcb90c23555 -8123871ed78f46e9eff4fc7af9f490594fd7c20fb814e505481ac5c7bc7588c1706a79b14b85d29bd7b97d7c82b2ae79 -833ed8928f154fe0a88ae98e5d8c74f816e3ad679c1c4ac1322604093e85ed4b9b9c4361ac188f0da5443c72ee4bf3d4 -b9fcbb8a422bd8d996e713d176b7e63edcc6d73b3d1fe3f2c4b59da637a168accb5fb4d227b709f979742cc0af8c0ea8 -ad3759a6a6bac3047935443347e3c63819905f6c01f58f0ba76aab422d723cee10c769663be9554473e668bffde1d500 -a60c1909703211a93d7b5e8b8ec1cf4ca06ada653c27696a7dc9a2ff75cb712918888c6b61b8f792ce9b413aac09f48d -91f05985ff17f9ae20498185f6558f9f38b67966876dcc6981af4d179cd055661adc63155f4afa6167ad61b7038ac49f -95c5add9bab6b9792517772f9f8b21bf7cc325dfd13a43177b0bd982d0f620185d8596c2cba46a5e10aae597129870ce -ac0b4b6e2b3e417166ad9b17de0b3ba775df6ad3a78ad13a1892c0992735ae54c06b1e6123b0c0bc90544441630c6a1b -b0135c25f74ae776c241faa6c91a3f7ed6138d19a2100928b7ede64b79e177d92c5cf921dcce3c614e32de34975fa6ca -b2215b560d5a36f045de7257098e9d75a40122919d4726990b4395eb2bf1ec789cd0c64c46b775f6a8be28f23958e17a -870dc7f7a513728f2b428a3c08b15a6af88a288824e790f41b1190fbe02b59dce2914a1339f7203cdb7f2f9c98d8d721 -8e3895f03952cdab36f602418cd746bc0b6a07629eab0a20bbd8de6c993030c5287fc146fc45fe97a06c992e0a9ddf02 -a4cea15ebc0dfad9feb3d18168fd33768e8ac69e263263ceffcdfa35e8638711c2971697b7d5b2aaa0fd8c5440f3e164 -8cfaf5369781a59f4117283fd3f290b81816abd3124a9486ab1faf7018d36a73c1630efc4ad648ce462e541827d51975 -82b420eb25736126ef18d91e91ca2ecaea8983b8091df88343e8e54ca5ea7a3da6918c97695cc0cd5c2df95afb1e3cb7 -b3c13923a3d46d990aaa6a1eff3ad32f162ccc5186e16a549dc29ad4d63de6287cd05579452785cab32e2485636d568a -ad8a43ad6195e08a36f755dd536842ec88a7d920bc302451c860444a3fdaf294e5b5dc5a122423474d322af5de8cd8a1 -ae40d1a90a77965366b5b5ce87d6fe86eb255cc3d127526930d128ef7763455adb82475ebfb7be31f9c512394f2a22fb -9763bb9459fd4c0de2534767bd99f98b859030b6af5739a7081d889d6875f5c23f0154c30d00b7240baf6450b4459987 -94aace9e9318d79d3c7ab533baca31724bfec839b01187e326b1fdef846968b1b29882f2520a9e237dc41ada01bc3761 -b6084f9e0051be76244ead401e8d2758717e93c4cdac58443261b3603cfee0eaec7d758b2e4357650d2c1f5391edf798 -8c656a798fea470163e70869a13edd30d138bc148460d122a2275df8cb43f2b45a14e0d8a8a49eeb7c1afd02484b6ffe -8ec317e63df2881f49401eb2f6a82e261b07474006fc293bbb54e0fb7437697b16ec1d6ea101fcd56543bf4d69374cf4 -b27d9b3b8c3cc59d08159c765d24fd4660bd0a54b2b7fa9fa00b47e6770e6e8d3ca353d305fd772c8171e20765c8a66c -863ca045abc38ceee09c4a21a3dd18f1c0f70c0289437957aaa39ff764760bc422b748bef8ef133ee28d88c46e6be1c3 -b0de194caa68f5288dc365faf9e9ca3c69b0a8376cdb532cd6f1cc3478671a1e755d0e8afbde4e3a88440fd9cff4e8f6 -8a259f48cf5a45773522f3c5f283a6c01a0febdae09f873e009e4635c57fe5060b01243b2e5e1c9d2ff7490f2dd3b334 -8c4398e1e579778c88976ba12feaeac0c96fc97b4e26a133ae74fca1b9c315c1112ce3977d20fbe9ae5866ca6544fdcf -b54b25aeebf1917bb4981b43f39491918773bacce37e994b74f877d4a636f1b3f4a2f164b858f95259f285ca0c294f24 -a9db33b15331e852da3693f6328bde30b8cdd79c9b9b63107cf78dedcf14da68446c462720b9ffa5a1bfdaa68f5d931e -9966b6bea54405df1dc4edfde9f8c3ed7c0733d5a73bcd8b349035744d5eabbad0d19801a678d48cec84c0335346af33 -a3d0c32b5e3036c4a4b222c13f7db23924bc2b2f724bd908a38db3b8f9c95cf5034c4cda0c5083c0967d34061a216b57 -92ca6b883b2b20015fbb56cac4c4b5ef22e555a9b75f4f020822fba9167eebff8f9fe5c729c574cfa5ac27bae1a83fdd -b72b58d6ddf54c2d37bdc1599ac966c54cb4926c8d2f70d1bd4cdc383c6eec5e4b87efc59466682f8db964d80a4b740a -89ba63ee57a1e6f13d7c66150a8d6721329b385eed92be3ea784eed89c76a1ea88595725612b109a9e4aae41d3f6c972 -8727bb53bb62fb714e4e5de461c6cb298730641e38a0b49b3b3d4a29fa24167c7c6f4ff47f4f3b91e464a581a4181853 -816699bc7c3ed65747d34786b7fca4e35e79907f459f2df0918669adee54a70c03580c4e7d2e410ceb45c71fcadd44e5 -979688c14ce623dd17344e67373e5852bc1d3ea12d37f7b28095e5d578d8c9c646e4b97a3a69a97764ed0a88f62c99c7 -b4539a9eb6578ed3b8dd54cbf57419e99b69c0ae1ca3ae3b4a21f204813b2a78438d6c72f86c13dfa06a0b9244b98688 -a5d957181c30701fe6eabe3e65a53a33dc43df364c45f0c4d882ab88a069024bf04b71015f1c2fbf03f368e63bd82fe9 -b9ce9a54d9b17d4da41ba3135d077c546cf39dc83230506a4ee88cfe39e76f7e35664ff1b571e231054cf1b764b9267f -ae6bf2eec8046137016ba94442a7a0aaed0924ec1558885135fd339d2996aeff31ac29f1de07e84f7b7391fc5355f429 -85c7c247766a4ca44278be81752f4170dcc069f76992b236b40e71e31e08f30de6a5ecaddc44debe4f94151cdd8d735f -a19d41fcac394b750248e575c300b9a96dfc5b3dca07ad6e1d68dd3f8ab94d10aaf8edf500e3fc7774e7ee52935f73ea -b3c959a22fddce5a2e199bc8724e825a6d9776455c033299b5cdc9a9d184be169d807829d5df5e747476d172b5701cca -916aa7bc58f34bb8f32808858cecd3e90ea26c3ec1f80a40e863ba18fe9af6e67c0b2664a2274eca6d36ed72e59a9341 -864d945b7be551926f747406d72057c7a141110f5d269fb6657cf347cfad7178670dd294f6a98c19dc0943a68d7ed45f -b3480f8a42ba0e8eb020c2e1c1284a8a9102fa68b43f6eaf28e031621b9f68bc399899e35a1a283fb52530c8574484a3 -a8cd1cb93974d1a6072ed51f356449ac19b04539517cde34bb7b2ba55949d213ee07d387ce7b5534175bd8a044556ff3 -8e81fcc5fa5579f2479011caaa393f47a4e12828e2e82072736d85ba1bf70ffef9fe3b2c22fd11ce8eaeccdfa2579758 -897f935b4542b9ccf8c0660c8fb1a570a8ba108fe8440e17e6c50e01affc2a8597b7f7cde5244c7026013b52c7331b5d -b9a20f612c74821da05f48d8bcfa7a4a550979e35b49d52031be8bc9cf717fff21db0142b633465c5edafc42b7c73c84 -b88caeb2157d636fe26d3b221143443940427e8722596746bc337679e10ae6e5a9b33c456ac271f8b01db2f5d1b00a62 -b23bbd978725aae647ca2778e801235f605dde17897d4d56914b0d2241eb31f930028904a6555581ad5b2b74ec3c9587 -97a331ffcd02eda1d6e0e15deb110ad6106d3159ea641cfbf424d2e3065bf65c9b14f72a27ff3f576dc51eb068bfb22f -a9317840cd8f437ea97d80a3f445a99eef463a5e2beba3c986da8fa67def4ae9a0e8d1a675a35e5616ee90986366bb70 -8c26dd7451b12c65351d5ede6a00ac7b9316f9e28be8c692d20709c3b4a5dbc76fb914667a2f1e9a654f8d2850b7dc3a -8bf4aa18a988f82dfc54668bd4ad5161f276e31567c949b7857cec331c74c6b68849afe852892816c802736cf7c547c4 -836fd166bb9689520cefd6f23905e4c1260f97167b17534930923107fe934d4afb1216e4b89679a564433dc952a77b0c -94d6a5a4a11f41887eb814acf9b5a031d013d614621642384504eb78e65b6a07c50326632af47b408d8ccf43faf8399a -a213812713128750bbc5311dc317992bfb5124fa067072891f452880183d64d6fdfac8825552cb809178a3f3a641c9b5 -976d1290308868c5e41dd3766447b29ab8c3b72047a0b7de85d3ee5b1e13d522147a02572cc0d1ed8976d411faff5b9a -82a4494a95738ebe56578e1e4c0e486eea66d5cc44141f478bfc5a6b3ebbae6f32063725284df81b438603aa564a2b6e -8a6f4dee79baf71a4a40843437c16b2f304785f3e56b32d9ab2474666fce2c7749c776bd898a65f4a4d542a497cb6d6d -a04a3484be07c2d60f1a90f9dd8d4170270a808cfdb863864377c2515dd71c152920b65fcd5f47004d27d14d7ee7eaf2 -a984f6633ce3d42c75083ef7732e5d0ea15d91e73cf893be3ebac5e56defb8db97088c5cb3acb661e26bbb354ad91ce8 -a5ab5b4b0dab86706d68c9ad921d4917215c4fbcadc8adacef7309c0c853bc3c2ea34b3868d8f03cda6f504793832594 -88f03e55eb028353b70352dbe91f298ade322951ca115972f1207744254fdd01ccf899aa40ca747da8812dda5bd5f985 -a4bab627f7de273f8085169cf05413bc368c5d9e5f58bf10995a8bbd95e511b1ce15d008405728ae8e8a83621efb56f1 -8ed518d0f225b90fe7f01b0fe4c451589390325044f0d18a8c47bf13e24eae8627feb0c9e9514397536f73f33f67a044 -97c73837e77d965f401b4e4f089ef4de7aed1126bef6be4e9002b2b68014b98997213e492f7aabfd2e47cd0917a11d6a -a99e8a55ed0385bd279e11a80255b375f2d59bf8b0879bf2337ab5e3be450a2ec05d1bd8867a633e359a02cece4dc1e4 -82a74b5efaf3c217ee2bb56c9b8e76b3eedfc553c73177e59d982f503a5b0572b5cc0d1292820823307eec956c42b28d -9800ad3e10e8a19d65d5963673c183bd536b65e14ec18dca45e881ff3bc74eac32bef2ef845515ac4fd6caf558a6926b -a2933c78a67cb40489ffb8096c021ca017b99feda1f9c5d702227d7f0a2ff66a539d68a47ad90ffdfb5c31c774946f87 -947b29715258ca20da5b17a8e3d99665b7e599aa5bcdc5d2d7830a2e3cd78364d51a3d7c0d8bce48a1992b27d1ac4980 -86f2e2d3e160d3ff979ca70c456785b4b2437eb64e58adcb78c4aebc96b470f1b8b999a3ce8ce20e3d3f030d163cd138 -958f4435d35932a91eaad0dc476bfc2761a85f336ad2ca6fe0c6830fe54e8f417434616df9e6f07a9454a4403b00b64d -8b1755af961e0f9f59651d56b538ea59af489e859a1c93726cee62649da0e304093d62db9a2c5854c8da1be61bde990b -a5e11042f73f979c8649592f6cd01dafb319344e379a65aa9200d3b636abc569edf822c2bc12b3db5c30b9ee74f2c981 -92ac5584de1adcd38a2ebe361225f224e9b498344521be519faff77f87c1f22fe8e112f9df7cf960b16e358efca0db08 -81db84f05f75a218045d7d5fd4620648bd4a95cf468cbd69787011d615778ba7300b729163e7c8abd1a5b0ea66fffbf7 -ac2f522e9f030a7c576fbe19041f5db3913af58da75b87e8ad64b93bb34850a79b852804dc68ad5e7de66d90878544cb -ade9763d1c7e9f68b5f817cdfeebf31bb3ec1391dad04576c55fbe4bb13cf0d45abced3d51b5512c73b2d0f403906340 -a0b431bdd9641595fe1eb8d96ba4fe86a447a31ccf36cd2f7d94c5c86a7d96bbc95b204fcfe7c69c1385997b1daea3b1 -b3b093bd8fbd84414609ec9a108507f97d7f77833b93b15439423d2a2928e40b192247c8471cdbc12891d83c765cc6e2 -8531a5ce8e0c44e887ebf4beac65352c8a9673c51b6a1edc439e08bda1354d359e1ab2e27b82636c6dc0daa3aade931a -b22c2f3a77ae4813a75004dc2c9593cb2a51c430c559bc7d07d83e95592883b99fbd0f9ad24d2d80d86c871cfaad2721 -8b6dc7d5b8cb6bf36352fb19e42aa37647505436e1442eb1f228b0804916d569643102b2282ef66bc9a4442520521dee -b29a811ab81dba820242a990dc774cd937cd299495cf721cd11971b9f1dd9441ac687dfff0e91656b9764963a56e4625 -805b280e31664008fdd874bc38e870db271027da70fc2246fa82c499742a9a8de1152275e0be61f307dc8f7a918e270c -929f690538a500d238208930b55caa9c489bfd3476f6be2d385c36df3159dc3d8bdeb24a1ffd7b028ff4d881551e2888 -a92bbf103ad851a41e5230e1e37ec7802e08f4610c0db9706806afc4a247679b9525f9a534c70d970a1acb47fec9bcdb -b9f2698a39d6d7aa8aca181fc5d95dec796ed6eec002557d4b63369bd90aa4438c27ab90da4f3ce81168cb42f7400070 -b08703bc97292c56833d8e61105f1431c334f98a7946850c6175f37f703ff790d9a1522c0003f08dd111eeb083235073 -9355141cfadf46f37afb73414c8803f9094b06952c9fccb24a1f8c18a13fa7b1197321b19cb832de3f83ebdf8deee53f -b7c23f7cd8e212108906b7809df90db58d2c2f3a8e1f775274181bd81c74fd7c2f8d68bc7d4aef639ff4e19f86243f98 -92728e009fc3faa08e81c36c268b3ac18627da7618c96c97598b13242286645789c15c99518a07e658d92eb8d2b89c79 -8fbe36d4f2f08cd6245e8999728884c636a264451e4ed894d2116375f3d9eafcaa72ee59cf7923ed8ddacb53cc478761 -a6b2bffd6bf8f54231fabe46ab2c1d014ddaa797d08e5914f13988140bf804019fff3ad07ac2cb31283fc3e74e28d0fb -886387540b5a7acc8b2bd107124bd17d6515697e09c85c4e932a6421965c872f014d11d1ddf321651e4b3564eed4f252 -8b81f3ebc962e9ecd13a11e919d86ce14dd89d373cffa158b807fc91555a4ec1d7164504fb67edd9599b10fac5e32aa5 -91e3213ded5f82e34389408e95d4f7fcd0f50ecbdef9726a289238e4159c6d3cd2f401479a1f785865e91ca213d2f8b3 -99154b88ca5462f62031300177e571708821348e1027cad4867eebe42a6fe92a58ee1dc21da9031002f1b051351b3785 -b5c2b7cfd87f2f65df07b39f8a26dccb16946fef6b89268b9300c8529d730a1469ba565a480d7c5ae9df8600ac50e90d -87df32def37370bf8c4c3a22a670bf5605c78f240eccf8dba13bf19c8a3a9d0560f8899259c4e51c6b0fa64d7d1e4c76 -980a20e5cd352786bffeca1b8a31930d8898eff9f4a6b2570829248410bbe1c78105b6a61cce7e3ed1642e5e2af127e9 -b18b8dbb9eda5cf333ea29fad7734235ac9e7234b49fd04f178136b15d97595d5b415a92455a319ab594b81200cb17d5 -b713a71be9bd22ef6a2747d0bc8f4d008cdf6182e287c1e0274689e915a68150d6083268188c1f4a7fc76d21a219ec85 -b86ff129a981359972bb793a81fd422e0b37f89e76fea70da012fad160b9eb7b029ced81c7e34679f6897a45b4e8da4e -a74a4cb9707156e21caa20b95a2a4b4eae8f773cf679e2073fca2cd3b1e502ef06de8a3c010833d525a7f8bb6bd24601 -b51f06da38a76c2728cd01f6073f402fc49cf4bc5c60113a2700b5bb0ca500e465e541c467013a2804bd7641604bd2d4 -9855dd73307d8671b6f9ebcf676de3ab7e37e7ac1544447c7ff34a213da46123b57ce23bb0f381da8fdefbcbe6c35645 -8fb382c63f4c935462d013a0d3e2321d72fb4781c10afe6e31ac51766832218a05addc6dbb1f644aa61b5da9bccfd5ae -855dcff23e0ebbaa3562fd27c43957cfb35d492837aa71f27cfd1bf65a59a12d2beded9d09f3ddb4f801aca8cc34d2af -b7e7b317f10cdd13bc879c2fb0bfcd137af23e0cb70917e48d53b2bcf8c157ed7e5f58cdb966383ece9d3a4c92012746 -80d2f84c39422afcb449aa68b34fa9d72e9de79a473c3ea5897f6f3576d2bb6fa2d49f0b44aebe5e68b11e85e066e028 -a35b083749f8a5551f0dcf529e845aee189cdcc6ba779f4e88765adc49cc4779cdc2290598908ccedd8dccfdce29d53f -a30c412f4bbc2de80fe5c577b4f94442255cb3061a40649b0ee5357977503c6fe54821ecc8cc92d5056b6977c4695e70 -a2ed0d90ab612fa3526f7450a43d45a2d9e886f2e5888ccb8405adeb8ca3e41c6a94d18a54b3cb1eab5b8f3851841ebf -8d4dd3f8f8a3d69bb217d338e757c814eb69e6a776f55cf51fa7c1b2f1ce5f8e9bce8353dd335e793d68eef676cf7c36 -880d1ca33d5d3bb47b788a7ec64b9130752610816facec99af53b6e58a7e414616e9c815b1bad870d426380085f6b5cd -a287578293da4354f2c3c46d637aa77b91526f9618799dec4bc602305ffd8336d373786eb67eef01dbaab88f07f292c6 -a86d3fad257a64c84954a7530822346da0215ebf4ad9c583f35cdbe16a02fd70d58ab34c93681fbf55d6075db6425cbc -a7bd884d343a6bde5f6c2512d81ba701fae7afa6389389e4776eacc0698a54c3ab1a0e1652c1a7a23d3a1d2a63cde8c6 -8e0653c8b7279d5c958ab1b53dd77b73fd30d9781630a870d0a75681d38cde4fb7c2183b9c5758596ac556578b43fef3 -b76a00c6f5093e7b28703df85bf968dffb70c455c91e75cc81189598df052244f7549d18e45dc70d98d3d86e0094ab2a -b270f2ad3dbc8b43ee2603c4e641be76820f07a4757cfa96be2be9c310b7e39b574572103253594a51fa9243298cbd94 -977b8b86841ab8be7d1d50da7369e2bf71f24360aab8448d7748d59e010ce81bfe79530ee6f6644b987fc0d83df3ed15 -8e18bc59841b7d56f8d9eff8818eee06288cd6ca86200eee7b5e6b230070debaf254a2198b4cd7dfbda8a1d55a916c8f -8e7a328ada969ed6289972b7f43eb5958d23688603ee6d118b6ccd8978378dce2d733ff64c30519b19007a78340fafa9 -98a0fea70a219292584c69546d6d242cebb2f1d84f69c5aa275a257a87de652e721078b983ed67410e3a5eb0cfbb2bdb -a09fbecfd05772a9989008281a9585accba3850831485802f042413da533b1c7ee45a8cc679804340bd9142b2f9e0069 -99890a6b273a2787fcfdd8e8500134efd60df99410e8432664a3e5325e55e78942f4bb11024c90e4c3618a70729a277b -a5f3eb1617a77f2d5c76bbd1bc3546ad1628be90fafa9a8b62c605d04e599ab2eb74b25afe0e68fd020daf4868dadcfb -8b53517d93f42b833f7669c131dc67f14c3b0639c46d3b02bfdb24cc9e642133e0c665236a7ba851c100ca733d673341 -849fd288217bdb154213e79abe1a78672903e15429e37f6846019986e1cc8dd2b3ed28e4cb52dee1762a4dddb9ca95de -954d839198c3dd2ea1ffddf98050e2c52ee81b89f38d967bd30c6863672e43bfc32e1030bb12f5aa424983bfa31dbf5b -b52fe86414a98d0896d7a427d57739da35cac4ee24be565956d15a5c1cf5b4b95e5425dd2607fb9f6d6024549b59a4ec -9586070415a6bf1e11304d2819330eda88e81a88b9347aa866692c163e1af772be9fb747d9281d7aabaf5c9934596934 -a5b78e5bea362df26a89df682df61287763ca1b87ab9618609c99e52e6ba047fba7ec828c0552ee26279aa8a48751334 -aabf36b9dd465ae03551dc82bed9cbf1d22a2236ded28964334f7ad474f317f4fb8515b853354bc06181fc9af82714a4 -910f0b2efc608cae8cdd39df7a5ef9e570592b31df2331baa7721708057188ae96e1b43e2f2f2c8cb360b961d687b60f -a5c5b131205c21ca68d6103f8499279621da337a743e4a08547c3b4507d52d2d6e5014fa5d920b351a6f53a195687766 -a6898dac2d8748b8bae155a7d8c169e7eded73cace1e382c4dae8633f19463151399c5cf877f8ba344a698a98228864e -92919d8be671b4f490efb49bae145f419c84a1e81d3ef78761fa326f67d749ff3530f5de04f984a018065f42e852e1e3 -81083de978e025f0b5995550fa17915d02489344cabf8a79248352d78dd6e893d28a5c5204a65a8873756a34ee3c0120 -a6de92ecef84d188cefe29a03b564b1e7bef2a6afd785b58897f7f97a958573a35aa0767bef12a49b352de30b4f0dc18 -985cb3475c7a9f582c11784cf61a1988240d74e49084a4c0f55f3f6068c4da0b08b136f8fa62e9001e0a265bf65fa3d4 -97e6d360b504991d51119a78c5b647f25d5fcc1298631209d82c2ca40ead0380835fe3cbf8b82148b0b01b8157e884e8 -b313df44b2c47126b58064599a0dd6ea49e5ace9ffa663de03ad30c1e95301cc68eed67d37ae6238469e45124c59bd39 -8a58f70545db2242cbdbb12492cc11ec4d2b2ab0ed8450d21ceb573558d7bda91ab03c98736e13d041bcab84fd8248b9 -9077880ac352a5ab0e5e15ac89b14d173cda0b41b6f7fa66bb357195f10cfcf491fad6bdb49d71cc20d99cc6c8e28d04 -a09b2930fb3b1a60af8c5214e8c3f6deecb3fd3d0a5662f3885948f48d1836b5ad3dc74affc54dbeb5b522b90a17dc4d -9163bd2e5f58fb1d81007422b91147685542fb1c7e2c8421af284c7cbfdcd2d2b399a37123b58a2a349f27b31bfa47ab -8a3d859f141457f9d63818634f81deb5c858ac48bfbf2e1da21f4f0dcd66b3e1d2d8fe99c4cad38206b1e15dad94934d -86d3fec476b59782d0477ff333fa79922fb9fe3d6d6b6c5be9da9e88b006b46b2a0f8f86ba4159c5085e66e32fba67a3 -8041cd57335bcdddd37651de2c3e92edc600ac23041d0e383baf55651b1b0960b6a601491608307160f0d7d48ce395f9 -805c284059f8c03b2bf006b1af95ef726874c5548e93ea965b402931f42b189f9f674b6b52ff09df35320085172973c5 -8acf781a0b40cc56b1013cc1fc3bc43036545ce35591f3b905543c09cb1ac1a70a074202b6d5ce3680be913200c58879 -ae670c448996156c80d063f1dfb03d7770201a35c71cf8e70b38d52dcb5e2bf73d5286d63ba2f561525d62cd67d43125 -b0fcd0150fc0005ca438d6b0fdd6a70b121d35ecd74e62bc119bb0187cdf6bf674ce9fe01eeac5d46a68ff4d4210ad09 -b752c6850985ab13a057028887bc84674697c012e9da0265dd5ce1e48f0aeddce5e07e3e7cb68ae17a648cd1207eef19 -a6a5c71915a980fd0225847b45e2e9f3731c6b2a627cefb1e2c6a0cd7f1d0555dd32b6b601a7ae9cfc4b9d06a56a578a -b7d96f59a988a7a810c25018f7f85cd6e81b335a84504ec76c97d7257f9cbfe88215ec89553f0dbf39507d990b3a7f84 -a7cea7b3ba43cf6ecc488c34511b17fc7b97150b2d265785c09c676ad3123b322db32e043c5961384ed6d90d20c63061 -809dc467b304e9bda732cd92b15c0f9b363cc707432788971508b8d60844911ed4edfca96d8cc20b9874f1e38a2d1685 -a5b6a089e022fe460d62c4c5228e1381902c9a796ad92c03211c855541a7fe27c5a39d9123b001b0b892ffdf0a1fa065 -95d67a21154a49bcdc79ed5f2773b651c81fba1ad82bd373239f09a67a50371a147310623fcbc1211ac57aa154e8b300 -a4a4f0ca8073407575dfd5d04ebf76f8bb467598824f2ce7fa74756803d9645d63c9eb3ed39aa202dabafa4ff0a0bf34 -8a77374f6e449d94a443f2d4593a0c3e4925527e0653e873dc20756396a9a4e5696fe44fc1b49e456711259deeb3f037 -82585a825011d6eefa85cd530685b103862aa0777510d22942d8f77a0a7f489f5d10e5b36ee38f66cc96dc57d13f5893 -98e24625c31d5d97c789eacb91c3d51cc6edb38cedcc474deee459f55de557c42e4d0754ca4ce472d0123638eeafb55b -ad4351c76d96c35ee37362f2384ffb809bf6a47213863330aeac1ff9be2c6cc7275f0f974e46bfb716a89ce1bdbd0710 -afc8f5af4f9c38ae672d20e7bc3796aba23a41eb033619b4c0a06e07884e1e0c7a7326f069068dd22e69fa5f672efece -983d5af05af31f9082f381378fca3526f88309bbe51d0cea5860813bb0fcf6b32a3be110336bd728952dcd6ff8a26361 -ad3b55b67b64b188447a1fb10d027bf7f86ce0a0fac966d709e8b6ccdbb7333964045f0c4719c45c36b7f3c9ff73944b -b410fde230d8dd24b9f1bdbce8338b05110b130591913f23a34c5fd092cdd3f747c383f6967cdb529ade1a264a3ece39 -b3e4f0a046f93c332be07058db00c5182a498987759315bcc3a58d9334e09a59333031c3144b59d03596925703491cd6 -b77e58619c8c471531d9b2e5dce8f82bb8794223bc9459599a911440e64e0b5be1d37e289807733ddbc2858bded1c34c -b450945bc3e290df96a196083a45aa929ee080bf45112e678eac0a939db2ba67334ef782c855b9b354caccd94b3babb4 -9794d81e968770a6e12add60b32ccbbe80cb2680b157d125461cc3db998691e836d98cb3b3cfff4f156b2800d426b955 -98d1284b4c035e93b4ea0431884d91d5a7855ac6c5b1ea2a994e653cf77f0ac1a771dc75899bd1485066da17e40ee341 -b1da89b14efc14d15b2bc967ffab85c41dc447b6a7922b619b5d5b06dcda725bc4530959b70355ee20eee7c1802601b9 -b8e50ae98515dbd9ccaf27192e58a5c34def86b1d0d181e63e64439107c30254267969f6069e0b863c254440c3480de3 -915f0c7dc95f630bf1114b02e7d9936b0911a69c932950ecb7f800cb1aa1a4e1f1b6bef6ff4a23301cfd904c39025863 -85392fe0edd316031c69d90b106b6685bed56a0d8d814db2cd5d77d07b18fadb632694a214a176ef60aa0f82ea14b00e -ae4cdff23859b7570179586549165c728de4ca254a5da29668cfda259d43a387b3caea8537888d43f713d458da6bd4e8 -aa0b6a3e0555d64a5cd1201fdff7ba7ff3019e9ada1d86c90c626a710df3d97d2ed62d2b63e5632963e09cfbedf83732 -add726d97dcff922dfd748eb897e540a2b4b8bdbb4eac1feb74717bf086b1760a957f83586a57b5345bf4c73d791ab9e -9721889b6fd55cf9a914e5aeefdfbfb94d379c6312001ba50ec4bb1dcd03f95fdb45041330da8871cf3dc3c6a6b5e330 -8eb9417573ec6af24a610da5260639efcdfc802a95aba8efa829dd70ff179dec061da9facac95b6af02cba6a8646f7bb -a477ad7d2885e1f081556a98b3904cd75a4ac7a8c27fb0ccf15d117feca59f891a677fb4ff4fbf38203055a9436ebd1d -95b3b2ff92e8a0bace130d165984966637a74280d0e056cebdefa6f825b1d55c9bc6e13cc8f263e657dba3dc7fa68627 -b096fc33c038b425a7a922a4274d01eb366a488fc969497a575587ada74b9452a607992aa2d8b9de66705fe20b4abb39 -a813ef1053ea6ae8a37f4da722f16b6ad0213b0ec7829998362292aef68c28357ee27a406b567a629592447db8ea6085 -84248425c3201ed389fa1b64b9e1d151b5a6f5fcb8f5e28ebd665db57156ecf9b2fa77bca857200df9f54383b7c5eae5 -86d0a3c7fa1e64111115469ed0373dc3dbd448e1098250e9e8c5c7e775fd1f267d49b4123c347af07a28e686d5f357fa -8340b2ef4fc2afab3a3d51b6c0361cef4aec3d5e1d0f779f9fcb258711cb79ba4083508644e2bd182fb25b21523557c1 -b840749c259b5af5874750853b4de6f4d7a274e18fb77f774f5f454c82efc5979a431e28bc8e43bb831715c7fda96db4 -b168d333cf20b053c1b2a915c3485200a7590c3c3661507990390800fb95d3772ec6815d53aec5e2964eaec19833e787 -8f1bb538dd5005384f38f88cd2588228aeb0c6313aede14ccc12affa9715cdb938ed4573c391572f0a7ba6e33a1ace89 -ae4a8ec2eb938eec00e6608c087471128b14a773d75a99634671f6fed95f7b24b14f04b3271d1c32faff7f0f2d98547c -a4ad66552924a6831b657f8b318f303225b2cf29b09790a48285b028bb1420c56dfa2ca0df2e823f694e8e3b27952a01 -8af4eed962eeff534234d7c34f1033c68e8cf798c99880a67eabf38b533570a3776399b883f8658265cd14277b060790 -ab2c6406132413cba89a951d919bbe123fe4f220364ec2282d8ee0c140ad8d48ded0df7ab56f8f18ec7526ea2f1cbbd4 -9154df8800e26020155b98f630e640be97a3ac41b182fcdbcf31a3e4f233810e34e224c97df8ef0f39ccca29a9921fb5 -8f306dfc5b8376a88a104cdf67eab54f93e478ca09036eb780050ba2e8112b400bcc09d49665ab37d21b5a2d8440b3c8 -b768260e94bbabaa527b2af8be423577cec3bf4aec3c569a4fb69e1fb997a2157c59f1169065d24a8aa3625d89d988fd -af06139ca7d240f2495314d941890c078d504b2bc09d98a6156c373de29781e7581f33adfc738650cad0da3f6e07af88 -849a6e458ab2f4101167cbf75bf47ec1f9e481f556b1b9d297a6b4737584011d7881695bbf3ba31e3e4180696fff6407 -b107e7aff27aa19a4a92d1a65679bf40e85ac6f08d4e5f14859d97c170ceb431858fa4c46d00131527c605164b5f7bfd -a00666055e18f34ce02e8b67b6f181327ec0a11547c0795bee61802aabef9a3a76ea138b905cebcff9c4c86391763e6c -a65cd8dec5166949696dcccf031c300895c5fdd53709a1897c61d795dc22bae2f7717e7ae52a9950f9d00471ba6257e7 -8b49aeac3550ef28b5de37576a5d4e2e43bcce82de09f491984171251e26c27fd0a884daa6f3d30dda107dde4544b34f -91666b88be09799c7de9a5d9a9d4c1bc1b6fbc44c664adb15a2eb27229be910226514c2ce22818fd38b850c89291a7fb -85abf4084c735b20333b1c2145571b793f96188850bae161160b47dea7c48b0f588adcbe9cf80e05d17851cfe3400f1d -aedaee73c52d71d7ac3854fa41199615ecf49cb0c35d8203f95175d1ddf565499a8e9cb8d31d89e7cd9cb75a9fb56f9d -9413589f0746d3b81e2f88b280e354fbd63ac164369dec353e6259a2c4acc6bbcc10f2a851901f39f90da7e523d77848 -826121abbcefe3ad431c713a1a2cef336a0f06f69980a14d0a8adae5640e9aeebf4eb82be4621165ba32ce5e16de4880 -adbff68221279985891e9f3fdb7b1dc71db3e20213b7c8e1931e6f75c6f02e7a1f6f05ec0687885de55ac85440f372ae -99ce8b064f874cf028e85281bbfa43145893f80a8b12813d047bedbf88699266652de6ae9e4ef9ce575e67065854fdb4 -a809a71a663b0a9719c0327d33215b63c6ebb12da3477da8534d7e8f79fb81e06adfdad79686e40efb2c75abde559a34 -b26c4cd057118f9b12c9b86e77d370b3fdbf2654a5d80a7763ae98c68cc2769a7cb293ea89b3a08250c2f699b8d76e22 -867c56da9a2ed672f47924cce82c9d7e801d6a1fd18cdfdbbe07c82091c70ba0ebc6008b0b9d505632a97aa23c45b8c2 -8cf14633888f2ba0b02fc8ca7536f39fa290678c7e0840c58c53a9d2fe10628be343a86acd74b2fc01b0c03af0996f59 -86696802e4f27928dd6b0287d0188f8067283496d154060383c5ee295a468df32a2e8e24648d93ba868120ac429b68cc -b15439762d0f7b6c98e6946b3c0a7ea0521845fc68b47fe9c673194d81a6cb375c79b0122e81a027f21a7fa4cd6bbf56 -b1bc19c9a3756098c02bfe36429c0f0d8166a5c9274edc7f80ce65ae7d6c67864a457f19cfde6924d204b81f2a195fe6 -997f1cc78d707f29e3eea0952b5514b34c2cf0720f33a3244cc466df62b13031bea13df2296270eed42b3667c53d6c26 -94f599c9995caffc9b47543b822dd8f84f921fe2a31e82d5d0fc79dd93a4da0b87a0906b82fe7c2a8c23c7829c21dc2d -a7fc8a6ed802660bcc07d3ca454c415da18d798719dc2688eeafeb8971910377ce909de68721fd97c4d9fe439f37a8d7 -ab16f93e6df2464018be01fe040fea08c67e0b032fe1950fa37c7593c8ecbca24dcf0fdb9e1209d5b0def622f3f6e92d -aeaf19b49843e3fac538075dccbb29a63d55d12f8c4150185b1ae62de778c983632542eb495808ba629cd4cbd629e07e -85614d537efaee823452d0427ea3a2f7d5a3c988b10cf7adef8715becaa519a9b5174b63e401946362176dc0d65667d4 -aa08d8365e78efc1919cbbe562be7b28c57eb05c36e8da89378cfcad9f21e134eed923559530aa3f62bec758b00c70ff -b4c2760454170276885d66f03e9fc4e6a4254547b04fea3c233c11dfbf71ab05dd755b9697b442ec419aca000152f2a8 -b814059b189c0ed46f9dab604fca25d881a12fdfaf834a75cc2c0e1d8454ce0ed9f2a79b34bc5e27004903a48c6ace90 -847707b0aeb4fe91c12ea8570cf0d16caece8946951360433c8a375a69fa4c01136172ff2acab6d5164ff6d3b5340858 -a7a9304ecc5ff6fdaaba6e774556bcd7c5dfe8ee7580a677301dece55c6a8564e7c64b60fc4efe89ff73954f3c3f5b0f -a1a86fc5648edd58cc7eb61cc30c62edb5314caca5551ffedf088fc9c1b92ec5b487f670c5bcd2127067e8fd5faff03c -9086a31715283fd525034d59d4ba3465d6c30059b967b1eeb7d537f3bf8caf6879481ada2849167e997212f3300f8ff3 -99c11903cebf722e1cfd63a46b0ae93312439ff2f014b6653fc61927ba430c432b4955b30b7f078c340f5aad4ae24313 -934b7a8b7bcf0108ed31d35a645d73f661c064a6fc6a5d1ad417ccf1b8864623b0cfb54707f10baa86643afb5c5ec980 -89d5a69ae8cc18ad77995ae92d30236d5a5ef00cc63274e318d18abcf9d936453d18a8e6392b52d2d66b51c18d904d6f -ad2448cea1948f0a4915ab054273bdae33a08c494203d11f46888f852d0abefa310b50367c80cacfb602cbc249b31a71 -807274fbe6f08c332a5d2e2ae12cfabccfb53511b8d83bdc875856cf15ab52c2d01cf706c9be428307ea62fbfd67f87a -b2f4fee9f32c0ea7fae306605b62d983b130e4d423e2de286bf9f4343b79e5c4545214250cd1348402d8278140c61c00 -8a36f79ab3ee0063098a39382061ec3e1234e67087b9519d0b762aa9cad54a7e0bd5d24e2b0a57a690993e3182f3e83c -86668e6743a7b6d1ee62e70e6031fc8639ecffed38afdb1afb41d64ec402a308fe0438a22387d9b0c130ed301c39acb4 -b816309d1730cb39b1ab00c5333c6962fd5f5d8b22f3c3ba987b1e0a0065334d206141dcf0e68eba717a4eea533aa6f0 -8754e190b8f751aaf9f8e7076d21bd31db8d9ebbee6b26517b190f624b3a892050312cee9d73cf3d7245446c6a376437 -87826589ac28f442c608faeaf3d63ff057af7724f9d412d1f2cce8c58fad0adde325aa496c6e4e8441775c02d8a74c2c -af30e5e32fcb17226edc54030f1eff8af619c207cd9e42a2ded7f15cd29fe52f140901f0925ebe4e997b56f34d3f406a -a62a4e5b6591d336744481a0797eb23ccd0f580d04cfacbb3e415ae3f273761042b8901b0312f93a6eafc42a50f81cc6 -968a9ccc95e8c124f4475c348a33ad2a52a42e191a93bab3d7f0d211df999aa081efa935391a8289cdc4a5a8f7433822 -93350cd99ab7d3e51756eb01c89172cb406c1debd3f0001d2fa8a01018be5609d73df671e1ff43e612ddbfe7076d9ecb -8df26dbc565ea7e758ce4c2656b65c1f0396761c9360d7092d12c121d3bc1c293ed28d82f1057f4eb5375b15443e9258 -80a0dc22fb4a12b06cf05ce39f76537eb3db9691ca466ca89b2585237c03d13fe3fcd311ce2b3dbd1b7382044b803782 -818b79cab08e11dff3d55bb0f55333f6340c5b462609d43334c14fd878b0f310b77c542c74d3674a94c692de704e88a9 -ad1bda19b1bc3f6d757fe4d189ca82bdcd0a9c1ef509c43e3f49700f84be33bb9b8b8e70f7a09bc6bc00a78cad0cf9e0 -a22ab44c676ba2b3889341fb137dfa14cfc5491ce4c3c1fbe2cb7103fdf720ff2b77806a40109dea9a68d8f072e1c167 -8eba6af1659b6145676d3663b04ebe58c199a1c24837ac4969793f07ed97165d20bb0410421e561cb9283faafd9eb51c -81b216cf08a29dfc3e16b2865e712e15f494b914cb24526a96799a3078f200a3fd403767119732ca4de07203b479ce8c -a023ac601c8e0c22553068ce4a7b8361b0b37bef5705fa68a71c3cfa80510041cef3640bec2cdb4f317904521e99443e -aaaab84c8aea75303fec31694114b3ee10fc1a67357cdd675ac9d0e33c3279e3117d389e9ab017882d517131b14e6088 -8bf9a44b3df3d7e0c776e7ea5eb76f16f1870960f32e7c5b63aee9b432a0adeebbd378c574ed60e15a3abadb409376f4 -a93faee621d930f336f4fd952954ffcbdb261c9dcc4e60cb848362223374010c555a73c0563e7933d1596b0526bf75cb -88753d0e35e87f7572f2012a40bb757364af5cf6e5dc0dfd16d082e698d3fedfab3c671bd58edbf11cedca247e9fa55a -b7de5f03681634991d2aa8a0ffdafd223b1a0d1ff70fbd9c00d03f228c6772d93c388c02045461d51326483af97bca37 -81f96d4fbef3cf00da423a1c48ab8acc222016c21f6be3df778342c1d1aa1a420faa8ce906bfcdf955be045efa4b447e -8dc75ec37122afaf0aafdbea333291ebb735792b4d5934fd16bf28b536fa759dd851e1de448c3efac3d2b0097e0b349c -9186f66655fc1c551d0233b761c6982a3b8539085ca9a2baebb826091e179026b90f7ba6a825f38c6a09b190a31bace1 -a1cf319c9ed31ffdb2108b684bc21cb495e77c853e6c502e03f2ea08e88a0c2b4e31958004d9879242df420b628acd8f -b3d3e5a75c34640bb2fbc7b62f8aced8dcb4b9b165992717fdffdf765bfc81fb4e67f3e737e6f70f24d3c24812ec0ed2 -86ee6ce0480f73cc89ce7959b4af52351317cb6406cc368e889472ee5567e8a98560dc1f13b87442c9a8c5d6b31fc446 -9478256948d960e3148acec3487da232fc2ae6818ac2c6eba491adf130c55badfe83f9a519379fc5ed0b63366de86a02 -898a8130718ac6f98ef673fa8b725af6012ef28be3f2320359a5c2c40e479969e5926f1864624ebec10f27594b24f618 -906f45d4ec3f647d0c49deb95884629a04fa65cf91a075bcde67940634cdc98f76fea8717fc1e714ecebb337e9fd6998 -874c5a55bca05fe52a5d1743b8254b642431b720eaa74f73b0faacff2225f448ef94e12585b2d3bcf12c140ee3e81510 -96f76cf34b14263a30df2135131dea00074f2ee853677b94fc32e04cd9872424dd93b32c55026b89c18bdb4e58bfd19d -b62e2ebd543f3e9a11b72f45275cadf77b1033713625c7374c4d2284d63acaeb64977fd2fdc90145066146c311a68737 -b1759d3b667af9f15da8d4e77440fba4193d0db159a0bf73df32215b2d292bfed7cbaf41c07c7a94ae1f04bab23cefb6 -88423607f005af97b5f8131bdb1fd6d7cdfc4c2da4a4a14bb818b3ecf50c2ae6d3b8cf55e23632354537f5c0dcb0f48a -8ba63acf22ffc1576935467af19f555a0c27a4b56e5bf752163038f0010fbdbff8a2131124f4cf36a326dfc188740e77 -8b1996a0cdac9c6d896111671ac4dfa84a3a3738c43db6d6788f1a7b8ccd6df16a31606db00cf0107eedab28af05cd7c -912a604a97457a6b46d48731fb44dbaca26e7cc70a4628dcf553b43a9efddc4e5fb040a1b89e31902888a7cbbf709333 -86eaf5b2fa873bb56b94eb7fc823527ae50364c1bce87e36fc13de149f1fc937af858a25cc477277dc6eddbf9efd5480 -a0169e6e915e7216b83b00b31eeda207a02c9db6825b5ea44134368eae5bd009b7c95005c621e0d258c33c59085cb66c -8c8ac664946b5e69b4e34ffaa486b745ac8afc8ac702e4a4cc36c59f420a81b31ebf8b875b1f572dad8e4ef1f547a1af -aa6fd75ca832fe60eda078fc81a1a529364cfa8a4b4fac071d89e33cdbafa7d88ff3df611720b48e6fcdca2e3eeea0da -8d30857ada34991ce6faa82b4326bc353691ca32aa25511cf3d52cebefb262d6db8d93521020a2d11b3ea085287ad54d -b78bd8ea8bd6a2fd5741228502b9777177039ac8f033071c82ae11fed7f0a51d8bc64fa9aee44df25eb4b3822d571144 -90904aeb1a99c4818ef21498a583848f4d1ee9253d70c10b03ed7d669b587f8712fd26d4409f00fafc3e26b5d72b4c5e -87cc8ebf78ff2ad752843792e11aeddbfdc628e03e13e0db598e08b496313f463f481f3a17ec889a3acfd128fb89aa81 -b4fd122c4830f339fc019da6372286d3a0565ac04d4f5ac4f28b2c066ed507316e1b7beb7b552f60060825977a2db9c5 -86e709d48d03738ca97d6140f13effa03137570c43ef00469eb0310909f66061d9fb933fbcf30bf04f13839e36d45a4d -b4a595cdd219aff5b8d0f80b679e58d9a7ab9cc389b47784484704e7d2c5249981b2b86be4c37ccb11b9afbcc8070214 -97c6bf26c8b28b982b7a56ff867b2f5785b37260b90e0ae680920f368478a3c88f4a47bc394c07bbe88fa1aa1776f255 -aa48418728684c9a10992d1851b69e54529dbc3548fe46721758ac6b33f82254d56738b351d146268fcc56a9b7f05df5 -962a282caf6f08a63aaaf7ed2146dd61d527144f3fdacf1beef36b34356df50302330598b8602f1447f6beb4439a1048 -b55d325499ce03c9b1c35e6aea30622841aff2a2c225276d677338579ce83177c0d64d78e7d11eac657a30648ef702c3 -8a91b9296e5633b3b9144f61e5436654cffaf04623a864ccbcdd21c8f981618a908e890f61c74df19ce5b6995bc358c2 -a7b6b32333377df24c0b0194393a1487a72a8783e06b1cd00ce6bc39337b34ff58ace57c8dee5b7f0ea2c9a54048a61f -97db4494e4208c9f297b484cb8159e8f600c61a44e1d878b07d29f0406fd32a0c12ebccd42ee7ac4c0bf33ff54a582e8 -8697bc039265f7b6e73c133823dcac9041d18634c68fe16412b4af41286a4164dc86f7e71ab7a493223a84e185cb6f1b -b18a66cf37f93ca0189201811e7de02ee029445132f0fd4209e5efbcef46ba6a28aaaee42b30cc7e97a25b08f4bbb43d -8b69f189f3cfc34cc3968a07e13d1cab0f5c7e093027a9fac38504acdf12e2defced4261a686a2fc850336187e017957 -96afba402124d9ff7048200acf329ccb4e35dabcd609e62d04d25140729e110a674849037e4b8aedfc99c889b132cfab -b75a809fa3b1c17139962bc22ddfce47d38d017d585a4e76ae1eb8f02849551ff7bdae178cb4546067bbab45b7041ddd -89196f1fe0869f2fd18f5c01118853503d71c4073aed8bd9cfaf694ca4a9e87974a9ad6e37449bafd391a2045ef5cd2b -ae52921b5d8eb5df7d4923aed1afb125cb98aa6606f8cbc2129cfee56ba3cdb7225a30d98ca9271cca67fe39c763d508 -99f1cfd27833fb64905f8678a532aa984329b2369ade3860025ad334131a9550214297bb2f7d3569eed7a9cc558a5922 -a77fabcb76e8c6ac2a5196666e0c75c7f6c73fd8a0a5fca32a454a9457870689c83f5821f90f28dfd91abc3bc62ee761 -92a4b97b7c14ec14c74e06363b0ab2e263d0d7d84125e2cfbf659bbee996a4d8561992e19789e507f4c24e5afbb91b2d -a2387e7857600a93de57faa0484650289c7553b9ae5fb001d011f43e5bf31c010c9c8b5bb82e7000465b546236e79066 -8641b6f2dbe9f0b83e0a7ad8098b0836af158fa2ee6ff1bcdf3e2ac8b3d25d2e5a24d515e9d549feab4e82b49e468fa3 -937306770a47ab2d5d2eec4bd6d9b3a8ffbb8c8067504571609a7e7a85c665b34ad2662701b67858e01530907172768f -b6b1b89f261e56b0cee15e2f5284c76789db26a6ca4762500745e260bda40b00b65add4826be6131775202c8c6c4247d -b1caac20a1b2aeaf287d38d42987e2c381e74495d9e880eda3ff59821d5974d01c7e3c611f4773a13ff41bef0f2ad44c -81ef049b849d7b0a732579299a86f1cfeb85f27ecee4280066dedf6024159fd47f311f1ebc46b58f63f71735a05480c9 -b3b6b657e64fc154eb33b6056b8279ef736839b56f2c8f8ca438cdaceeb5398b8d3625676cd393c196f664d7baa3a615 -a450678001e8db1ebd8fbd5c808c99945bb3549e834a346cdff316ef8d3b49b818cf9642e5b8097181cf40583ce901b0 -af3edcbfae3c8f368958cd11c95df4682ed10f894f770783e967fac1eed533ac427c1d4eee51f968ffdef080593ca262 -8348eee6ec1102884929736d6768477029961c3d6d09e9ebf84d2fbe55c0501165f274fc1c0549ab831388d431e051ef -8d799492659dc44aa38262f8a4ae37b6ba6eb10dd20481f652a1c77ee9a4529efe042ea873c13bb2ba3ec4792b167c14 -b4d3962f574c3298ffb0958ac999367db8207dacf2ca9d563cc1efb42fc889e19b7f00db15ffa91d145ff05eed97c3bf -a3a7c0e45dc8ae816d8765bbf097502b56651c0c11a03f476e362b64ddaee223128defbcec5629f4d7f1f9c3e4cb9f2f -951036c2878582d84d90dff79ecaca673df4760fbf9e09e63d35facf3e3257be6e1bd504f3c3daf8ac1e91d306e80d6a -8ae85094b13d349e60c8f303550cf4b01e96e24fa3a9f12d44c9822c004f1b3e9cbd772a2b4699e54023176074778993 -a7292b61d2667d74cf62a47aeb559499f19dfab2a9f41f16e7b8d6e77909457eb2aeefadd9d3d3f6db18a438ae53ea0d -804310f5d2ce8bcf9095945f931eecff79f999ffdd24abb9e91d92f6e405decccffe4a8d9e731c4553de79baf7a5dd98 -a77d3af0fb79b6f5b6cb640d04f4e13a28f8aaad1f60e732b88f86de547b33117386636d1afc7bfb7bd1d4e527812365 -a431f239ffc68f6b1ea13bbd45675f0323cacb279e11a14f664acbb15d1673b99cf3603b335a100a0e297c305d743383 -a64f4c28cc36b86dca65359cfdb50ed3dcc06fdb22ad567c7e0f833c880e76a53c330720fc2b96235cb0638394bae41e -b6fcd2c047de58003e9af3a416a2cdb143899441d82c691fa46d89045a12d3b087ee4603b401287a0f2629154bfc9bdc -a06e3b863bd183d8f91dea6d0211913663b3924f1e3476cfe0f328ff7c388aeb8e5c97757bcb56992c104ce0ab6ff27c -aea78204081cf5d24162686a824ff8e72fc0f88388525d646af7739265f60695b7d80b53cd1ddfd046bfcf59aa25f5cb -a89f556d42541a655864adcc1d5d67459ab488143e1b4eb48c67af30a8e753541fbcb479558ac26e1fa498f74a59025e -afc385b6b08c355a05fdc75e9360f4ffb384fcd74e8c9db34bbae9e0c67e0d1fa7efbff4160b387428ed58e129fcc027 -9428d05e17e5525fae515e1ba3f04742fad1a43baa2ee166d2f9431dabb46895b7345ad833d495c99939f0c57cbaf1c3 -b7a62d36ae55e681d48c911e1a433b568871c65a97916f939bfd638a054d6f1136a78c96640779ce1e3afcf90e3bb23f -a45b6d24930d91fc610e57ee78c6dc7557cb2ad976cb92e2157769447cd7c9a6a040f1008be9eb5dda2a7b8c9e524774 -8b24eddad804790df3ed82db7c0ba05082c61a81763c44c98ad436dcc7e1e89a2800ff9c2deaf350f6222cf4278fdf9b -895409dc0aba4d29ff322d2414b33c1458126c023a3d53b25b9038bb90372b7c20d3e9f6b791fcf8f76449fa0aafa758 -b22767ed218b575f397ad8306ec48fe07e8dc3a9f2f090fbaee411b6ba673a1258785d61adcba007d748cb019c458fd3 -ad4b9e4164010c4ba05a23f9a46957c8625fd4281a4e76f76ef7b4d6040d2228dbd2e6faf22b4a966ab42f32467a4655 -92340f1051f88c25a915d0504c1413146f37f709ab060e3859b14aff9be7f8c91352dcc3fc866910a84192d301029cc1 -b4e19bae926db3e1e295ba856984b32b796d86cbc81e81c6978e989f5331f27ce9004f90536a741ca996d19f998541c8 -91502e2a69aeac8e709553501311b4392dea3d5b6f14e7523bf780b8af246e1f2bdc4b29fc4ec3ceb725fafa31bf51e0 -b20607db1bdd6136130ba9683d581f5f45d8623ec4a2d35946723e0d8768654bdd9aeed55ba38303d8d1e312bc4f2442 -8fec23ac3b4cde8c18346dda1afb2b72d4af1a6c013dcea36cd8cbf7223626690ce933b920bd9137f673d0985b64d54f -996bba551ae3b76c5aafadfadfcf80fcb554ff26e6a9e14e60440b3864239129734115d11a89ba79c19e452525cb5a39 -a632f25ec68f02f7758103caf613511a1fa2e529e0861f286b4e490e8fca6874af2c13e3aa6ca97c63f3c621c197ae24 -b332292c6213c7216bb78612457de615da878619024626383914f9c28f835f1289818514038c30eb2bc3566d2da470b4 -b5bd5ed7e990ed8abf7de268aa1ef7ccf5562cf9c92486c2472051c1b5506bc9e72594380e7bd00c91771ed4e9707851 -8781393278ffd5c522ec450220698328e60294ae1e35f60b25baa290a125cc47fbf7435eaf9b22ea819d431de0656f38 -80a308c1acc4363f9bc54e6831c5aebca2b2af47d699a17ae2fba24495984acd4a25c7c95b96aeae3027f0fef9549284 -94a55b36389e05b848c6d0e6426a400d1596195c2cfb4a972b6bf8abde2cf86a932b769a90b62a65d0aaf388e66d516f -8d29a5db4ab3a1199946a79ebaee9de225284f0523637f90e4ac16fc609dd3dd5a71072c30e869fdf6f057b7806ec254 -99caa565547b13953b91f0468b78551784d947b5a3fe1b7278e4a45b294f074a93281e9ee084647d1b24c83b39a0cc90 -aeee1c88769e7bae12f163a056d19b0090c7fd866d451963bc855bda2736c41500bb97a8d72a1a077357419ca94bc3a5 -a94bd8b793a57b4fd79a84daf1f7fed5820bfeb44cfec0248f6aef130fb3219e1bbce68a6a55d332b124e1cc55224c51 -8528607774d780b31417bf85fa3e54a94e4ef6e8cc233ad2a1dc795c68c299abae209c46ba77c33ba74c6ae75ee004a1 -930f2c302a87d6bd159bd6b4db43212e7c806e17f572277ab14dd9715a435bd67b3624a9e72d9a2777f9b2080ef5cc36 -b50d97fd2fbe60105dd1dd44cd12d8ad62b8a3127329f969be917fbf10132f1c6c6fda8029deb990fa1ed26e8c220c39 -b685aea07aa1a45941f5eb2a593c0d97ecb5a803fd2977783488fb00fe6580c41ab83ab6cdd678704311c5542129c510 -8cec65b68f4b3b10d032d39ec4c448e6d76e7615560bb754a53c4c6929c2470a884e7d39d9f3e58a2a9f121ad4175a34 -96279388cc3e91dba49763ef50faa7550c3b4c277b2a0b0ae3541a2f990f9352748db75755a7b13efaffc9b8df40c74e -a7599c33614456b1b02b57921cb76b01109811a82f230f9e7e82675d57757f06021ac3f514d557ed9f2dec025364284c -869684197084f42dfd95350f8a54b0c7d940ceae2bbe49ec18fcfd178b6b0d21903447509e0ef356aa3d2aee83701bb3 -85e9ab73165878b93e0229e3384f048e9651ae29980f9c5e26492c45e180e09a3af9058fada434d1c398b43d99d13056 -a453a46ae96e6330c1b315d1b5f37d160731309d49d13d6c38c5d7f0b4f23ff1d18c985c471564afb54e4477c5d28d19 -a5999c704320d4468f94d647d83c9e8720c19782d2a03677143c7216dc434b3160d193389b0115dc638f6e2e12f2d441 -abc7a466cd848304616b2eca049c4b7509c5260c9236dc1432044ebe3e912afcc3a6ffe3e27d5d79d3ad4636ecda09a4 -89ca07faeef1118c6b840a2c328fd32a5709b31850057302a7e607891e11f3f9f62e4fafd420564ff10a35b9a44c0f06 -b0002f9d2a8aa850b9f22dd8d3b7881e8656cfc53e6c2ae6a913d88f6934e0062f30da2702dcebfbfafe36785203cefd -b8527c70bc791c87f5fbc67e2856e45b7254c5a0b673d4a5d3e9b79fe0715b608a2f35d88a61eb1d8d7cb615fea650bc -b9be558dbe778ba11fac7080789522fc004510f7b740c42023d850946933362a173267106aea046f338533e4cb29aea6 -b021f9e635e64d3c9b4ecc8075fb74cf0e5727ecbacad15f822c8608f0d981ad2c300fe6e47c6148a6b1a13cf920d85d -ae59f2a83a1384ef0b5613e8843cc9a934f7126430df7cd7f5a8508e3d83aba83bf3d18be7380570b24ba0e00e05e0e8 -b403e4d0495a0137a710c43393798593bf131cb8d49beb0f3b3d344554dfc3355ebee14e884f543bb94bf9aae40aac59 -a73b722287df7558c503f89d113fe0c017765c73181eeaa9ebe6de5c8a15ffe76fdb85ab93051a6f565653046624216a -a7d1a28fe1d36b17e37cf5eac7e27549ce9f6eddcb36203b58797d3372371f3b195cd3432db54aae4bf99768969f5b60 -a3447ece13c415c457b899d4a8b8ff388ba25bc920b5711f8687cc86e9c1b3f3af42c490ec6352fa8609b044e642e3f3 -b12f2ac1e033b6a627e7f7822317f629c896c8f8dd94ad91512855882dbb10b8e80a1e29c3e39138402f1f7e0de673bc -a7c65988996741bf59888415fc2264495050cb13500b6597d9d0e034898121b605784f681962cfdc80b0af291c316e7e -8c40cfc07dd7a4bcf514f2e87a1830c911e8168b0b8531a2838d2a14e790922b76c4642ae237b7547d8a3625decc7f0a -b480d70b57434467a40d6dd066f51b9e637abd2f49dcfa6450460aeec2bc895347e21aa82baa1bec7589b6a5a694fa73 -a919a033c24e96af1eb0cb1ede3684e9a3bc338c7ef37b67cc9e9982586f74072cc540981e2d1a2524e99144bb21a64c -921e0b350907e9993a596b80f827b2d40aad60e9c62f4b65a67d3fa4c0acfa924c93352dad6eb3e868264bb24904e3a9 -8d5419cea0bfebaa9c1509cd748c8af3869aedc3ae27fdbca3a0f08b3751a3b870e8dd3640f4abd4b46a2a1e745758bc -8b25e6eb600de81fdd03584fb9db9a7bf4c154ef1482553d7bef880bdc5baa7b64abac6db96fcfc4408329adf8fa351b -88cdb72bee7a6768b7c24d124dd5e8b29f0c866a0624e5a7c4759962ce1d71de7faa97f7baa56d5f51e35bca43862bee -af1d59add7df3b3ba234b0b4f758349225b9cee65691c102294eb7e6fb683d7588fca33ed97eda361060253acfdc36af -b19370b8fe123f1dd2ea6d5bc75e151b0d1514224f5824437166fce77ac41ac5ecc1e7c1e75b75e948acf04c420efea3 -a1ebfe84f1c012524cb475e68ae6c7cec79fb3372f1380321a0e306d15828613589567efe8bb5784360aed568e26db49 -a0f964e3cb594c359e2308defd3eaec476a638b6e1c216157009e11f7c7d0c33fb9e62c4243057cbca49ba315d4b508f -9391e5087374e45f03d36f6919463c473938a653adf3880571850374ef0a0e521b25ef84b6012a19a02ec88f0ca3891c -aeb86d4426d2836e6e10c3277583a37b6684ba35f4f30d2d073043f0a0148f763b99fc42c3935026b56c32e5cd0cecfe -aa98c07dcfb1b0a708486d83763511c7004896856e851bd83d25a9551efc28f059c3fb8752ece0296964e8c13ec829b0 -a466fd8dc1aea7022a86e12a119b16de35412a1b461680f6a1cec408e9b9c1418a8e406fd4a5656c73488adddf17dfba -8c9b0e18a033c27731fb3d22b7c83ba7a86fdc2234e8f2a19d7659aa67bad7a85ef25264e8eb81af529feb3fa9340ef3 -a371feccc2f1a1b96ad8a9a7d8db0c06fefb1f2800933134299027459b0eb8cd101b9a37c76c22dcbded01a74b13d465 -aeb34fc2758d8b68d17f15ab3c299344ed630f7351c498a5fe7986f7e14d62e74ac9a8f5d2de7c6289771210539383d2 -aff9e961d0acc71a077e3af52ced373bc694f9154302abc908710e500e908f33bdd10b3c41bb8fa8066758a18d64c667 -98bd5a8751e598896e9aec90649294934f81c36d2d0fb60070e9b96eb47d0988f71d9b68f4c475477eb4c996a9265c13 -b25a92c6260f389f6443a572960e0a52ab9c9250d8760ed148082584b2347ec7d103358c033266bec02374e69d0102fd -b876968bedba7f4712f5e5eea605c1e5fc40bc5773c61f08c32e0c0f3ec575eed3e13e48809983153beccdbca2123edb -8c4091ef8946c9b27490099d5c0b47c404b5a1113500592515deab1c3f2778bbe933b09c9824a3a7ccad2141f9b5dcc4 -ab85f95d318ce235929531e2e397d09b9906c58958fdff1209a514624a099d3b8c103a51b2fcfa0b17a8f008744b5d71 -9016714cbe49fac5e7b3e493574078c462e18f6363f413270c23da6327731f71e2dba5dbf1da6bbe0e29f57f0c33f869 -8c90df700c0e2d104ce7b76be7899209136498999f78195cd888aec6f069778d657e5032ad7db56381470dd1f519dcf9 -83dea8472e8418aa069a0837a5c44835aa1e00979a217f6295aa35548f509fbafc7db5b31b8767621e4f89957892e8f4 -80a1d673220144973ab70d977b94cd3d6b8fff7f82f23bd4b30ea393952951d2f07c24e6d411b2ec19f3bec13583d9fe -804864b58f9747bb3ae54c588dff46eb6e16b6d98e0f711828e97d9f019297b743aa2202f823e3153ef5bc4b95da3501 -b08eaae2eca2c64001e1da7d0e345f96dbd3e09888f9ab86f178718ea5a04321a8b8633e72dea68cc05687042808e3b3 -b962f91819dc570c2cf131b89882fb2a44a999b94fd1ea8b83f400e9b66075a35c89f0fe0e8dbc3a597cdd1aa3135888 -a5f33e8f04a2d7aab44e832f8ab4640519aa4ef88b58e0a398e45347492b040043e494de4b355f07cb4bc728b67f1ac9 -8ed80bfb4cd15bb87175cff427c6a1bfc3e6292bc5c2d04dd42b497bc068baac5602d41366448ee7f37d85a5d8437750 -83441e746afadf64583571a9918ba5122ca987e76a6e37f98514b1a8a178380366d10ded5c70d4feb08be6fa6d4bc25a -8807fb8adb2aaa6833960f435ace162c01a9cd0692a4cf038c89ef7405600868efe7bdb3e8a3db48901367ebafb0a1c0 -82c64b1f77fb78dec00cab089cb7a88ae16c72c94d0870bc92df11587feb62277eb941d2f7d3d2fb033d7bfee12013bb -ab2f1e3f1fcde3b8b2c07135acf3a492ae7675d9bc971ba57e06c99fdfb39e1f68d1c826cd9bba872749cab375e44009 -b4a25f1f5a2aeabc29870ab9a815721f3cc031ab1a55417b457ca6504e5e96e4fd0d2d364ae17738726c8f40cae9c36b -9519efa4774cb4de4ea834376d6213d946fe6882e2b36342f683762fe50d754765dc301569a836febb2c7c9dbcf44f64 -a75de0d0320e8cee962d6ed4b07db718615e75543fb25f0d28ec5e76f56d72b18d648ae42d7bd3da18f54ec1e4497a08 -a2a17aac11e732097b25c0b9f7b97d807dd78ecd33d88aea5ee0a46a42198d379a241e888ddba940b3307e9c560ec45e -936ebfc2234d46282ec4de88958553759d766f682d6f9669d2b77a2cb0cf9cea9b1ac02014ac3f5cd47dc5d8af2da314 -b33def3135e7ad61a660ef1266d61216220c7e0bdd867b727ff3deea904072e33a195e4febe64ee1e263349fc9096cdc -94337e4f14752676a703fab8544ea0ab7acea0ef924b85b05ffb84e4476f1087acc9a6d6250893a32b82f02651a179e2 -8f22942bbeca0118747a22d0aa13438e40bd6a383e310eafacbffa1490f5758504da4a11e6320e1c55b3daabc72c63f9 -86e3ed934fc613d0b3269cf368e32e67f4add59e4dc1ecb1f016fbdc6c53101c2435f95fc36625aa8c69c596acd9b0bc -86f04807460e1d93f8eea2a284119d889659b5a6b124d41dfb2825b31685361e8163fc3a253a49cf878e316463c9ace8 -b043b2a99b94661ef8b270842fe4d3c51891ec23ba749d9c999982553ecade6f658242b373982c9a3669a886889e4f33 -8b6a33a68ba7b5932ce11b3f0e23c3da580510fa37668f2154c59c3bf788dd2276a2a8c66a6bba1a68084e8b9bbf378e -b54581c88d4880fa4a0ec6d3c17b6f0ba339e8f7100242efd3b820ac942d75d1f898259d6f1e64a3870fc301d9dea2b5 -9449dc9bce23c7e3b41eb34789dc7765c2f7855f9670c1d145bbd1b2d1b47a9318862ef3738511b4f89cb16669c0af18 -926245ae9d4eb213ebcb88ab2d7e2a7d198557721051fef4cc966cd11be3490a3f83d4ff48f5fb60cbad9c5de4b98d1c -8518dab07ab15887c68d0de9fe3c0c09ea6bfddb99c145b3f6ff84659e7799da93e97bdd17884b228772398caa8c2ed3 -9969575cbd7953b6308391e9ce2cf4da466b3e730c9cec0e88522258639be35fd31abdedd94b445d7075919482513103 -8b1f28002c19b17d6ac1a6f50afc3448f390b3209b1a76a9a024ceaa274de4588ce82a891a03e878ea08747ae5d98211 -a611963d1bc45b60ffe6756a743ab379e4022bb3fb263f5f305a615c92432199c7e1060a79aa42f7662fa89a0812a4d3 -a3c7706ab74e976464fc341e5a9f7284264c1610fbff02fc36b88e15d6859fbf40fd8c5e93c8237b97acaa0900a03764 -aa623fb8892dbbf4fc02004a44e07c21a422e5553e4b02fcca24dc1f416a54eed36f2f7376dc1e66218e850772676e99 -8133cccf10b1686bf53143bd3520515ec72e7295f6945c43bcef7304de597b767265a3a9f7b281fa353acbc3cf6997f1 -852e4aaf4da9dafc988d0da13a7f31fe8403f6bdab88dec363eb8cb8d3e64c48ff34102f6660642749d11d69b613f8de -a616028c6cd54a6514fd9f7aa9ff13000eaaf39f582441f73a3ed8208a513b580eb7874b5cd0b1e9a542c40c5887bdef -a48ec58bc3bd4b512c21d3d55618e9c51836efa97cad42bf79e748542804114714db23d79ad03e410e0989055c9bd46b -ab480f3750420119ccfcf8d32c4a18ca580ce88bffe81433c1d6999c221c8aac482de5c0e41a5531806bd17897698d6c -8522bf3b7157cd29e948afc8f479d6192364a11f85dd5c58d4ea0443aa6b655f55a80e6a3152fc02a8eea4c0815fcf19 -86c91a6021e738103031c1ece906ff43227eb23088e5ce1b6a1cd58664d4a80d7bbcb0d56c3b0e02cba1e1c2ca22e058 -8ee51a59ce6becf098256e19c9aae5ef0c2c9e66c587d9a32cb4ba1ee0b64c13e2e008908e35f43314316508956654ce -b94766a0fb91c8de2338a68c4ab08ce5bcf62f6efa221067807dc647b595fe5a342d7122111540a1ca6ea7743b6ee772 -83f917b8f6aaeb9eb2eb742546e3f2dfc9cfe00cfec60051010113d55dba2421974098c157dc2601902d8f40bc84693b -996e489890dad3c4dc35faf53d870bf1cd76f1dc24e0cc8a1f899bdb44e89dbfc77fb11f7b33c270a1394c909f7a27f5 -a89936283190b2d1ce8d166b36694afddb4c3df01bfb1fa7bae69c55d1acb4e68e5e29867ea33eee8031029b3c6409b1 -b08e5a5d6797ca252d12428b2086e528a6e5c3965d2e5ff2bf83bc71ae9c0346a4ceb3bb2f2e3f8a1685fc343f36997e -a05bd12a7a6d52d234a1b3e9ddea7b18d6d41026a0d18251b1761f1cc863064dacf821707cfeef2dd1c02536f584ed94 -87c638feef9c88a9f89d10b56fe4bef6406c1d734cd1f01006e2f2b331196a49c7184c10786e855b3de8978927df42bb -aa194f3e4d0fc1d3107f9564b13e6274bbbfc7b8c1e73ce6677cc66d9319dc34b5a0e790d6d44c614c11feb50530a252 -b2ab7be7ee9d72d1015e94d006020e758b73f200dde81e89e52cd33f25aced0cd84b8c300413d32565c253edbcd2fb1f -8ec08b22265aaaf27a84a6cca5f0875a3ebc70fb36c4f5e59d60c55bdf2a4fe11ab7ba4b387f5d668e67682a0978fa46 -93643b9541db11b48e0c84caccc8da9ff7696717aa176ce6d863446ef8d887f3159b0ab6fe1f79fac883a371f6736e93 -8325654fd8388ac96935149165fa3238d0848151a04be57f2386c3304056013efb49febee0a871cfc2ee3c11bb029042 -a2c15cbe5d5167f55f2a454390b61d99601614037fd67fd198968531ca2f84f3c214b971ef300a20a114fabc6c67db0f -b40ed63b0367174b5b4b08396afe2385b0f75ec2569fa3cf60f87e1b17fdee888dd66057be2cfb185e9f32df59b7a8eb -a466d2c8052a115f121177979620385bb07148e202631979f4ffb01e7e0f6fbce28747df9bf70b2168653096aa704fbc -99395136290cd020cfba0ca896642c245182e2020ca2299be8ebb2f62e2fc62fe0be593838f62681f6632fbdffd640c9 -8e4f081d9a724bb54fafb66297a32f84687493464550c09259cc6f8abf770d076a514ae1d6726cb29349e27ef69a74b8 -a8d5c941e7c03dba0232c763590e93e3d99fa519b0a65996d20dd20deed1d0192738f3b339edac68ad42016223733582 -877baee9ee979be8ce3bef02422e57799dcadc34fefd8bf2baaf945f267883f67211ac5c06246f7b49f1ea5c99550a63 -b6fcc2a73dbbba54760d244bc13e1564a3c61097e9b525b247cc8687ca08625a7330fc6b15e45a3ee508b4d34853d852 -adf720dde6e9b5c63e361d69a2ab46ed73e0deb82f8e30f27ca2b19c2d8fc43e18ac04b4fa029f553f8d7dd79457ecda -8956c9038f3338f541bae9ef1f5bfad039d532dbbbe7814e3a3d5442d393ea6114aa666559d8a7e3a026c758a17c79d6 -8d6de7f95f30a5a4b3d441781c7f819a0265852ab78b8416227089b489787c8ae9dffbb0bf88acf1b4c4d6b8a29c1a53 -81d4efd71c9d08e9f6d7f7d7a2fa5089e80cc3f8dcc685686aabf3b4c8bd531b4aa07e328c0fde32b638f23eb78de588 -a30053b681ed8328b5d64587b0d38edef0e366a2762cf5068dae177e4f4084c4333f9a5fa5fede93db80f7a8fd5fbf57 -b340ddfaab2dcded58930e5dc2b72cbedd0e79ef652f34356fcf72054a87fc2373bd3aaf8a88af8d4633f73dfa7d9a28 -b9f3a7809be0bf834bd7affa2059d9371b848dd5e5fa93e83e90d9e078a2fd3aea64410a72457c32d33ff1ca11dc9300 -a9a8ce26a38dcf277ed66d75e111b07348101e93d03f446ea72bd903198122f8a08569f7125f6d4ecaeda8c093a00ec4 -81e78b705b44533e2e997f549f46723a5e6b88241d7a86ca20448ae3ab140e967347abaeb8700594a0cddf1e82285abe -84724094dae5b7ece30cc01b5f2acc8787de57dc0c37a437c3e8e26fc03069b6e8562302a0f1c95de85937f07fe63d3e -97a715861e5bb715a17a948d6b6a389b89744e8ccd3699fdea9ac3d890fad027b78d436f8012b0abeedd078a20ba91e1 -b710b2e7d87771416aa34ba2d93a044bb118f279fff62c1224c150ebc30f21abff212019f0f38c334daa5a96598ab900 -853034af5ad08c563ed096ab2d0590ea644d372cb400bfb03867092768d90b7432d35c5506378d001f986c59769d6d56 -b340ab52f751e9d516348faddb45f0115ba0619ec9db820f870007e3a4d305ba2bd0b2a58a7576296531fb78886b16f8 -b8ed8feff520009743ca3313899a118df025a61e6e03bd5fd27898a23beab472746ca3636c22ea3835e9526e17c06dc9 -87af435e3e4ef611d6da74c8d98e8d3f3de64ac8748105dc20287a7dc866f57d10a2b854f7e0e09235eee647dae1ab86 -84108b1f0f0ff73a179cb1be1b2ecb4268e7fd2fac3dfc7f6f99889c90a33b4310946909b9eef31b256b8d0e3ba56bf8 -a6b9fe966293e60bd384a1e4d472b0a72544aba41b31172ac8bfc3e19beaf51da54a66625d73a9ae22c7c4d1b0840a30 -92e82e92aa615e198ba3c83c039b0adcf4393b3fbf9721b2e47ab17a84bded2bc8bc2bfe257d2d76162a87e8bc7ce759 -b9286dd48800606b7ff9c3fe2abf5c49ef0a6b981711b5ba1f62952d6fc4a9999bfdf061c4664a019120f15e341925d0 -b5da5dbceaa7e82f30fa5fde88b03ea88e7003a50eeb53e3f3aeaa63aa586900525b42fe1b699451b5d915d1b83c3705 -b06072869fb8526d3077cc61a3c55d54a7a1197bbbcc875aeaf617d7d1eff3dd3ac243e2c76caf57dcdfe306edcab4d7 -b132db9ee3ed16e6d76db9e6e3dcdc2b142cd70b9582518bbdf5415b3bb476ad900d50004dc0ab6b87ba697c6314b4c9 -adca92336f3546ea50b034525fdf548a36049ca82d9d3cec10073e7cca186227cd662d4d66673e7214a6ed58cf75da6f -81bbb3fa241f9514575fb3f6cba8e34301187681354c94e7976a4205c0bb238dab52b29a76a5f0e0d4cb1bc82f8857c7 -91008dda2bb7dfffd6746e3544ef540d9a1ac7ee9c68ca9984a1d81041a18fa9f35b8c4bdb44ef3a860c37481d5e9a14 -8224195cf18ca0d8f01521a0ea92c9c598c556746c825a4dda49ecbe324d570a96775eb81dde1d3a14aa3660d50e27a4 -8b355eeadef5fc7cececee71aec3ed30349df8f43f25da1d75d62ab00fc73702b405fab6d422053c2b0fbc7469ace9a3 -a4d657dbf2bb30c1e57e0b63960663bd86ce17204979a9ab82624943ea370119f040b58b067a05ff6d1867a22a58698a -9379a367c918b2be61a9a42a495ec03f0168a4ec36f753dd37eac6e9f58a26c8510ae7b579a89afdee1d192edefb4bb3 -85b37bddc80754f0432573204a1a4b86a550bfe9689f6c710a61810aa94dedeb28763ece40f28fb3a6f3791ca4c86b8b -b41c3269b96e190e40cc16e6c7cc8054cd0b7902a43c69b79d8ce471a417d3096b2271badfcdc59deb6271ad3e5a35b4 -941185020a227b7a995f59805c8900f7f6ecff1e7b948a8b714f85a54449a0d41e28db5e17874e018eab72ade20eede0 -8a0795ce082f74e4633acb1649b52b46ea2b4360860fef6ec107910e245b30466bfee8ce59a6854f866f55ec5cc7bbd1 -931fa63550530af5a7ee24964b8b4d0c66c2bd59108131f375c7de86bce59cf52890191ec8540666c895e832dc312360 -8fb86918190a3455014a5cbd15c7b490d68c10cb7b505e9233b3eacdf52e63299d49ded75fd74f8c2bcb3632a9c29d14 -92c896826c9d871a83c4609f9988cec0db6fc980c8b88a7baeea2856ec2a0a56c3d5a846a87d03393dea966b534aa8c4 -a9d4c780c94384f5a13cab61c734836f5729482cde62f2888648a44317b749135b511668834d49296ed47c0a3b9fa8b8 -b7c26da09c3998367063fad19340f53217e8545535d376815773e201ef49e9e1b6bf1423b0b6bb363586f5f05307fc89 -8c445b3655f1f554c2a7f6f7d035121939a8987837dcb1a1663586614dcf2cf47f73633950d8803e2781baaac52c12c8 -8764f924f41d8c5c91fcd77de26ee3bbb86d5a5bfbcc45188be453c8dbe4b875fbc5ef5b01ea3a26b889d7b45417f173 -8605a8186d5716dd5f955a7125619bc72ff385cdecb187a9a646a4bdf6595d67f00e777836261f3a69c19d2e2cae27d6 -a97dca2185e4fcd7583b1e695333d55f54edd751da436b8982de8c344b5f57e35ddb61ad4a611dcde08e287c78c757c9 -b11c576a049f93e0731652f1a1ade62b0124cb7b4e2b13f6505206c27ebf7998ebdb3d887bed01e43ce5c24714903aff -a46dc516b8ab4aabe35f38af1236052564b01d66c558e7107175064a5226713e8550912867eafe4da133f56950df57c8 -a13e75bca5bd3b08030205cef4faa56a49e5d7da94bc41c708deb2f65343c1687aff26368915a490b89006185f18fda4 -8ef5135a6f1f635a4966aa540cb877dc98c6a88fe462be3226c1a270c82cad8e091aa49ad39862f012edb3c93d15fb4c -99158ace79ceed67b6d8e884050c6fb7c7a1509e41f0d2b9069ce8dea392f17f88303d0942cf3c0af3ea52d3194123a3 -8805c76ada9dc7e57545a5e1a874e6105592601213e22c1601b0b157b622e51f004a1da754a8fccc8f2a2241c14e21a6 -ac3dfe87e17ccda6196f621008716a14be4b983d187265eabb8f5eba7268cf770a70ffa19d1c7e77fab0373eca7a4045 -ad78a31ad6f2c84f6e5348f33631d876daa3d5978f6d1a77db80aa219e12c9ea656e9c18e6316f899bbf6c2469cdee37 -8c8726f8f6fdc40516bb64b6c624a6eb4caa931e3a9ca8ce2c31c282ad59f0624ea290b804ba84e339e83422070df419 -9303d1906cf416a184e15f13cf7dbdca5fb296b078079782c9044b9cbfdf06b0c965305a8d88678b53f0a10220e56f4f -99b9735a77cdc1c675988e613b3e8843e2b0469030a33f5c14383803a1b20e328d45d2fde6ff0d15f6bc2eb8da4f4d88 -892a18f4ceae3fe7cde8f32b84c6bd3d9ca867143a30fab4f939281cec12587929faf07225725bf33ddf154b90972214 -a100a35a2865bb465830ce2f68406d8a92bdeb21056bcba28c0ce8ce5ddfec6e293e926d764499e53facbbacd3f72994 -b797ab22a57520a0584edff499cd1aa1663d8b3f411faa542022c5f1a645a3f952f9164f61d200e4500673a8d95a938c -b1a457d100def2e26b2b30617ee866264a3ea649bcd9edc7be132f5cad02f3209f5dccb02b95a462b5af9a71fb88a341 -84c1f6d4f29869a359cf89118b1a80224cb574393fb557d1c61730a1fb1884895c4cb07f23c52165975b89fe9d6f5a77 -b6d53e49025bcd1d7960ce46d4f64ff8f29e4239fde1b19e5167d506b086152da3bc3b86fec8ea531a20afe1c785fa59 -9635b053c03d1be0bdf81e9876c63e8541b793ddeeb2a8f3ab0e44fb78f81a9e61f8c68ce393c7c959b62b67f9724409 -a19ca9ac5a345c96a607f979a958d83eef4350ebc9cea0e0aa11469dc554fcc39d9b22f8a3c92de599ca08ff4152ec23 -8e7d45d35f6fb95799846fab51b0ff2415857bb54b049694c1ebf93f45167b8497c3341b656f194edd5804195a7c96bd -87c05c7d5834394507ad3d363dd0ca5132a7763644e354c3b7a803fa594d951084d37942f59211660f10098cf49adcdd -b276246af578557aad38190878111e804db0f29846185d7033c913a31e7657d035114448ddfed2f3d75c04c79ee01e79 -868bbcf14f96547192053823e4f85b50fb988da5c4cf73f5cbf23953252b665ef7aea4421c8baec90522f58f027a2b19 -ac2be3dcb8082b64a3745ce0d2b97cf341483713e1bcbb37369123d6723968d3bad1410467aac7fcd3b623bfb1d90d9b -b1e5cf361e0857373814e8db7fc275ccc1dbac8559e8487cc892bf82d4c6be00d1b2ffe40289692a70072c5f80dbacf6 -98e16a5854635c72bce6e263bb57c071194df076e1ddd81e645884367b730d4d557ebb8c74b3c582e09046d2b9ad8078 -a0016bfaa348d44a3ef814b348f7d56fa83b78baeed4a7b58617b6f4772dfa990e912ebf91c2321307884be85dbf81fa -85690a2c5cec392b6f98cd2d03e4204cc51868612543c7a3112066ebeefd4304c5c8b21da44534224398648b413634f8 -a3a1d00d0fdd8c8cfee153347d590ed78cce48eeeb7ad42032a95baa73cc458d46882d0e9707f3dd519b1844f236bcdb -aaf2774fb26da59c115a28d86f0c6320368fc6d2c0bc2b7e4516cdfce3058cb423b0026b6c75030ddace9ccb7f058227 -af507cef7320bd003526fdf43c04af46beaaca5b6ddcad835ae14da60a2ce732b453d8164553e95f2b776df55ddb5efa -b2656c07a8ba2a2248d0313a7795b99f5acc120648c08e3a77fff5cb9b861827c94d4f2f99a2f2dec1d1667ca3ab26af -b426b97a51f0439f2da2d0d934693aaf52482bbb48893de12fbdbed1b2155e30791e7098baa18f93ecc45f8dea4f22aa -a71a7e08426518ef7307c2a1be7aaacd843794601c0d49f4f0e474098ea0faff74fb5ae2bee416aab849afe04be434cb -b6d510022dd3b9ca35e93ddd2ae77877967dd6966706f339b2197d2891bf523b5d55b7cdc80274368333f9249b62a7fb -95d2f6cec1b4038f56c571ee0f5aa14fe5fe7b9a2efab89eab4c51a696d2ada549a42095245bea14d7f7ffc69ade417b -89147eec9de685483d0a5e21b877cb550518a1bbcba0ee65e9519c294fb0c422a729bb0f5a8c8e3fe77070e1a89fcdb2 -a66e7116eb277ba900c06fa48baf274e2a6865977698a504dcc1d0c20f90a7030bb2a841fdbfaa5c8ef6d81aac4fced7 -815053a8483ce2a84a34f81909bc3eabefdce59140f0fda6da77ec005e5dcfdbc6f289d0f0513efbbeef0358daf94025 -b480d2b6320ebf29f3781f04dd88e835ad81d2c63b716f6f244fd2b113ba3781001a34189df586cd629e70c2baa0e5cb -a74281bddc3a93503a695f0375121b3bdf98db4b2b053eb2cf0773647f6f69d1d98a61efcf82e2a823035ce803b82001 -b84fb99a6943447cad21bfe2b34dd8da43d349e53e85b73fba8a5fd0fe3f41e7dc629960b3325d08af1544e5dc66de28 -a8d11ccfb0dec31b39efeee74c58536f29abb02d06dfa11acb7134cac626a17ff4e204d1d138a472c63c629b6f8406c4 -b5017d42a2388d90bcf4d0b6e015c63612a0864b2b379e9cebcf2e869e5fd45d2713bc549ea472d77e82fa8750f364b7 -83c8e090de4ab6ed169a033aa4ab84f7f3e2b54186106790b30741e9d87d9a5d61bd6a285447e0d1a8e1865ee618a91d -8db64f3a1680cf461f9afaed4e714709d37559071bcee52e13feb5627c1fa7c093fc8923ede3e70db07563d2d1eae69f -b6d20dce2f50b78b094949e64edc2ce1b077a3258692ecc2cdaa01ec19add246d0832a319bb0d4153198e3a35091d86e -a61e585ed55dedfad57352d2abbf8ab336a999a5abbaefeb5d0da9fb0d5bb791119e52034844ffeecca9655675d17228 -8ff58b27196f589ce0d3461e0c00d695da47a79809719b4bd4a229ea7bc9319469744f2254be4469092b1a27532439e8 -b5edaf7c3f9dad7a54908da0e7a153d69a6bdb99fde07fc42928a0dd38031e32dec81c864147066412a8ca240e7dfd0d -ade064bb3f87431a32b361074a89dd280cc1160a57fb3cf21eea5066e886c7bfc3655fe39099a1913b8b53242b23b2ff -9169621f97887db46384b43ca24b1447e23fcf5abf141e70fcd1834e9d691b9bfc6e8059d060bebdf9922608593bb972 -8727bb06fadf0633fb8137a54d6912cedda0bbeb0f93af97deef3490b1b47e58fdb37a972dbab1534a5172ff0c840114 -91991b98243bd7c138bcb60cf703a9d0828f6791eff5c2c1c5cc7e8edda258d3cf72680bff2c563c8e964f87450a3037 -a1bddb74f5892597ac687451b932449305d6deba20e97e10989bae311d532a7b72a3fab08dd832589e6a22c0fcb548dc -afc52ed64208e4beb029d1428697fea6add02210f613551d1e5ba6011c5d13f66ce26b3dd2a39b30186c566b1af66c06 -929bb88a9e30862be5f45c002c11537780d151f9836edeadcaa4a617b0bf958046ce331e15bee646f9eeb4d9ff854661 -b3376241793ab9f1732997cdf515b9114f88bb2c25c0bd3f3b22e5b665e1ae94fa3f6a9f88de37b7792c3aafddc682a2 -88fef7680a7fb665043264c9733dcbd23e20628909278711aad2e54f2eb8fa3d07011f593069b6ba7ed312d9ddc3a950 -b031434d514d0878b7011ce2840e23e94a4386034dce422f37fde539aa35cedad1511f9eec39fc23c7396f43ec22cf92 -a4a32f1e58c4ccb2cb4ac6c2dd8acafa292810c77126844f33287c8d522bb8c32dd89ce8f7c1dc9a273165b0879a45ba -82e5b11b9fad7c7d5e2a8abf03943aef271ffa43ed8127dfd85c7957b59d7cea56039116edd0b0b992262751c347f75f -a650327144db1806cefedd1daec1de3164b77c02a0aa652371ca0401b50ec3b7a392ef6a80de6d4724892d71cf48eb07 -a88d8370d88379b52bcaaf596c32faba155db4857bbc7eccf89b5d67a97ae481e53e81de6c9461a6719d179f3ffbaf16 -aae8b3d1b1bb0d71f19e37867885a1fd550f7805fd1306881515d77e5f6a990e0bb40c685e350ed09eb4a55298f3a393 -ac024fdd79688628ee188a7a9d39cd1306883c260dbda9e79eaf2d2f57051b5379834dccfc641302cd12a8a24fa2224b -90cda91b9e71b7bbc091b9e8e28d79f0fce42255e24a7a3bbf3348651405c46d3b6e2e33c5fb5e99fb4d0fbc326f77a7 -91325730bf7d71855ce0462a2fd0840f3753964b296f7901e1ad761f48fd133371fcb805c315c4d8cb2ffe34e98ab9cb -b9e1a298ce9efdc004903b21e573c113c771b1bb5b25e2e88baac6dd7bded130016b2f09e50a4346c59adee607a71760 -a703a60c430e365bdf9023c923a04fd9db427ca0da2da8dad6b0f0d5d352524943839d859c15dca64b590ace6cb1ca89 -995a5ef468a38caf66d58880245064a7c0ab520ebf3c9e9f956110a9dd68658baae22ae274a48d59464c8d37d2f8b643 -889c6e4516ece0e0fdb8c99aa482f367f2cef0ae2ce0987b6b602f6c856b02fab27114a6f4b82050738bc98a48ef5837 -b432ce5f638aa48ba952b9c2e06ce822d531c9a24011d14650cac0722a4c5ad1bf22109a2f429cbdd22a567ce6f03094 -86fe41234d309118d1256a9ac79b7bf01da1fdfcfd579b655f31b7c4cdab6f687d46855d56bb11bedd4b0be17e892b2d -905ec536f23dfdcc4f8128fc1c00daa877eb3caded7637dc911aff0e6279eab12f1748949e4bf015e4f8e30626d3177a -b6b9f47cb82244d7b1102b37cb52f5c9336e4c05e4c90f5e448fa92444bef12d2fbcfc39af9e1fd05811f5f864f12047 -ab56e7c534ee1f921351dfed3f3eaa127869849b44540b39b0dc021b3dc4dc94027e4161f7f3ed40bf42a1d08315264e -b9c62b4e679dbb3405733bbe0740450e72ccf39bf953142cce65fe014f132d5af5864ad96167027012c98dc8b8889e8f -82b8036a3fb6f648c6fb0492334fb3dc8f57c32779d4eef78ac2becb0b93f046dd68c2fea3b5039c21ce8e1efefcc685 -8525738182748d6f901650cc328ae498cc3c712300441042441f66c683e06dd741b644e8e98732552e55839b66f86b82 -b625cca7bf4ce510f21e8197b223dc49e7ce245c5a5d1e901438eecf7160a0bd37d0196191b1d934779f4b6a387b6db4 -b63d753d728670f3b63d4c24acc4a3d4859e5f15ad775e502fc50d7ca42b0d2484a8649eaaef9eb22cef28a23e10d5e3 -8e951028c0b4c5a691a219a6dbf348ef66edef60796094d5f6abaff1ad5802b53a5abec9b8b3b3b98f8b5858672847ee -b6b71004d898a3bddbcf7f730b8d5c0d8bba0f3b508155412446732ed9abbc1d03a90864f4689e6ab207aed495830e1b -98f33a74e36c035d9476b198dbf3a75573856264d45313e5bdd89db291dceaf4084917a2242b0a30d3b1ba4ee3016c42 -912fdb4358fe617d7981bf9a9986dade7fe279a0445d7b14951ed77eb88c77c4aff4162467e40fdaa9dafe78da0ab4f1 -b17bdf7a896480ae70b3696cffefbca468b57493d5db59362dd85a3da296e1162356358080c8b0a7f3fde798a3ad1d15 -b47ebba84e62bf453ab223496a892fea2244ba6c37615c3db31c2ecc16a5f9519dd79aa710ec1220a2cebd254f7690f2 -b3361190434ab75e46a40e0ce21ccc251fd0139bce90664bd33d9eb6400317c3210509e4ffeef604c7b05b260544e19f -966916b3966d7d33be49fa4eba925aa2f92adc2d0228d1144ef633dc5d67fd8231087c488b492688fa142a8cdb45ca70 -8ffb1491d4448af82b7cab5409ad26d99ef6ef08158c73a9ee9626c5a84d2fc6d852e2c786c94b47b5931c7194d5b82a -a2d4a5bb458688b8f593f39cce2b27fc05f8ee3985f4c5be453706e8f174d5a6585c2070c0bdbb54aa1d8e79b5ab40e9 -ac180389d0432699bafff42a4c3da59bd32ab1bd1c4b4a4829580577fb3c5eaf8aed4dc61a93262f23ac44255e6c2b11 -87f8fe99acc93080e2a2ae51eba24f0b146c1355855a202dedb7deb8e1cb5c6ad8664ba0e93ded5ce253597fe015fdc1 -a554d88dcef521dbf5e4823bcc9145c8ea98c598cab56c85f101ca7be82297dd7f361d457966bc69584adda6d40ecab5 -86ee126cc839d869c7e91f0f8d919929f66c1f67675ae8c5eaf6bc35866580c49d45ec8edf0891b546ec2fe7bebbd304 -970d74575be6cabcd2e33a8dacf25b378ce750478bb44086e1821c97b6b27055b7f00cc8ca189954f0150de7381c80c6 -963badd0cac713d8a23dabb8ac7da5e9a83ca7d580ec81dbbe3e5d53c5c9370b86222ca685215eb282c8f67a977b4b66 -8d2735c85136625b3f8c4196a8f892e276845ca7c876648498143f1897637807a9a5162bb90773099a7b0cdfaa292263 -a1a8507bb8a300e1df882651b0155e46a0f58399375f4e5f993251663b5935a76a02e60999a4851fa082a89d5cec2e63 -b712dd139d791a95486d8fe48e35bb8bbddf890435dbf8dbb670699dcfb143fc582d4bdc8a6751f6bf58a13dd8c2871c -8f108fcadbaa43dff904a23c89d809746a9f732be817c2c882ac3493624aa5e49af7dd9b46de7d9d01ae982bb78761cf -80e270c6620756d3d127457fa2e51592604f85479a1004d63c184d7d2ffe2eea4ff75faa436f24bd1494f4eaf90543be -81f039fce432a5d3bf9649ad0fc2d93de831f5b9c0d0e5fa92d35b5bf4a52c739d478289c2386efc964026134f91ac0a -89401011d51b6106855487a37459351f18c39f08ce90b15e52a876cf36e969a9c9fa6cad94a55b844ad45fcf1807f705 -ad66c149ad105ce8b53d38c410d73a3cb3ec910a9f0ae798f3aa5207501c7ee39b85f10e91b4cd91e6b280f3912c492d -b709445e56d02a558a1496bd2b9115d2635855b18984cfb908cbd54cd279d29ecab21cce704cd9ebcf34456dd1195d79 -851059069d9fef4eadf6ba508ca330ecb7436ccb91d09f5d0416874f9fbcdc56472d2adbaebc63a63f190b6abe7650d9 -a933c1b614e6d5a58c599b7189d06bfa3683995f449d636805c8307195d8e98b62ced873997898d6b1b01f6e6a52b743 -a692ba436613db22bc30c3f36a516971158d5489bf2c50c39d0627a74048a6d0b229606823f37a0832913425ddc30d06 -830999596d203b96329185c100bb7360189a50f7930286c36544d20e57b8418c71d8db331e4352a98f380c68a49b2005 -a56d7c262bb3d443fc0cacb2b61f24554ce35b8984fa3418bb4e271d5fe4f5378ef7b12c6cd02f537820040bcee95f98 -844a4e9a8c9eea0b6f929a80da9f4e4e273e999fbe182d3855b0a40577afaced6f8ea285595573e99e13b6a71b985c03 -b34df6205fc429c9b7cec189b2634d49a4877f22bb8060b9f7baf8c2eac4e1d476ed1f30fff1f4c019c65fce96abc554 -b3a97648b3b79cc513246d3d1722afdf7645e7216af233645fca6a2756686592635facec913d19acf99ee586436cb58f -b9cac906123f2a4aa13d5d7eaac84e84eeb0a1b7919526de5198b5475fb815ce556f8451c953bb0bc910c93c6fb3fab7 -a5e441019d492897de73d31a44a0055fd04e8cac894d626d0457ffe9de5394d0bf851dc5941790cba388b403b86864ab -8e3081cc7999d91d787e4c0937c9e22c959d2ba4be6fa04eb97471997ef150836a910ef28455f117dd54fa9ec655148d -98eb793d88faa691ecac3a7c78b25eb3a833ccfd0275186a63b1b1517bd2b984d9908c84e55f044b31c2dc5e251d0414 -b38b5454c2debaf1a4e9e467c6205cfe26d52d1c1dde5356c089abfd6a90dbae89525442419f108c7c8e82e34ec3d5a8 -942545089077b9f27304d2d6ceb3d549e983f100417e88332bf05bebfe8d42b75a96171ab3bcd049acc859f3cc9ad1fc -b9d444777403590be63076b5dbd9325ad58c1eb244dde2c9628234b62ba74f6b0e956642af2d08cc65f82a1b2e24bfbd -aee8deefc7ac67882ed7ee6c01c08d7739b6642deb2614064c69ea38c5c65e06cf609bcaf7db74545199cfa6122f23eb -b3e476268770abfe0cd64a4f878c58c027ff352569d8cf571bb067368e777eba6c003d344746fd006c8bbd474fc3360d -858137d63f90f66b9ef2a38d7ebfdae1bb89e5bc1d9032c96d699ef276aa2d7461366c00de8c47de9231d9ec436572b6 -a3dc8fe541c9cdf89d83753347d8c573c49e8471dc07b5d41bc48ad1b10a3fdc218adaeb72bda0f362c8af8e1194df45 -ac75940ae476a6ff07cacf70a379096786d10a5a5244fa5c466bdd8af69b1f98e97a3a27877739dd4b223627e0ce6d55 -8c6809f893c5fd03ca80d845147a82d8d54bb7dc6a688733b1404dafc360c45d5ea742f98f6a70ac2decfcead05d876e -b0818eee75f08ab207832c591aa783193aee5742147eebf75cf7f1eee6a6d8855b309db4f7ab51a16ab77bf619e14fef -b339ac167debc92cc9132dce076bce281e7f1b9c88978d36e1b5b9bdeabc974af318ff142f746319681764bc4db191e3 -a51dc040c75a8a8bc3b0ecef47ca313ae13d9560c782ee014257ee728a09432c4486a3f87b5ebab690231735fceadf80 -802500a52dc271c52f893b620952604b79d25ad243489dca7cd679b22907fa85947c88dc04463268d25dcccc8a6c34fd -97b136a881f500b07e5b0b79fccb84b93dd108074f92a1cd76e441239041ff389dbf03483fe76cf7c22a5f40b73b51f3 -9155dfb5d7f7915e50da7a715d1a5ac5b43d7093546d6d342ec8b69d47a86cfcb9dc11d8079f123854033b8d3e1ec928 -9423ac1e11f70b5d0cbbae48b7a5be8350387460631126ebda095b3b33a7ee2845776aa20ad60e2bfaf975722d43064d -afa907dc76e03d10cfbcc226e50e3bcee56baa4acd8db2cef8e484ee7b7bc536e1765e764180663710c4396e22fb4dc0 -8b6fb4bc641fe2147d3394322418e2e8e091718e3b54dab8d0d6bba687bc300d73cf1b17f81e2812f0943a8bbc1de538 -a8bb533bf42f56edf112b03d34eb64f6dccd57251244f39daeb6531af650d0368f6e4a0f9171aaf4f5a5b4a17debeb56 -8d763490dbc9a9b73bd571833afce20654348cd553a69678ec89454c4cdac044ed3ef0458cabdb60ff35af5e63405961 -8d3ebac80c55b7ce726f4cdac41c7e2f6a5ff4ffcd5f1803c463ae524243f136dcd15f9bc74f8b271ce90a4776c94868 -ab63cd85311fb9889041e692bc9d5c1153b26a805b511721154d28f11dc8ab84733387fd20cfa30c566ab2f8e066af4c -a506ba11063b14f25c26c92667dbd9eb67c8585d05d3980284aa19a09ae97599a1cf8d7cf45b70a32063f1fa3174d3bc -b834434632307602d9e046de6f625af5de673996108911c6b05d6bd3e2aee17246b2d860f01dc2d6415fa61c73110e13 -8248b69f51196ce1e15fcdc25d487153896d1f74818a5617500cf0bedd5180028e6567533536919156860e34ba275f1e -86a5ed8b6a1e9d8d17b69640220bb80c9065198c8f7610d4ee6a60d2d808508771a84d6bc679ee4db34f43f94315e0ff -8fde55abc106b2afdac3b8796f83c8ce1b90405532fd586d349340c4d7a4f4c46e2a56fe2663fba770a8004dc7b9d523 -82489db9dccdd13293499194068bb4ee8fff51f74f1b504d203c5deb5216287a6d614a2e0a769d4c929bc103582c92b8 -82b2d71281cf886e80e09ff907c1f9213dc444c058e965f964bd17fd36dc0382da2449fdbc3aa7b6d07004d6722a5848 -b0729dd38dd64c441e81a94fac0c8b5b3588081e43a5b0298bb576b16a9713acbdf09b9bc2499c677064619cb3a172c8 -97c4bd5c97182e80f55e82648e387c4a3362c6088381e96b67cf0f04bcdac3dc670890904180a5388b97002c70481235 -98d99f80ae9c59c921c6ff71ef01c2ba283f531ec32666cca1fe7dfd9bbfb09f197e9112af1761068cba8d6319af5d74 -b0569d892ce82d87a3d809f4c86a88ce627ed420dd106ae49b88b8c470ddb081a3dbdbd92d7fc032a7082650e4197ed2 -8ff68d42ec2dc5b13ff5c7ef506c619c4bbb0f62fd4c08e320953e5cddded2aa34624c6c5768b546cc2f00add0dda58f -8b53131206c80638dcff21d7f2dabdbc6faec545f19ab1f4f2bb858d6b01d87adf886072c3a744d58124b8a7a0c87573 -8b9c9aa127ddb950cad4fc21cd7c8eb802cef6db7290664b1773b9744836450e48af503009d4bb266ceac83d765b3b9c -ac61e051add512e749588e2549ff55f3e6fee5378443cbf64c80cfd7b260cfa63f16fc3e242aa140ea243435be28179b -9240700fdcde974f319a90ec4a9b92a0323424fe39e513c7412c621cb33072d193476118636bd2655867ed2816e03034 -b6b05975d0653079034f9792d5d8cf5743e1737e1b3860e431a1e159199efa5a55b2d3283f6d270c9ed3156a233e858c -a2ea8fc31294943a3a6d02509cf8b75a7b5d94de917ced468fa64a6c24ead4edef11c34782eed848792b0570219fb77b -ad0b54dc5dceb242c05a7f7c529289c8caed93ebe743f6609df653aedffbd7eaffceb53a18dfd109f28d14c80e1f7935 -81e4d4667900eb5a8434e2153503b2318f63708499534a8d58382931791eb0ad0522b41cecc7eb0e6ddf99002bd0127c -a4c5c329fe159bdeeaecbaf479c60c8f43a58ce613e135e9e9eed4af6bf5b6116bdbfea31c82bf0ba87c3f651e1464f8 -b95eaf48a9128df7f970754af926f9865c2078cabb4da4918d8b45e95d72748750ffd12f1d8d3f76cac0936ad0097d16 -8567385d52e6f6dceeee52f6b690781f7c05c26f0d20912bacc38c23afe8f64925ba18f8b6464d4a0557670ed0cea232 -8f7483cacd15fb7e49b2f8deb7ab05e64bac18ac9dba475666649c2cdbc5d6df0d5e789fdaaaa997a3b524521f0470ae -9252efa0698c0cb30dd431a72a0f5f2f14429f6ba50bb60f7039df45777557afe3ae732b9283b4a814d2146a8cd8b7b9 -a54da5287928a02cd5eedabe70cff80e56db252e2811842545beb14f25ab67788460a71ab8ee47cf0c1a5f8d01635256 -991a80279c622565a03929c94590f33cf0621a79b70a2168a41a4376bb3f0dd12a9ed9b16c0b6a4a59c50b5802449874 -924ff5d3a6f0ff4ee58c3674319971257543d2e19f0ce3fd0b0edb214faee920f8d6199ca794a173363a9fa06c96d7b4 -96b136b8df76ba24e4dcd68065c650fdc224fdfc9c1ab6410e008fa5b9580680c3c85801fa217917c620c86dcb5ce3eb -95934e64af642e7d45ada1bbe8b9fe972877a674252005afc34ec2e857f755ea0d77e7759ddb24255f21252d6c739305 -ab14c6bdd6d1ccaf69e0dfc6c832751afb70f89e4800c6fafd22db2e7e5d6f2addab8b1267c8f3fb85cee51c761e69f0 -87e2edb8dec1253547cece2a7e6934b0299715e634d599316af0f076c61726c7f2aec83eaddcc9add1c397cbc9fed0ca -91170baea88ba00fe00db375e8d948f58061f9e7b36a4573031b9996757afcc2c7e9c2d9642bc51402aa586569f0a398 -89d99b120e4565b0538b2ef4f8d8c05997cdbdf61840e068054e7f21677cdc1dc2f63adab1b6814225d14275c737b0e0 -880c2b79bff714665e9b3a0a647773a212ec5f0dea37ee6b29ed6850692055013e108a86affbe44d1abd0ae80a748950 -b564181f9ea65ca25b1ae7f25eee84b73f9db109ad1939e6b9351663ac0b083fc13e6518ad8eaafa3caba9ab959bf7c5 -93cd91391deaa726320574bb46706fd8e30ffc2308290c79abfe2d234d0f0f59ee4c38791e3bbd8c3f840a920489ebaf -8e846d48e7b120b59c6556a0394d25f744dfda0cd58d4e70029837753a82afb63a015e79157fe8c810cc68bb481d19d6 -b36904e7dd71bada7c9b9172e4a6748287cfa0cb6960ccfb7202a36c57bc28d351e1f5371c2b449437cd266f2d22e7f7 -8947c11af34a42f314983ba9c673e62fcf44c6c1f733a697351e1b8422a75338a85bb19149fc130d01492ee18b3c9492 -905afc0103e34fa9787102fbb80967b8c917bd03abb02731fe49ba1acff1e96059227616cd21080563e92dd021117a84 -88c7acdc65e6373e4c8ac6a13d1bce1d534aeef2965a4d9f887b2e823c7ee7921db1397df5cb5e7f12030e310172d6e7 -b028c19082411efe8a46c8abfb9936c005e766e2ad3120be774172f16419e2b04ba3f31132ed2bc209e7214c2d7b2b61 -b6b3a561d583870193226391ebf51ef47185ab6efb3556ae59106b6f266776064e5cdb66f0c93748e60d557db64e8f84 -93732aa1473dc2e50610eab2c8152f2d96992fea840ac2d82c6e2c5760d8c1c05e8ecbd69e14d03713f43e77ced9d3bd -9734c433ad41a8fd91e161de033a2a55189ae31e2af406d1fae443a182bf1977dddff93f6fe2ac7d9c4fb955c26ed59e -a1f305d17c36c06c515d30fdfb560f899e80a2e2461d0bd947032e5ec764116c7ccbd528ea42a3b9351e3c9b45904431 -b517f46b582655e551f766930637e8dc2a762dd7a2c54fce429fdc4cd503e9fe4bfbf323f50860be2c18b3a17d528654 -b395b5c48b1cb0daa8c156188b390a78441c8f16ecc8650520f9f2914bd1d992b83849bb11ec17a47f9f2d40d138e3d1 -9147b715b62fd50e59bc96d210e10f1062c87a90263b5586746325deeea89e759464be55a09b0548766e13bc910c4d3f -a7dfe5e7a39767d14d531d371b92fc4979d326ed0f966eeb7b4b4252d78117bf5295b3c17d1fd636dc2c0097cac901c2 -aa3f9fb858b30675e9e57170a1835717521eafe4bd0a0690b10020c7a753951576b4c7dc80cf9f042894fd5741b41b1a -a1f11dec034733e862cdd4aefaf0252a9e8175b6d4c834b7a7d30ab884bb6ed6a1d92bb0e958f0082085cd80157a0e40 -a1751d7452b7c5596fb801466d8d07a70831e568b8ca66fdd75e5898739709795a5768726ebe13c469b1d51092d86a60 -80acf49051b7caa6efe78318792d05401f5246c5b3bef25170b2a49adfeec8048ad5a5e6d50cc498b23896176a9d9669 -94156df9959c678578ec6e12ac068f3a28d69a981443fc35161d14b1f0327b8424746d62869ea9377a86ca6fd2c95b5e -95dd91b1e9b457de913a65f198dcdceb1fca75692853bd5ed44eda6343f32126e6aa2a309411e019dbdb9519c865b96d -b2516bc36a726cf2dd5553e319c64fc508682c7446a2a5ae696e43f1a8c129ca9602f5a41bfbb57865a9dad1d56728d3 -90cd63b4f9216fb70635e4dcbc9a6c5874cabeabe4f9ea83bb923146d03366d9befa48b20a64f3a2cfdb0c3a84007ab2 -a55bfe9b33781501f10d5632e8f5330841eba2d0a64b0aaaa92db56f014b5e44dbeda3b1f5b2e4c17eb6a243977b2a82 -b9e84b3c617708971f5e174fb8718906f9bd353f8b0fec8fa03d1a6e4bec20430212396a5406595343cd15777c5a3f8b -97deb79dd82185555442f91fb9a70cbd30a564751528fa0df0a681315b8a71bab5073716908ee0546d70dc41efa3b53c -ac77c2fe555584b9cba7438a4e3904958f671c49536f185cf1f3b25c5a57ea65e15554de22def94c5c623e8c99e47a9a -a27c62d39508552d79d2899bac6138783f308e3befab65a96a1ae4ab108b799628cf37db1ec72859a0ce1ac68f68b106 -a2aa287741f03e31f2c87fc37e228279b1acb886f32c6438b3e9807b8126da875fca7f194295c45531e939a13048a882 -84df8999c4c5ecc807819248957d68909d16ef64d94a820dd0d266cddb6775c9c7464f0b2385b7bdde8fc0f2169a4177 -8388e1a1babb941e03806b392fdc1bbe1a01438292ea1db4087b010de0805be78cfa56d20e9ef7c8b6be5a04bab1b1e0 -8cb6ec409cec27e7c4537ee2e5bcf82a33e7cd4761d19059e902b6068a9744e897a6010e2ab42ce72625cbc433892ec5 -b6e71cf74455b0f506e03eecc0976831ec9a56eb8fd0e39e5e12ae199180a4c6e5123174ddea6ce6cfd7a414cf0afc5f -815dd267d9f67b4d229a798a499b70ea2a611f3bf2a9d3698d1105890a2b6462fcc7c6ebff0d5d709707ee4ffa981689 -b4e5b7fbab4d8a66d1b167a5acaa4d53949e1fbdb00107e62b727b4b4b2cc70e2685cd4a16266e8d13ab176f9be09c10 -8d1bae7566ff551f06baacd8c640d0d04accdd49fbfedda0841914aa1bceaf9f3f27344b80bdf5f9b93ada438a4e6d68 -adb054123e27afd4a691d2cd808a3232ab58f56fbd514935caf47b8193b4c64aaafed4d08a7a10ec4deb66be8c292e64 -8ab5255246e01478ba7dc6807c84850308a719f8f8433eb049d5b11cbc361c08930722e7e5878ad99fe1586b3d11cb1f -90e862be1e3d0824106da33aec437a87dbd2599aeb58d46b4a39a5f651097d49943c3248a154e09e309eaa7abff3d500 -abf16f35e3b2b29a72cd96802c900fbc54100484299198b2d40cc6071945781cc9bb3eb43f6ebe433a14c1aeb172929c -867a0f396374cca7303845d8a1e4bcebaa53cc0fc2e790dd58cdd0b5ff2b9a99e18ad4e57aa2b061826545935a5607b5 -a6b6a2e22932d7c9ba8f27b1e1de8559631a81effc77ed2cd7c45c48e49ea7d2f68c59d07a155757493ad82f733d93ee -885e4c3904c545c0eecc9cd02e16d359ce69a78e3a355e7fbe6485762d4523f2604f2f663a4521152a8bdb6fd4a9d4be -a668f417391b07a35c5d40ee5212cb7bdaffcf040a4f20a3d7e70e9d715bd908d4f8fca87a7dbf7b676e088ac8651ee8 -a70d67f3379e1ee0708c34c4c7a7f552267ff679460b9d8891549077c724becb99ff79b35bd80420a4290f293ed4133f -a523cca782ced0d8a3f7e19707f9c64ff38495f739e035bcfb5483f202b209c07c50c764eb28d3bd8cf68ae093c46f19 -8ce98e5f96889ebada090449ae198208cae5c247cc5f6fe7800b4c2254b0e7f2475b632cbd5021a0871b466c5b943dc8 -a69cfdeb27ce1163ae6b6b4b5d46b49507c7e62789f2f90f7f5a0fdce79de988c755cc9afd8397b1c02976e03589f985 -acbffc94dc0445f7797a0d83e5107ad3ec8bf61620fa83e73a999ce4f9b6bbabb00245a619aa6f9b082a2711bad5ce8a -b64162794503c86e478c23f060228105bab4f3f5d46582bd455a94526aa6d71f4c9630d8d63854c8c67aff3904681e0c -b1288073c012a0b2b7e31708e874106031a8cc98b2c94ad0ef1d7b9df42f429f58caef5494f6d581baf12970cded2a17 -8d7ad217c3c1cb74cc301540a0e43be6d74d5a3c0383ab7c9dae57e25f8725781735b58301ebc014476171725299782a -924a33c759249af270617767101385910494724a51fc63600836ca00d06f0ca86a4a0a85e5e87cc29e404ff8e04d036c -a7b21ad39bcacc96cd857328a83e5d26cddd0a5bb2326da9a8f593927ae7b5927704acda9ee217176618c964d0452d54 -a5c3616c308bef98807a852e16f146859b0b1f31ea8a721941d90abcbe37eeacb4403c6568480b6d6e773bbb94a89307 -aefaa1033e47673ca2b68e4c945e6ed892e223146d4fd24219304c2667777c1b18a19488b73053cf7b0e6e09ba1278e3 -b308c690176bc43051f51839d3ae1636f6de5a57c626e8def464820ce2f96ca09ff26294a3dbc9b4573cfc42dd03bbb0 -8f7b1253ea9e257195ee92c54de41f2e7a310c90602a628ba3180e059e5bba79d6bb8110d1964c59daf4b65cd9735704 -a387f003f7731b81bace54c8501a3a2a25d8a910cbb28dd603ed16ce61ef1df34e233dc8579071856d7198a071efedf6 -955ad5523828c0fbe8ad6a77a191661ee9c8005b741b7b0439b76711b6992795758d76133399d266df5e494e4f86cd67 -a44441964f5cad7b54d0105f162ed3ec40d12870fe8c5c30bf16238440143b330ba986d6adb00c9626747e99449f765c -a52df726de07cccbc77e81abf4f1712657c9261f65feee8815ef0e8a4ca61b8e470503801f1da8a23fe6d52f3306807c -b5d239222c3d852f2c49997e76d97b70bcfe73d85e81258d9781f5f7de87f9c81648bcf58cfffd554e4685b2f860e6d8 -96f0193aecbeb1540678f1a3369401e916ee75d2a85f7124c555466a3def91a5d8b5f774e3156a163e1010690d457c5d -886b9f4965120d942b076d053571837780232e139c3efcc6bd6c64eabddbed2d55c3a9a06001bd7a2ccebb36135edf4b -897a1e4e9f4eaf755807bed984ef0bfea251740386a168061f4386819acaa337fa6d3f038b4cff9a11926e68f7888f90 -989d9706f8396ba422a34b55897b9e261ac1ba0c7a7a11a30562ebfab92473b9e9b604ea8baa6067137a4ded070fda10 -96376812651020f68c6a1f0aecd04591fdb628051f01daae179f7008ae33af5abb42e8f304662c9b6e2584e8b02ba6a6 -9344e6f3ce42ada6281d0fff654f408e61f0acce81e23ce47466bf1145a99cf60dfba9a22304efbb1f428c92357d644e -b90c5463445156c8de69d8c35db656a76f3e195c325808396a829c11c06a7503f3c092816b3f23a263d56d3f2c075ff7 -b4dc6d948f4b67b513ce27fd12bc8efe43813c119d01b2da391d01c1cb0abb7d51350a5446e0a72a6f8bbbde2ee4b0c4 -84d208ab983941bde208fd71d58c7f9335e14db237cec42df453155a3a8dcb21dec8696a1334cfe5d035c192fc44e88f -9577996c78372d2d6c9de27d497afb29c918bd894bfefad9059bd85cf2ab520ce1d517994724e1567f12e385c126f26a -b778b9054776a2b8ee81be356050b977bc8aca0d0a202be91d56ba89d8a384bd29c5c652ea084709d4fb365b107962b9 -b7ea99f8c841678dc854527ad0c8ffc700b43b5b36b3d18303e51175b3901b144c53e22eea6ce7cd500f6879a80a8c21 -b466aa7d1a5ae3d9aea240c8114b3dc3af38f7d8f1e323800a6382de5766f19626d07cd6ca6eddfc4d71a43d2d49a07a -8a72b1ee7993f16400396982b6a5198f0de08821431bc66489189d5b364b0e36daff5077b48aff1d55c9a88580cd1dc2 -a7c4dd6095f8cf61f42c5901ab67e9d1ad21a42d1eae9ca5e147a9396507c7a21747c2794f71ac66002840f4fa4e1dd0 -abe40e33cca787e7c521e2e97fb5f95cd4ca7ad6148a505afdc94e0c003e4903b1524164a1df2b2a1330fd800ac33b7d -ab8e1930b1e592aa2379cff636e7fda9fd7f05b358f47d9cbadcfe35fbdee5bf06469fefc052f62159c10942ea2bc5af -b28edfbfdcc27c3892d64e7e05a2aebb173808c020186c225590b03d91dacb866108370f2c14ac97a6d20d95a8e32f8a -97d4841704bacb06bce2778104e4437c930fdd9320d85cac383d11ce9246525ad5167cbd63ef04a8ea39c8fbe3d88169 -b4b178a1c3ccd3344831936b784203919cffb611cd18def1a52ffa2a8e4286f9f9681bd48dff9b2abfe62da5fd619fa7 -afb01a4777a128b02fc22e282e0c4ab1d86246d8e0813a7e85c51907bce079766ae40c31d3c440d5f99c92e89d3a683e -91cd070a607c20140c1f35b25057bfa20290b1435e99c5b33068c4e5755ff8f1aa2be61fba28dcfc131cf881aa1c39ec -aaac82ccda92c6090970f60a56668c011ac20dcab26347ad40585a60b5a9b5a9af883307c55526d4eca1b110a079fd3d -a7480de83b4cbb2eedece3d3b27b8d934e9183f448d56d5f49e0b63e24575014a94e09d406d7ca5afda08da9f4eafbc1 -8e568ae356775b06d963b440f75bad9b5977b7bcfb8fbd1dbb4daad5192521bd189674654d4ab86ded4a6be5fee27ef7 -a501a84cd0b4138383572fdd09242e3a748e593f55400fa7600698d4f916a2fc1feb96557a34f4ef0f13eee580fe9f54 -8be0f6b98d52b83e9deccf09d05fc4a7b4ae1cb11972f01baee4fabdb804cee2b0e9b44a1385238f755d2c1ce395cfa5 -afd01e3658ed9204d39fcdda2d79239b8c45dcf80fda8a680a8797b6be294e7e8bf56ce345896c3f08446e9a2a053a61 -851f0def025a50910bfb6c2fbe5ca62a31426747d9cf4634c8faa714a014fa22586c3eabde84e23ca77371ae25d720d9 -90a1aa7bbe7842cd361d0ab2e16203a56318885d2d32409370ffb64ef0ffd3c8c57658573a0714b04dd1595aabfc8f21 -af56f30bbd796de5cbf6f3d041c2f649d0f36e0a1335ba923eb1487e0b29d0ab307a1143e6cabb79674ddc01dd9a5cd9 -8429afa5476d0f3a4eed4104fdeafb79f80e94e709b59aa44b4caf0a94bf75fb3efadf76e96389179eafc389fe896efa -91d8399bcc3b82f0044b9a697b2bc402285f6d2e7b76eec25ffecab769f3fbdd45d20897d28a8676f090edf847eb3c70 -a06f8d37404ae58c35732db58c4c6270e4311c691ecaa7d89b3e9b2bb1421ee3c3cde555d066340c0f2479faea1ae162 -8011fcbb711ba6511960245c69a73fa99167eeb4d238426bc31ce359a90a2339d5936042b281f3ff3eb976357db96885 -8dff2bc19830b4a58d2cc3c1598d060da34c8fde11635062dd4222c96dcbf2bef79b339c63fefdb1653153ef9af79c48 -84ae7869e2405e326bd167249f89c2e018817d3edf59f3db8adc25f64836ea4606c78158cb30020a54551283bcd9f39e -b7be6cfbb7cbb7788fd60fbfcae3504d441b0af3b46317944e00a23079c605c08fd116311432be5b378ed8a11da219e7 -a3656ce4a79484e365b6b7f81a9dd72a09746da16175a61794bc5fcc0c3dd608751ea2cfcf7bb0c14421e0b05d94df75 -929d5603a936bedc69ede2d1277692012d0c820a23915ac6e776b832b9f4e0e6276fb3b257c7abbca32ea166d4482149 -82d47138de8b6ed4bdaf69526ace4f6fdc50fe5abee63f1c6d4447fe4948a84a63b7963c8a65858442856e282fabaf26 -8f8b2d05e77e9e4e2cc5229ea98c5c02ef9d9b6939ce6663d98d8e2dbed73af3d41628662c354972c1b48157f8d3c459 -9353ee31f477b51558f4ba5ca437d801f59d01ed995a8801552f8c578d1937997bd76c31aedab99fb5532789e72469b0 -941f777fc9115fe948f3a979e1ab87f133238935acdc19d33e1d86a1a64924eb9008e91bdff8d650f5e3ad06db931234 -8ee79ecb7d07e3a5fb80ec15c085898e97876448685891e09ebee9aacd5cd0147715dc60b6f75b601fbe83598f1a939b -a96a50de4fa25367706c99abe9dba95ce1717483f50692bde7c8c3a6b427d02d59ef6e8bee82762fe774f5afa528f0d0 -a451ff58246340157fd94d028ce1ebe5ce49e5ed87d9b61884c8ad903ef9b697c4ab9e5acf66180a89a17749046c99fe -b12739d77fb96e9e93065fe279307eafb11c795da2b9efba4cb239425faf687b9762235700d9f2cd5df9cd9fb2b36e3f -a665e34895d02e68f1dee7ad8090558514720ff3e809cf46cc06d1e1274d219fd08781fd430367a3f09e2c591dfd7cf4 -a262410cb60409720ce68935e91c743aed5eccb4a0427449f32a4acca103f9d65413290ffe2cbc895e2e1cef96ba7c6e -9597cf4d49db896796132aed4bdfbec71ebba08a617a611d1fece75bbfcce902e8ba228b662d0ec5fb927429f082eb38 -80a045d2bd30aff2267a5385be12c646b65b24a586c4f5cb1bdb81387e3ff8edd2358cc8e3c4c5c60cab88d4dce61d90 -80323f4a9fc78bc89aaa172f739bbd4f57f9321a7b8e9eddb74ee5c99d6c7b8dfe847f7103110f0a44d4e7c20ed29114 -943b749ab77112be7593bb2ac11094c66c94bb89d5ee2cc05316ad623a3997a38aec741ec93c24770adc670b6ad12e91 -a8e1b4935aad8a84112a99fd5a4d3786ccf1c985aca0b256c46d52a8801a132024391431cc2cfee760c25eb18289041e -8abbe403bf13bad914a4d5bb0c8709f5b264a7a81ba0542850cb89c3c45bc294f62b22a36d7f829ca80830a3be5832aa -9084defe85d170967c08d1f5e74ad1dd592c2b013b01b84b5fe3f2ceb260bde2e52ca22e4006b07f01e3dc7a36774e94 -a34cf1cfca622dda528589b5e5e36a4a68cee7e18cc621736e3e165b06a5df9a8e9f3ddc406838c1fe94ebdc44bfaa18 -8c5f5d7e98828d0a063d90d5f78bc493c46316fec3245d47ef8900241fffd5316e0d6d6f1653cb3b22bbf05286736c06 -ae7f2beef46b6645a6d0b3ca664c826be205ca6de35bd2809a4871f19368bd2c009ad7de0cb4c269c2934357e87c7f64 -abae2cd1ff7320d0803b6b5345ef9dd364fcc001d91fa456199dde24f474ff3d0ce94d460be9659caffe7ae0a6814217 -b86710fd69a6eeca8a813c7c1d643b487a32cadd70013a4aff4b7331ec08d1469fb17a06d06926e68f546e7f5238e1f5 -b42e9dd8d0f12f95a16112ef7ea60e6f4c76a39cb64e7f6bb4fde6ed1fc54fe8317e93160d736d97d87ff7af69ac2a41 -86e5561a7b621e68afda9d63945dc69bcd615cc099c84ac51ebf6350b25c9c07ab371ed5b160a86488e8213d143335fe -831c730524214b8368bdc619e5c7e55a0731b6c5ddd035e9d7cd90577a472a429e779efb0ce47320c8d3b62997eec0de -a3bcbb6c321b329ea2bb944f48ac984f8bb6cbcd38a5f80e8780257765756cd902d252a51804879104527bc7b251c1b5 -8b1a0ee0219a010653f816de88b05116269325c42811d717544468b3bf477953900394a71d56b6dea13e4e6ef9c9c5cf -a5d06e2a43d965e47d400343c093d64bd5d4adcbe3928093c80439f815938b9e952bf59da7fb26f459a5439fe60fd49c -b92df54cd0515bb9868a8dadb2a808d3e62fec12be3c708fa6c845c833c3321017e2f8d71f10b064fdde02b098e22962 -afd8fb1d8ced274650ecb6c370c5bbe8f09d263391af7c2f2290b5c99196ddeaeedc8b9b6173b6fa349872f58c83149e -b359418883d3425b1bb896a9a9e2a3068c19abbb18ebaccadb85dee713b14bca5b83992cf239cfbb73adbe2f07c63f04 -b8cb045dcb0735b02d6e81d9aa9906ab2f19df2e2adb5bff0533022c03a9a530bb27fcd45173faac63a8d13bf0f41565 -b8b8ed443891d3ecd807d3f92d8c2afe714a423b97019cec3690c24002cd0444548ba6b454e1f9934f01a419206896b8 -a3c28de7e71c54dfba701b7e1053a1719032bf48d0e520bf8d513d155d588d08d14af3cf1e9ba3083f8e59dc947ef99b -a94d1569107e659db2ca58864eb8feb03c83ca083c75a6d949805faaf7095a4f981cbd1f89a464aa46107a891ba758f7 -a9c98b0501a8c5102ec0daffddce83ab40bd097c4ccce66a8f8a61a3fc28564ce5dec37940092640b36a0ef6efbea4a2 -a473b784935b52ce73755894177ead52cd9f2a10521e9c034298fc0461aa6cfb03d499812189eddbce4b3cfb58774a3f -8c7a7984739a3db7b28b7ef10f081e2cbec93e1da39738d082898fc73e83db206fb52cbec476c9809c7de61ff5871b71 -88b87148a573e576d0a8fa912858b7a9876001d8364bdaa7dd2759dd908555119f6f580c0d3a663ff5c2a2bcb05fef99 -b169b58fa10256b2753221aa33dc4f0f3308a294b98300528347ea4e89128a1a1da502990c9f2d266fcc10031b3c5a07 -85b1f0e49528ec8e51112771686b5b9f18e4cab091f6f97dc9a327221fde48be87f59cb46e6caac6e1af1a8c70135e66 -954021598c24f5889a642b9d20488a04e3c78c5b04bafcd0a01f377cf24b49f64b1d820ee8a73f8cc193e1de9a106a6f -8954b280ae11638d6e9c27f826fe66c0ec584fccefda8665f75e0699ed640e8e74fb1945753f84baf606d2fcc804b1a4 -899303d3bfcf48d28aa49e915ddfe263117ab87384f611bf7d555ed141dd728a39b97eca74b6b623a20d44458f35a157 -8d792116aaba18c94069cbaf0da373c4e61662189e8bd0f24dd675531ee6f99d574f91844ace86e3d018c4603ff0e2c6 -876c457846f27161c796f2d063aac7f73c2197ce707872c828af81ffabe91a6f353c6e887464c921718425d046c0a722 -a0382a36d4f8007d444643bd5d85d0b6c3c892c7ef8158f51c878b13af6a5b7c8b098ac7a6e3241a6e13b4ae987addc9 -81d668e292ae20a5a39b55e6798255c39368d9b83ca46e986c343ff9cf4f3140e3f07115995b8fc2554dc0372e4acfdf -85e58c950d8089ebd5d0a9d852c9e78d1e066c4cf1f1e64b4e76356745d3eddc13f1abf177dd32f0aede2f190053f8c9 -9420d1c470588085057549b7e6544aca2ca329ac9b232187d8ac894b7a878d6d3ea351357174089943b43a83f057ab8e -b6ea12644c6ae73b8b9752f8eb8bf06312ca14d93fddeb5f79b92167ed78338964d620379387ffc9e12ac0e323f3500e -82767d1ca19c7672d38216bf17a8ca0a52aed5dca77684da56419430f9129ed25b6c547fce50c834746cab666ddd43cc -b1864c611fdb1b641708a5be8140ca0ac52d59d7c3fa3eaa10bd815f7f5e34413751f829f5fc0faa259064b73d43f4c8 -92f67f02d17a1ead3b01478687cf26b40fb32f055f3b34feff21de083852460e02afb834f61c37fb91100709891379ac -b640a52bf00e4b29623c9b150635391b4dd42f0016e827daaad7aeff6e6a64fae4d67193664bc5bb368c72b138c76efe -941c8aed9a85a005059b83d35f6a70dae2e2b5f645719b567de0da3bbf1d2b85704ac977970a7206bd98609182090160 -aa976af6c9809550721103fc8bb8359cc4313f672421a4ddd760bc4ddd86a036c1b4145049d9c8165335309fb608d6e4 -afb11dfe01bb6a9d2cc2c040e18152645b4aa972fa01b6cb4285312bcb11a317107e743efb53aeb4bb6f8a7fb7741f50 -95f8f780fae2878792aa3f60eab8954ecb107942bf07f0e2854173595eb2d4b914f4aa208f98a63b0ebcfbca46840123 -b1dbec7871209fea98676e68d7a02dd82179a74e389bb9dc0eaeb2ac2d446d26810146586b637869ddec4caac8281bcb -931c9d571e50dfd2e1bee0c36f42085e4aa4e7d80a1c3bf99573d9d09ff710f6fa27f30712daba107d43d263b226d130 -b080bc730ed34724851d00be3bba84093a296d6320fe7671a83364ab1faf922189ffe997eca0e1ce4ac2c4435d7b7f10 -8dbbdb4f82398c891d16dbd4169716e078de5d677d3d550fd3853ff6ac8d15d278f17a2950333545bab823fad09a4922 -a71bb5b71699082cc45037805fcd95e410c29575d229a556a7c5f2969fb6f957f0c63861048c65d5b73fc4680a5c3c70 -b5bc06a742016a20c60d61cf55006cd7c2c7b8f367968f279815087b2bda7009c1773b9c91b8a4b78717b2bdf6a5e96e -91aa31c68634a81c9784d0d6adf4dc85c981e122635d4e1f25604c8184da860b1292d65324d4bb9bd8a002572cc96bff -85484fa47e235410e2ebc49f4dbbea9847ea064f6f6776dceb0d868280fe88bf6c5bb72e24c0ed3cb0a3f1d96ef8c9ce -88ab35f32986f0bbd8502dc81506cb18638298e856934fa374480dc455463482ca780385537e7ea73c4c863107b74f7a -b3022847a668b6d5d52d0af14d594c3e842afaab5416e3ffef21224bede0e1bbecb0799ddb7e095623a3a6f28b6d5f43 -8802d0e6e5203d0018d243301c57934ca85a002f91e5763b2f7372816c7b3ddf719c3b743f2530d9b7330f4f35d69d83 -85709fddeaaddead7a27d3f75e5ac568b0c9691c797f1505f5b33678158f5dff96ab98b921bfbc83368c6763420bf949 -a45ddf8ed1c273d61578bf6830fabd4927f82e3efe7732d64a1c82887b9693dcabdad1e7a65f09bde459fef89c0eef82 -970fb837063e059b1c2b4ec88011131e8cdc459daa1e704095bd327b7c94115c57cc1d9e8b4a29d6cc4f20895e309c61 -b789aabda019356bc5c5dcb015f8e7c5da25150988af0d44cfb11d8702da22fbb43f69c4af889dddc0647745d162d91e -8ccd44696d8c52454c833b0b256ed0073527616ce49ef25a113cb9f16d41f39d27e3bf169ef0d3b2fe78f2a5910ec83a -9846a3ae6a2c339b09f53b6cb1262114d1ce2fa3ea43d77b04816eea6451e8620f0030ba428eff80d72d8e907c8f9e3d -80c18de89a31e2c8309353be974e42ca97dcebefc1a914e76b57609b9cb7c1c6298e2ee1bb35ab9d587f195010d24337 -a43ac7ac3798af0923ef5bcf2342550aef8551c198a31b0bc9015ecb24fd2633bdcffd84a2c84f9eb72b4e67084caed4 -8cc1551213a33114c8e6b3e00c68dd26b9cb3728376b498c95aeec60e7506a3346641ed5297fd4ead33c0e42b85079be -afb54536b43e311eef9f584b8f1074866f6d33cfc75a3294aad5aea870cdbc3c97ab6e849ef719e2e1e4386a8a360fe2 -a2c5a2240256c64673372b63359b646dcadb108d785b4fb16a165f4b3b0ab3dc3dd5058582b25ed7b728d56d5aa45649 -b35e3e4407b63edf3eb567fdbe03eef00dadddcf41b799c80a9c9e26ddcf0c6b0b9dc4df0a0c5d54bf31ac8273740a32 -a3ce737baa7e1c1c69931a5b2fe1493a06fa0dcfc0b819ef8242b4fdae8d63bec8d15561d4fa24ef6d6c3a326d0abafa -910a67b377fb17d3f9cd1f994db52eb5f35a4aa002bc1b7208b259b12c64c095e4dd65ffe54772f8e2773923a890bc97 -908c5ee131dea3f444a9ee2052c93a657d28f2f58e604bf08e51500a306decb2db964f68e87d5ac2f8207cc4e92adb09 -8f3de5e756409b575ac2786590fc85de506f0adb51450f5c24669bb3a688f080c1cc37cb8e7a3c8db8e25c49a4bd76cc -aa62ceaef91fdf09d2ac2edbc07fcc651584a7e7d7d93e7bd4bb4c42105144c2da32326b3ae320b36a2df8aed07e5610 -959fc29ce63dcac2b4dbe8180577cecf9bfbb6db6505d76aada43ddfde5f48ec8f6fed14fac19389f6c9ed3555ef7882 -984cbe54156763d6ae078d6a8205cb6f9d63eee390dc5990f5d8e85b9a19fef563653d3dcc190c9b18c2232a916b1409 -923b448808d9ac04488e8345d3fbf9aa57cc3b3f375af138b674daa0e5a864faaeabed08f94010478543f3e1248c699c -8c0823bf2706d9aa4c074673e9d221eb021de2baffe8b703e64e676b6801da73440b7793254fe4c8c48d2ff395e44bfd -93c9cb050494824aba0d57320e2d1dfc95c988bec46dc8d73f7036be9ce0d7de02e56ad1ea3dd8fc129100800aa639bd -9339fa01caba0f4837efca7a3d983fda1f6a479f63890db7f7beb837e3f6535b1f1d0788884dbeb73fa657410a4ad308 -953f213ec904d4540b356d53eb88f646a98581a6deeebdf99a6646cf612e5b07110839d46c57b76545f6879f12371b10 -99a4576f12de20fbecd3906e48dcc784cdbdf7fa0843c570c6f59f13cf3a559cc1f4882fc1d31015304090f83306280b -b07fb8b73793a236e58b7181df5a0a2e8d50c1d3069c475c6e178e32d14b6e75c45af60a8b54823c23ffbb316bd4a98e -98781507866499ce396730ee91a08e91d3be337690f7195750bd43a601a8f78e9475d5ebb43e347934429a4ff3db58b3 -972a5a21354beadf80d8a6e449cc4f072d6b747de293f075b8e0925c89660db9195a30188dfc8b73dba02467ae02913f -827dd2e21ca88891b9b37e10f0d6b6304438cd6aaf9cb125ea7ed822078a233f3e1b49a8bc65f843e9551691b46cf91f -ad3a4ebaccc157a7b880db6990a937e2d230875f509ce864fb0b7ba5febc7f4668191bf3aa55b85f3c17ce8b7d75b349 -976672c981d106fe1835188e202adf6ce77314f8d7c8f797aacf25f00d57f8cfea31b057f6afcb40b9f97df6ea387979 -8c77ba87e3e8fd5de85802a764b719d67f4edbdace75433af7fe966d3d18a94778c4414572b84f98bc6b5993a3225212 -84ca9b0435001c246143e50487a55349bf38300cde86219d29199e2e9137e262a1619ee7d6f6c44b9551319f1ea8526f -ab06e3313800a7dbb970145c1e89b7849db8a1e3169560fe2c64956a1f9d1d3157d531713a8d7c2213356b22fd3014ed -a0d04163ae987227aaba1ae82f74fd1b44387501fa47fa61b66728a0697155f48bb44b9eb5e87050a5bdb7605038db12 -8e76d3e50853ba5945610251dd18736b8541bf72bd643f6b561cab1c028dd044c820fcf79a5b45882e7dde0ba6db164d -967ec8fdee2e6d61f0ca2cc255f4e72c41a9c1a62150318be0fa508b424487d9254ad135fbe8dcda55caa51b9901eda1 -ae25c496f872f7380d9c64fc9bee0dfdc0f05cc1d2d6ea7747e166cae7e67c17a72a24a9e351de15f52baad355625d7c -b8a95f3bc67ad2a2d3cfbbf2de2003b7bc894b3f99f0364fd181eb11d154a7193b1df9b671a3a8eb8bbabafeee2d1a86 -b79996f818d94842175b06650a1e7819cb12c96b6ba37e61fa14b67684c2879e7d3884fa6bae06faba009329db2b0d1c -856e1478ef99338f144757fe4be68d935f0069a05b0a6209be2fac9ebc5cc669c6a80825d3c74801a54ff8b1a3777da8 -8024798b150aa722dc599f288cdf455479763a9bf776da74d5f9cf76026500e5a0282d840e5ae5451a0e28d507b397a5 -97cb767ebfc0a6cfe25666089f85e5a3705c108096a38151baa22308276ebf7cb3c04079ecd130cb8cae1689508d4bcb -874ff07def0f8d32f2ffce7cf31a43e8bc5e633b279acd7138ae938e46889e486c092ac34924aed9a4e1f93a91994211 -ab5b6bec8c81133b6edddcd048fbd526d59fc8a1f5acd7aa72d07852696faf5e8d305e85077450188cddd43d6c1aad27 -8402f5173327a95438797cee3b107407e8b277759c942bf1b1f975dc63ab89b8c43f0f4ce2a11de6e5727e9952b8923b -a5179a16297f7a0913ba61d69879014b9adb5e41813ac33acb8973e2b43cbc17a2f9a7d98210b39471a47b534f0eea23 -8f7cf3928b51b0b1bce18a34da935e7e2558595e4ebc50cc1cb698f0bf3c1ea0050aadbcec33786118d791218e1734b1 -81552a8927942591572429892e5a1572c8bc4fa7901395a5a2de3ce9f1ead122e4e5ffef6cc8434b3b18af1aa62e45b3 -8999a1bf4f22fdc884f9310e7a3f5baa0d32c04e887c51a20736cff3216f3dac5bbede43632d29704536d7f275b0be9b -85d9952816412a890a3e479025d1c0c8858337498ae28731ae23332c16a788cfe51fa9836bee73d03b253803096100a9 -b6a736447acaa6f4d83998973cd2bc3e12d34c6c076880e6765513c04087eeee5b5dfe9394c120a85bec8fbe127f1f54 -89302db4ea39662024c748ff5b22108c0f34850f0fda476051a89a3eba0e02a2294a4511666987d89f3b3bbcc334fdf3 -88ef018d32e6b379cea9ce35d1c12af698d8241c4c7468a5d558099f5101f04ac8e49d09b6bf031a811970faf02ed0ac -b33afb11f73195a7132430dc3961252251aef42150e9aa63a8c7cae724f467543a4afec289bf27e10ccabcad2f7f812a -b706315deef0529725fa6c4520e5d320a028b4607d47fa6c4c8ca3558afd68ed65dc072a354d263d20405bb13ca119f0 -8ba035d75939c1a3cfc72a9ad3aa4ade105880345eaad9286a182950368e688a182f6175357a2e62d977ff7ae08959cf -b47ca04b80107eefd3a596be2e990f5f021cafc6b7fb64cbb78802f9bb7bd2cec4f37755c451bb1fc8786a076e90bad9 -b6fb1676fbdf6cf95add7173c264b820042511e34dbcafa76273ef5e4500ad1208b274855985f0eff5196e7200e5a8b5 -8c7493894853f4e9fef5a0143dc134f03eeeaa10c80c5a72afb12f10ca5207df1c7bcefba6728d61f3f89d3978902629 -97d14d9debd4228be04f2352e57d9c8138d4e40228c269100930e2a3f6eb6e66f2f99807be0c9857082ff8b9a089049e -86e327360a19f6ddc8d0362cf92fa84677737064a94d9d0c1031bae92b85abed36193428199b0f66720be0d6edb0d28c -ac79bf758fe91d47d1ddfba62bba87f5e64d93f82309d4d07b62d78ad6ae95908e1989299db99ec52c5ad8c8f3d7132f -804712afd93328864a52a9f9ca1ae148de26fdec7d9f51d1bf8c0385959ddfb639ae0904c855180dd418ac21f9a8a7d0 -a789e15cf3c1e911fca7f6759a2c5d0a281c6ab744f29709b8d0623c1fc197ed9bf56b89fb0953baf261ffc4bd8d1552 -b738474bd1788f326c5145ca2a468d914ead6dbc338680f62ee21b1e5fed49fa501236d70dce5363a72147b0a8974c8c -a34019db5e8d5cb680a78c1692978ce0f3f8b21c1615ff65f3d103ed5a1e32884680c90d1dc18f0edcd8a506b1003806 -b1b1f26ed57a7bf77257e2ab1bf314b22e47f8a4f4c5cd154beaafdc34b257e9b976b26c8d9f1508498b6e8c9e9fd2ff -a5f645d7a75741f536e5218d4a38ac75f5f2d759e62bde2c9b628a4cac299b477a833bca98010b6c2a8f30b85f407250 -b3947ca7df831d68107713bbd52fa300411bc14362c37c2617780f5d621e211b8bcf5fb7099d903748420818d840234a -ad16157ac24899485e7eae71eabf9e4262d01b8f8bde30d7c79fd00ffb4c347d765bf2b4a30c260c9fe2e5153a3e1c69 -b1bcde4588570576872430e704a64d7130f921667c13101c3fb771efc1e0bd72c4ad4b8e35cbb98d709062257f0ef59f -ab45dce0e29201e79cb1da61cc4353840eb8b47db99319ff7802d2e18f00e3fa8d5e70aa6a797684b4a6741277ae033e -b6977424f2f5b968a4eaa9dc1ac1018ca51e6158a6a4c189f0adc94ea1c2f30bb33c57960a5c972a1800cca2650e2f6e -899f48fedeee4badd5b69632f78a244756458529f27c75d05e9c54cb29579abcbe4ff7567445ccef96274c8cf5b7d31e -a8225095071acb2610d28d9ce2645280a84c702f5f5040df7a4134de1144fe1a1b07d3e28d4ff5e2517b4b2bbae674f9 -b48316873f8245854568a37ad9c5fe9d5e6d9ebd60c9cbbf9e6f63c512bd8568e3a736039422d21d383378c77d8f10b7 -8b40afa65e47ba365e723b9e24bd4a13335455e059346187356ff9abe99cf71eae383ee33bc184a9ec17b32d0800f158 -96c3b7ad1e31b8d4ac0e14358655e21e687beac6f6b7b48dd3750641315ac7088352976e9804b9c625a712f9d4fcfc4e -914dcb36d621753286340077d16b36bdaa1414eac7a8e7ee84404a37f8fadda837bf4c5a932e8b0f3e8e673832e9b3f6 -b20a438985a4bdaea41b98e831537027f4bf19ea9c1ac5fd37546eef117cd3d41b9c1b125d2302ae3d41176ab5d9e9dd -94a4cf3cc42d7055b55cf58959a7715232a273e66ec6f83fbcdb79d01769f7e6b1e328f6b0a910d1f8cf7a5ba4934779 -a62b07dc466c2f83dcac7fa98215ce5bece548164e32b4bb3aac055b3c0aa68ef5cad58bf7d392e3b1d54ea6f0d9f0d7 -9870784890da6cb0223daa367163cdd41ead23c300d246d62debe980fc3e7de0b42576309ae35da914474b8ed2c5acdf -b0f28a74169391fbb179ffe8647f3e6228e75b409c49ba81d34ce780b12d408d2db5968e9664b9de6a7416d2f6d1c1cc -857697b0222cce1458ff591e1add39f5632cb3aa2e589a64166738d8c00855e354c2ed44c4cee8dd707188790fffe6b1 -b3566bb224742d0871ec5d15ee890755d7e6727aa7e2f374abe965ef8380b49422897545e2cf8fd3f58bc81f05abf173 -88271995f9c647da82820b042e59011121ac723b4d0a2e461cfc1351d89cc10eb7d18830adf1c7b9fca55ed3e910aedf -863a43548db29c9cf35f24c1d5f7aa984ba21bb924dd9e09210a1feadb1e0ddca98df47e970c230879faa5e7434b118b -af5c71b27157a2391247622a5029ba11d17ab4329001b01b3236f38d67ddd6b8902aebb48ee9c963983c16f6d8c53d26 -97abbcd4fff0d1ee2ea777788cc146c1b32601fd93a5ff9908fdc2de225b954d8fc0c9874c258dcb90ecc7fd169823c3 -94129bc418ff5d00ba3a3389b62986fcda5714ad25d25091db12a66e138a35a9e38999c4cf38fe7cdb1340c099c467ab -8a785f303473e763578a5bff75a069764e346224fa2dd8ee3105ca779cccd5939ed8c21f7369bab9947a4ca92d3b605e -b37d1644a00401b213f29191a238f4c9c32ba550db2ab3b4c9d1f02021a8f6972ab0fc76d0bc5b9c6291d5edb9632658 -8e42a2c87d7feadf1a2dad9dc822b40029eeb8afb785ce574a340929c4c6ddfe4d750bd3a482e62bfef1bdfdc36f5bd9 -8837b0408f48c8b975ae777b0516c569dad0daf607da51f187bc2c67d3f67315340848fabf7ca78dfa46b05e3fe33005 -96d53e8e9b14e602dec666fcbff8ac2a7ca0474605b294365bab5f5228d8cf0a17a772cf2f37f7de3607f7ea6127d0e0 -b286888ab9afd161a714fcb1954f6046754c1e3e398cf639bc215327057ae68ed69113481da88627839b551cb9660be3 -ae5747c882d3ad685e481b0b42907f0934a717ef5b0bcf110fe3125d40628959b879186464f95bc4a69d90754034c141 -b1ca38e7b1f87e4c878d4b878afbca750fdc2509f625a06871da830c1f68a6cb20dde7d51ec73a78454ffdf54451ed47 -82225700e9b32f416618b074479302629114761fc721ff492d792d4d1a4d6fec887185aa81395703fc8d07a67fa4d87d -a132ead3cac6087bc7bf5153f29ea858a115249d779419e5c52f4d1f2180f4631caf45ab7cf90129af68bf67665b8dd6 -afd4778ab2921b6c9c3d3e2d8ab7e33882f7fde3c8f66d6704f0859f3bec468178eb25a103b78ab092de5b694f2d2ff6 -aa0123ab3e8af146e974c9fc72dce94554cbab212336c8aebe618ea082c15ef02c6b47b6c575d262d1cc6b0cf2d11f47 -a5e35113393e82c0ff3a39afc99a60f90993d5e4995e5d21a9a395ae31074ed5e2244214d4dd877c3d89e52fac6c4252 -b2f476cd5d9df15e624713f22716ff01790f2fe16957b526677bdd3d203fa8af98ae58daaffca10f84a7c61e29ba1d79 -82d6d062828337677ae19ce13d27ef45ee55270a27e674946c7c1c762bf43af6391d77454dda4dc613b519f4cde43636 -8e86b1803d4ee07791269ec9175dc3d3b595197c089551e5bec3edc55c77532235e64848aba62e43936d3e9438635f5a -845b7233e40eab725c241853013d1884d782457ec188ff7ea535926c36da0893882fea2c9609f96b6d85392471b71d2c -a2090ef73e125c0809f2bddcdd7b74b4f4eae452d76afebdf47691d2afacd1db7c6a3032e9a4c4ca744bb496258b8ead -98e759616bf468bb4feedbebaa8df381d01cb4b0009a5ca5fc980426e160698abd6fcd2095cf964eca6f8d92fe1bfc42 -8a29df48ccec0ecb8b3d904078897d996ecea1d2db6b40b79fe51bc5dad04358d7f7edb6543d7d1cf0c1f54544c3d85e -9422e88414d88e5d84b17f9d2f1c50fb48e9c5b8de215dcd7c52bb26a6ea71cf92c90f3004c4fcb34040eacf5b60b06b -a643123915445bf0e528d36dd7f2da9a3b993f93a7fc9f6148049fe14eb5a0063575d971ec955aeffbdce069d0bc2937 -81741f92a157bfe12aaabf0d81121e5a8c7df2dae86f5fdba826167c4558103363c653a928babf4ad7e3e80634d26375 -904fe8e258be2500bc5566c3890a9372c9404935ba19396e8cd30289cf02bda13ff3d776bef56dd87ce57aba0a8539bf -811997c1d70feed33ae3684eee512a46ea91400b39638d405a8bd6f1d0169706f48d1c04beb1c5afc5b10879390a1a0f -a4fff30378dcf1f04eb97951b85abc0f5257b9e53b7bee814a5acf060919d73504db14d55edaf54e4030b4c1d7278c57 -ac84f2568084ee7a715b2387e3fa3b15e6940a27ea99b4fc9889c828179c55f29992b68d719323c2ede8ded3a4e16553 -8fa542c15bd29bcf72a34b3c56eac1e7d4e4f3b15b82672cd956d23a9b9863233816ffbcc6738a225c86d9dd13d1c3d8 -90d94517e7f1236e49ed6903db72c0de3098b42fbc76afae7abc1b09a903cf92cb1bb6a6ec8c29331e05b8946c2e9e2b -916c0d6b1fb7c74c0001599211ca37812f30c309cb6cae529c876221c5e7187876d37268776451df2aa44f91a3a17a11 -b9ae0c4f0c00e8b07b489e015711346caedfc7cbbcb36acf3a2ffadf2a8f11118f93cb70181c27443d42634b2f2f6d90 -97a51eb35da8b67e82d55fed968ac9aa42cf2d1348ac146d534344c4c7535c29ce25dacf9901abcd7e8c43a83e34e25f -b2f035822c552cfe3325da99f28aa31b847477a644402d43379947ee219fed751497cfffd3536c91f2474a94bf758203 -aa2fc0777c208a2efb2884dff33c459f2f6c9dd4cba360a65918c8604cb02fd493c8e5d26069953bba56039f8bb694ea -84c63bbbea15e06775bd39f39995afc613586fcbaf32c9ada1410dfdeff09b8e7f3dd0c99b23c678ee72e44543ee6443 -8259332662ff222d4d2f817bb94033d458e650e5f6e2c31ca84c6f3a4b3d2e8d1f40593083337a17193cddd960ea86c7 -899fc292aafc17d01c06cac50a78edf1f11c8c3253f4b32116625537351a1e82ee3cac67725973e3563fdd73781985b1 -92d3b9aab29854556666588d94c3b49d159c9ba9046487583469ace7a6b8ffa61164839dee24d28dc2fd36b9387b6225 -b54f62077e1e42e18586a03b3d3fbe3fd680dda6988bee8aadc95dcde46c215167b261433d6cfaad8e2b3b6207662af8 -a6c021aa10019319f944f8a77455ad5b153a502dc9eabd9d306be3830a4fa2539e3cb380355953c3581f12348b919214 -8cdbc2c995699cc83768dd23383fe492a1bebcdfa55fc4b9d1113e510a6f4432ae55fd57db732eb56265dba6ad452c46 -aa474f1710bf6556538fe389694b4fb737713dbbc9c93d8a879dd3aee8e004c2441dd14b5f4cdd4a98e804d031ce00ca -95448d62b1503e71d47ef4f5a01c60c938fc3cfd9280d7b6d3490ef331131130630425adcc53c9c96f262a80c3251e4e -a4535757aedbf6d7b9bbea99f4bb7bdfd1c99d5d976bd8d4f8c69ee09c9902ea81884d8b6f4fc084e12702fcbb9e4b3d -87796bbc38d5c2d9a56a65ca91a40530b57fc2a768e9e08a2081734bde163f39e069edc99e87a84b539606164993f30b -8cb7647e60f023066c4835c956186b9e997a7425cc38465e95be568ab448b7303977c7ddaca73b78f6bc137f25e5e020 -90584dbd8f672a349682effe2f775f2bccb1911b06d20cd02f3a6e30311c6678e5082ab87ee47af72e0c064a43592bea -8886147e87a552c74767faa64516438d6473ae275e72b4cdc174825696a4d7878297b1ecd0fe1a62fa4559ed232e9e26 -b739745959c324a62943a225140daa51faa8e41c8e20ebd68d6f000351101a89341641933dcb2ac5b3a45ebbbf7fb26c -814f858b4c709694472eae1c82cfb7370191ad6d0cc5aad69084fb8e9d81e90ac2fae52b4051af25f1b806c273f61e0c -a00426131acb84ee08684f2fc2a3ef01290e48e6b5f96bcb0459adb62f4190a4b2616eff2a2712991c48adc551ddaf64 -b37a1e92b72e3ba42b79dd997bbeb031a392e42606254965597ea4b8a2ca51f8c324619fc2b9f886e17b632ea3bee629 -90817db93eed264f49445d1d3a14ddc0d5ca93191b6baae278b4c48231a56b25725ba6f7ac0e9c7326755f0082b79587 -95b7f470ef1630dee768698a31398e8cb407df3b651a15493c38f6be6c7eb387148124a2cb1fe1237117617017c12203 -ac49be639391aa5dc08e8678cc690ff617e9a0ab40166285f90c2d889c87ac70c455a972e61cfc339db59be4394a0ad1 -a6f5a698508f8047edc45bd605ad4e88245de20013e7a4e51994e99fc60d81dc945504b24f23f7241f28059f4b5d6756 -a4d30a6db06153074871c6adb0ef4e562c1491c1f9841c110359dc41a3bc0bfcba3b49fa53c29b8258a814b8ba1ba328 -b25a500efa7d38f797395cbec660250f4a00d104459cdf7a15b541db3917e26bb7568526444d469d363040fd094680ab -8444d11f8a0c686e2b22642ba1b28cc556ab7311686028e3fb4040fcce22959b7b6cf244b77c711ba86e350e17411823 -8ce90bfdfa93cbe58421be78e30e471b2c6e6beb1f9b3f85031cbe269305e18d25a2170819f2699346bdd735b6f5d664 -b73970a3dc993e28b71bc236b3391acbd85a8cc622b79e669109f9d3ad7ce7a01a8686e75d85408c54bb70ff9771ca80 -a64cebe05fd027069a18f152a18be155ed65b6b563696e395e045c8b2f0455fa75c2ff41c1247e596451b36ddf258460 -afec84a7a480b09cecdeafd025ee3ee02e3b3338b02d26cb3b7575ecb895057650f0955978d1d732ca2e6b391ed97728 -8caaf53038bfad6e0651e61e9a44a39027d456ff3ea46ee9d8e190698d5a66938d5c5723dd7bc75f0ddab660e178383f -a91607e39108d2540b4b5c9d33d96328f56ce9574ac9d1d4a81ab5c938443c3d7014e19f77cd55ef7be0a408e44efa43 -a3f4c6629a3c0f34ea060a8b976096e6fd3a91c24d2b056e9b6b60088bb0c706e25dfb31079f42e0ec031aa840f46afa -96b9c7d3f47ec35ab0270cc57841e9f3b3f5bce3d26faf6abf6cf657b6e949ce0bd1ccdcf9d490beebce722aea48caef -abd2433b4003b7d861b35e99b51e2eedaea4831776e7c289beae2b561ad69a771233e3d6bc4a7f869d0744c5be61b5a9 -a989e5080d39d4031aea86c03b77abe069ea9b7fbc515c6a79c825eedd6a9bf6a0ced1891eed20edc605f9e25a691f74 -93ca5b311d28e4dfbf4de84a1e1530a9153599e0853c9abd3671a1ce04995e00f7d3092895461137fd78c72d24a99494 -8acebb0309595f4eeb990b7a1543f0633690b7469ce89884d5654a7bd2d2543f09232693a04e1e1b445e6e0041c8b242 -abe3858cea5a873a7576d641571965736d55d46f9040fec219803740dc2a5b43c72689e94c9b61d3c3c44dd3a821b694 -947cd395aef4faeca9b78b6cfcc8b2f8f361de884b29181266fd95b21ca6176e7944058e20cc77c7757fbca4fe445394 -8c2e50234c75d645f3c887693e2439ef42433eff328111b9c37aa3ad5a3b21678ee44ee2959a91610006b27a0f5363b2 -967253e02e34069ac676063aae9a493bc6d52b8bcbf1da6243bfeaa9fe05f8c840ada0a282df9c0180d05eb866402441 -a16a4c9a11686a5294d8329983c8a4aa0e6e5ad0003ab319b493842e8d072aaef45c3335d9a64bfde6bba120a48a72a3 -85187b866fbc72e5b42b91d76e7ec2647b93bedecb060b7475236d7d152d17f901c778b704f7c2c1d3d269341890c233 -83b192d925e3f4a1fafcf22cb48083b2f88632ba93c1d498539bbc4997f61f74a0a3b8d4947253a0daaca8999c407b87 -8338eb3e7f549988435f4f618f4ae1942c6756bdc28a80dba7ccc530bef161c0bbd20f77c8c4d63c94e60bc12f7cd387 -adc869c5acec5e58459eb804c2141e03e3582ce1fef7d40fc1dffa3ca0f923919e291a2ca4a60129e2a470cdb395be31 -9279068c28840f2c34e48e9a7e7e9406907ac14bdf4eec7b8c28ebcfe16a18fcb047015e4309f19e6fd73d6e6c454157 -98c4fb637a868f161f2f4222f93f3bdf13a61ec1f4e4c20435c150fca1bc0c01c790da91afb6227ed2a6aa540d70366c -9209fc7b307f40294bd9cce166277a7ade9c64277c600b3ff09579fbfffa471a887061e9cb5fac97c423eada30a8a52c -b1d63569d5d47d052f3a6e8b2c390bfac1e92098291a2adb209f20af875ebb2a8669533155b1d15b232690e26d399ab2 -a2c975c004e69e7b0f22636141d34adfb2dd1396c7355e95fcd0493e931eb7eb99b4df0f0f202945d7bf837809a29ed2 -818f48e65e337913c52e9256af134f4311be84dc332e3ac4cb5ef659b9c6e9cb34f04b0bcc0e2a3a574c9c3cc51d7368 -b92b63d0b363a368a348a4abb10661c38ced99a3132afa6cf002b81e6cac26f862c9d0a6886aede555d7bc453753cd37 -b4051275cef361cdebd254115275b0b86692d3802241cae5e2c75accee7df98d3165cd1de86226f382e736b12d9dbac3 -ad89d85749c23e045bcb95c3433eb8038139a51c8edaf06b5cb235549a2f9ad17589097ff8a350e934c8662a8879a3d4 -802010e6dbf4265cdb5b5362c0b197317f2435253237561a3a7bc6766f98b129ee06d370382998ae70080624fd65831e -8ed6a5b601a5ee11e983035f3109075444b063aff693b3601f87c0d76d2ac253459de48d0fee32330c3785d38eab5cc2 -a6c8bee787c4b87137f70c2c54ad3ad0955269c7ea57ddabb1a215e613e250944cada7f241430c0ef09f8eee29fadaa7 -a3fc6a643e1ce110b08344f8913ea7f8c9e44bdf1a02978df8dcd3671d9b357397df9857fb11ba220521d1ce40064ee5 -94089626bd9c81247f45e25e573bd6bf727a0e1a7dcd630dd5e661f65d4b6f35bdc16b64da648dfda404b5eab39d9152 -88362a160a95f01026a2e52aee3521e8496340f96a35351892034198740d8b6159175c60b910a4ee05af488dfa578c8b -b55a5b875f5594bf41949c212543517bb1ce34db3a896f93d0216813261aa95f73663c789ea0ceb2bf8815255bd328ca -8f9acdca0158df5ecea4d574e0ef0c256ab271d9d3d3bb4100761f5062f0a1a5d2b8a23685097a1a2b2a08287a2e2c94 -b6d4e3bd49a17fe7d929b41fb223eaf93141453f7dc233eaa74424290014a63ca6a099174b687048d59cefd41fc720db -ac0fa8aeca20a0b4189e96c57c85a2174338550855f9d0ff0c553e773a1a1c32fe3f8db7c8362bddf601e41380c9177a -82f05710f08f12b206b2ad6a2d06161c884b2511ad90b43fbfcdf54933c2360b7c85dfa4f598b5bdce8809a803d483a0 -a2ca711642fd498cfeb897e4072d13e43b5cdb2480449975188fdfbd4b471070cad941af03a2dd8938d3c376366fd199 -90c27a1df934339bd0821cacaac41fa70496900044aadfccf6e5fe28ceaebae5cbc500fd6f2f88c5552b7fafea79d06e -818651b7c7a6f691fc47a61ae4960bba7239007e14930f3a8cc9c95dcc0b03643047671f819e30d89c2d1891640fc13e -a88f01062ded714e7f2f1523644222cd8e8cb8e535eda88738f4b4b19079f4f7be664abedcdb618ad1de3e74689042df -8174282a183f3f393667352fdd60460d2199de16752c372a44465f8b71ca134c410d1d81f15afac839748447875f8643 -a358c3e53dd70e1a608f36a1fdbe225e28c13b5817dba890ed8e82adcb7ae86fa68ff6cbda7e02e8116c11587ae1ded1 -8aa0bc208a84d5a58b0206a8fe5ee3c8d224ccb86b11b7c9d924e16b2853a6c3623502dd60b94f8d720810e0079078b8 -8bca870eb6cc5f7b5f6b84f88b49d9a3994e61ca3f2ad963f28f925e58430887f5362ed4bdc2a2a38b5fb9e774a75cbb -ab86840fe84b1eab81675eeee17f85a500dfcc95dc4872e57b39919ccc71b702585ab9ac66146d264d2bc8fa39338a72 -87c46966a4bbf2523dde607852a40b26cf3431d0bde9b2c609997c0f29c5932d28014026862abb7d4107b28ab8e2ba70 -a91666a8c846a9944ee7ab243ab535e4124ca8bbb756777609aad848527b354060c484acc19c333459c09012670f03f7 -b7145784894c6df87d2ce6a06cbaa713e46097b5f83db60e5449e62ed5bf382a7fc3136e5599226a2fe7951847527c4c -951bdbaaa06ba8b427fc4ec6bb44e93e70692bcef6369fa06c7a6882227d27f09465f37f0a5868ce43ade188a5f37f8c -b69662dd5dcc9ce7bf24be8a0e85e80c8e5af9b030e740796f91de548569bafa2fbcb19d98e13900c76cae3fb601a8ca -9630a7eb15718a2324518f78f26a71e3c801a8e2eab3236be7623807321c128ccd79c74ab657ea8e115d6ff3078a6887 -a2f98c2084f8cd556cc1bab19398e98921ef56f6445f63444384efe5d7c895690c57d0d94cfd24e99f63f5e31859e34c -8c3994d3cb76fc6ac22ba2049ea4547db92ef78f009d24f08695b282c95e395f2c1477bd52d3f569d64551aa5e259b5b -b58571076faaaa547df9522b48c684b310500850339d79d2349dd8211bc2c8307d13cd5bb7571e0b5baaa013b502e410 -93e07feb14f691e66be756b37467f290da9a6677b8ff565964f010fc20ed9c58d8c712c4abaf012c787bbb22cd1473d9 -b4bc6159db1578111190b19aa678281eb2fcf7a82c7f699da7473720493e66e0ab54429da7af24315ed9f7399863c954 -93cfc98563f25b45c15a07780ae0a38c4ada52ffc1350233a3b45417c16cef92e7926354b761d0e0de55aea4c1314406 -820c37c923807790d77d2cec39f0eca63fa3ac6eaf0a1978522f0b1d293a5c46af3a0b4ca542cf39e796afc1fb3d7195 -b87fec722faec6a739355fd30a2757e5d184c07b5bbab8581b74eabc2da413faa6d11ccd65cc93f886c788239b1eefb7 -a183bac7f647a0c15b14089879a8aadb712f079bcf2078d3c65851137a00dd3ed7e47263c064feb19362f98180aa425b -996233b2010c20e0246295735b6d5b3e932f2aeaf0b35aa3dee66b6296f39e2e7ee95a7e1a15838ff3389ecc8052e315 -85c943e09a6c77e15d49ef4fe57d89744fcdb705ca370cdf70b3d84aeeccbf2155868f6790333f88fe36e08042ce195d -b88f82b35ae14a3e6fb972c47123236bb7db08b9f9f3828033fbf5a895b09b9b0de423f1caa04b3e8e754409b21f3a52 -a12c957409b6dd335964532ce3c045aabd280188b4d6ee809cef479e51dba030cbecc86b0ea8777cc8828c087006c5ec -87227fb4299efa535240793cf0079e952e971a18ee62cd71a62d6a5db921da669c5d8eb1bbda318ed5f3b03b38798a73 -84b5c7585fb1c98d031a0bf6fa8ad5484c7766025af552cdd72e7ae59247deb845f8678862c44ebe640a7333cef8391b -a94cdb0f42ae3afb4b1878f960669bd99008c7ddc24f2fed45ca521c60472e5587fa9bf97b315efee1f74619a4d9b762 -969a9bd21a6a90aa30fea44e397cc88118fd5abeb68839556194f9ab0076806aa320928a8ec94a47c4eade15498f5175 -b2fb215bbe7acc3baa04b0aa9be654afdc450faabe2702a0c9fa760c9e9389a58aa5e3a4c6af4f6f5c934640d90b59d0 -8be6a43071464e6c7dfb0e9a791a658214c1a95adc88f144d8349ecaa0e76b8ea5f88cfe95e82694bc170e49a43ec4cd -b75d56cfa1f3b61428d24784d51dd65b78b977bbb52cd71401ac7d3c2643f3dc097d6e7668104af402cf7e7e6ddfbaaf -811005c49d1be377ebd2fd3bea9771089a0f5675c55e9da5f31fe13cfc9d1ff8520f085918279ccbdb0363eda16f8056 -a487f7000c16429f2b7bd7e8bf4990bf26f666f8aeb11a99114d33e24f946cb0e3e025ec8c0b0721f9be101504c8a1ca -99b72e711ba7b97083976b2db7b97346000a78bff9b20ed910eaad02f6c03b45fb3f0f1217b328c3e2d87b481eaab52b -828429d387a0b83ac8e377b32db1c893a4555ca253b8e3159399cd053c5de726655a2ad39348c8e7ef11b37b0bca78e6 -835de10c73da7f0c07295a3306ffb18991334c86e5fa4c6df2d8091e8989f6454c8b43721b13696e1f665480a64284de -a4ea48f0cc5915993c83309df99247dcd7df4c15c723d168759175010fbe8d84adab8393707cb338fb90a6a77b69745e -9976bc842b06ffbc5afb309eef8964908802e9a5c733de4a8292d5d5773ecafb6daeecc63a8dc8847d76b77d4c3915ef -aae89156b013e4adb4bd8e7b6007937f0ece09af077fd407798e4155dc09a129d44fe8f8b5f6cf6b3c84746181d7f4a3 -81891cf2d70a8c326c6870a8158edb79babf302b4f9d51229bbafdf038cee39b97f01694eb719df99a62478bbf909a85 -97bdcb526108ef3cc2205aac074ef3001d528f56b4889573e0f4a3a2504232adf23880f7fa2f57bb787ff30b89599da9 -9778949a95fc663c742e70596faf91ccaf8b5b93b78bc2d4993480722ffe10bab3c8df3ae50535d258b6e749a0abb86e -88bffdb927dd88c1ba3eefe7da3fd6a42ae494bf282e094893e144330cf08e3f518f47aa1dd76d6f249cf83e6bb9d4a7 -b53effa345fe59917f4f1ae754e9f6b8fec9bd34cee85872b3fc47e52fee29c418b9406aa50c8d5a2e853d6f2056a49c -a616775e7e77e846066fcea413f0023dd491d8176dc450b0941368680571cdd236f0f83883d268842fa61dcbf3e4864a -8b5ae13dbbd07ad19bd2c7bdb48eb3c760244fe0caa73d28df3f0c31f5418f8b06862526f5a84bb16b2a92eb2c7ebc28 -a62294830750dbf43ea497155b185d611d75e767aafa8c2c30256f8a4875b6fdadaac429e8363848b39e964cab2aaabb -94b6973fb87c2efef5efc0e7dd7ecff5ffbe76320fed8a20d730f9e3751efe9e5db39981f45477ddfe037e18cb971930 -b931b6f789947b5298c258c8f0b221ca927c447f190f0d8afe2f18ce9b90979eb3247e77e128a1d6c57d3bf5523e787c -968259d9d001a08c0329bc19b2438b48dceb5942bc6ff9892d78fc36014f1b60a5ce7deecc7a808e41aeb4e26143aa41 -a52c1906f103e3fbee8c12fecd93f7b7d6f37eb733147bed841b32caabc880fd6e72884380a3cf93129d9800ee7877a7 -969dd12f0f6ef0b868e21539dcba5dc7327033eb546570f5bbf91b13f9c2ba6070da430538c40bc53a2ace4794514038 -a853a74380d78710c212bcfa92d3f9c433b8ccc6936356f3bdf923b8e420e1017bc530ce73bb8d04bf7a25b20594c753 -a84dfbbd3d9f409badc8ac2da5a0db98124df9d01bd71b1cf5b2b9c32866309304848a4bc1fcad1130bddfb9636c1b56 -a9599f55173e77dad54cfce6ddc77bc48588f36b79a98c156963a2f5397262ae07634a98ab9bfe1aa6357f78aaf89d89 -91e429b5ad0bafc09b5eefe600e179ef56f1ee045765ab3d5ecbd73eb201305a6de4382038b1350abc70bd1435151a0d -8785056b83a726622c565985e815847b63745fb66b138d24c985d6f42d5762c61ccd5172d4a3237222c881e5f036b98d -85869796ef180f500dae84f669b76a9b245e2ff4614a58d74820c22e439837b7d9866f480b72d88f44682be54c6dafb8 -a118baf9c17d85e22ac3315f5ba9aa4e230ca2a031906f99bc43fc750a0f96aaa5e6774d1cf16b492726a37db7b51327 -ac8e33f32c1cd14c6de14e75f83b8518bf1bf6f0a70e23ea0e5a29f096e2992f1259a121bbccc5252b9668c605240435 -97babe93e2016d29af74f776e167d82f1cf2242202bdcbaac4a1eba2b3fbd9e7ce57cdfbfe799a0f6a06a0e6838c4e99 -a70acd7e1f159adf7381d3f3ec2cc42b56232601f18ee62fb650e13a80954cd06d39a57217ebf4d8927e28c910671ae0 -b33ef5c10d0588df0b9d2d963912b294a2375a26bd25225f002cdc206a1cc058465c64180d348cccc899baf3d677033f -93086926eb1be21ab929b0098767611bdf1a853b6b67045c14f00714f806f8655be37150be1da05c5d2e6d9c66057bf9 -8890aad532a6c9b818ddb9f1ea12d627010b4120fd4969bd239a9654a05116272d4cf783ff8256de337bc01f9b4154d5 -b878977630f647a5ed7c99f59ca5eb653cd647277b899b918e5f667eb17b6dc433b56c2f3a2a18a785a4b5a9ae95f372 -975582fadbc276c9afc4d8ef767a66684df5f56e898d2a8749cbc2763982c013e5fd0ad0ca7ebc67758124a609b59663 -ac45e154a651857f0464db38afb2fb25853e8bb1eb476df31908b13b4fc86491d4f831c0a15ed6bed0c873b3dcff55e3 -a778d373e361753964a7fe4e1d28702c62a919e5203b941b04b0e74cdd3b4e838cd9b6dac3c39dd523f3227f1b5e6766 -b1bab7994941f8de4235e2e188b302bba847c1618ebdec7fb782241e9eca8d32dd506d254d865e0319c66396535cc484 -8c4ae5b346325f1d1609328e41d20108c4388bbe021361a86a1f9681caf1e6fd64896d72641ba8c984e153537317420a -8cd312c6a23e56657624d21f230a2c22d102badbfb2e38a8c067186abc5a459d0c78433ae7b54334591862c18864d7fd -8739d71181c5a657c6fcfee1df71756c3b6b8c48e8d97460fb64eb891abfd23433ccd08574a677fff600ffa5519a2363 -ad3c8d1e9eaa6f9122fb14d323318bb0338c5f9f29c719715cbeb15a2738493930542769b596098a5f505359c0314381 -a6d78b78227f8c1203e502caab1213092f320e77a6e9729e1659cf81e981cf905170e99b56c4eed1326320acc6aa60fe -8e5ba0e69e0f08a49ea4fa28ce0792f7ff6c032844ceef11be90b2215940d4b0f3e4acd5e4b189b189b0a0ef8045aa26 -b7b31957e7a85a640b851d4241c7b2f6af64f59ac221783b88c1b51cc4185f5ae6446a3c7137ee072c2eeb97c929d7ce -b066bb41c5818d6008349dc6015ab780633cd961b5d947062e14618c1ee1abfe42139c86b77e7f5be0c275fc3f5b8909 -a6597158957e1a0af153183151fbc4c73bbf8156c77f7b409d0f97470b5e127beee6d9246bde770127d3e3ad400cddd4 -82a6de6344e5bd0c5ca95f3be1ccd42fc974403269874603944c08ae1cd3ca887e66fc51ed61da8b7af3cce02f152e6a -89fd363aea11ddb2dc71288bb534a4a6e32feb5b9e4b88d132f4181f2579f8f8f39d19fcdb3d3d7ea118b9f4431520ba -b70c945986c8227d239201857e12cc7cebc932c3bda8913c82b62c872b18f866313738788e11bddd630bb5953492fec4 -b4e3a1e8f82d988c85cbb58d9cec69bc63fadb4c1c9a09f36b5a61f1ee96baac1a9458bfd0f3250e1734ab3fc6c0a0d6 -8d01d1eff496e8bdad1e6fb4b60e4bef0ada39a378c8b57cce2c115e611e0c4fa54f9b599e4c34dac925bc06e940eceb -90857123505746f7bff08e03b1a90f67051a71ba47b49e7bc63f1a8ec30e02a98aecf56465d3b4746aae166081099da8 -98b9d3b7fe1d5449bf6498c30036e3f60c8b90962fe04ede9ebf605d07497f617d99d51f0f0c0c14381377de765ecfd4 -891e7867e70582ade85730a21c19f6fc239760f76f8bbd8c6dafeddfaabd6fa4845f62d649b454fd3af8ae7028ee5f9c -945136f71f290d8cc6bf282b554cdf8ff92200feb7901987a1348f2d2edd3bd7b7bff6f57ec25fa302a27121a1a959af -b574d8379842467c5f3cdabc2da9a45e5a6083efd7298b077ccef2c4c3bab03abf1dc11507f4c896d745ffd41e4dd319 -946fea5c1b1d840c10a5a732c7dc23c2bc5eeeedba6956f85ad78fc1ee4a95b309c0d4a4919d1f7155814e3f36fe322e -98befb2f7d0a860de662f28968fb6200cee5a33cd7a6c376405a9cc6f0718b90fcc5cd5b9142e84e95223a3dfbd10f29 -8c5f208ca23aeae44a056bc21e04b570c13bfd49b14681cc085d5b318e62e4c088f0bea9dde52376967649919b59829b -b14478442f8e985618272d4c56d43a28e10112ea200b52fbb32b19a4d1eae965fd5ee1e9772416d52dc0e2db57d3ecd6 -aa308b19a57159ff702bceeb69a385f91339db7e683db991b1414bf3af9916d8e52dec4c492d7e8b5a5a011680defc1b -a8ac18a1adeeaadc192e15b7e92b611c936ba9cc9aee01f03c2a236827ba527039c719f16149d7aa5fb297cd63878766 -aa09af54f9a5fab6a61552421c13ca62f99fae212a9606f8a5a050997271ab6dbc763390bb98d90b1af3bbe9e8d9513f -96b8ce26b346a0d3fc99b6e463f0c619196cd85340b795fe1c1c0cd4f1b3a9f2bef5454e0bc7d51d75ce26f217460602 -a3efa46273c392704ba0718a44f306edfea03b1a6be0bc1e5c67c62c89671c650eb8ac9bacc35372ade6bed12321f1ff -b484881108a43a1dbc16a6e7369a04286f896aaa1dae847b4019fa287c18e9d82c8ba4ad22cea2837bc220524a9a7a17 -827b63d83e15ef61d54dfc365ed8a4f9e200d526884ec4b1d35032227245410ad7e1b1dd3c1d0ad48ddc4720f0fb5e1c -b513c3ddafb01b6189590b74d20348db74e400c106202dacd9ea9552ee2c642909a7a73ed7ab45a986eda3a0701be79d -831f4030463c84cc6cced28dfce0b3e6b6ead01afa200ddffd807f31ddd4ab93a8699ccc9d26970407628d521118ba6c -86312e006a800720329b82f6feb2934e2cc156958ba394278caa6766ee10800d2fb8907aa92346dcf6d389c4f66f5e1f -ab6841da372a286fde1dbbc57cfe967cb4bebd6fe2ab9e317cb9f9eda04a4db0d5844ffa8db72eb9cc6bf311667ff6e5 -b8238dca3f2be29bfc4aa65a9f59bd4e2c17fae78114a69bba1170782b993afacee3755e768317a923fd32d860f6a74f -923c1b60c052a3ed4736da7e84e52b0e9e154627cd90cae335dbdf05af109ceeaa016954d6e47fbfc40d9d5649c198d9 -96a69d18c838512d95d97735263a8cde752b2bc790b3827ce048e177a063dd11e2a69b86b3184873503a68170b2ec255 -aed7c3af469a93c22afb47a904bc70b7d88262ecdad48ea6a6c07eba7398410bf5a97a786beb11843cf40ddea9a37098 -a6b50f6369ae558dda3ceb8cc9d99382a1e62d0d9804b903086845479b9381fadf8d4595c2f342307c94d09e02e0ba2c -89fd703d457580a76544bbaecf65f93d3335d7a22e93d14afbaa61e5236d9c8d8b005e403e9f5e7a103b0386971a5e65 -8e909a3638208c8f885820af8bca6ae839128ce0d902a2b7b6f9713d21da8c943a7984d9aeee7fb104df4cbd1092967d -b41e2d7a1a0082eef43e886eab5e781bd961a83155d6a14d62756ab7144a208f4e4574d47d2ea094a7fb50d0ddd7a241 -acc6c63450d124014a1db846bf578c44e910436c83190fae428fc3125ff2065d4c6a1165aea799b46093a86126d4c483 -8dc63127435cf2f269a83024b562b3f4da18aee3399ed5255c295e6b80c357cd8f1887de94bcea29f84db3193570c417 -8c4cc72a98d42b9c5807322f596ac0b48b08b16ec956ea4a70c641a16a70895644e5b14aee85a4046673849249115abf -992afaccf05d79a3147d2985970c1793459130ddfb18a9d31f3036c260790109c9ee6a19a812f5d55779c2facf87785c -91394d3e84649cbfe018d9c709604f6aeed53e91cd57e2b29d0e84aca3c413f1e0135c6bcbc70784dc8985a30b9f3fb5 -a33fc126a8f9652c6905b1f522bee45848ce42d7f4c3a4cb3f6ce0e6e64c82de74e175c2ab6b5a867a8d42322d257ea8 -962d5fb816010a14140767c2486cd629f7793b304a96cb82ab85a867bd9a407bc8ed44131f87238c34a1e4ba41adb1f4 -b09048879ce26a34f56e1d4b2cbd6eb2a55d4ddcf3738c462329ba6726fc0a21b8c1bb55169cb8338b2debf20dc0927f -a9f9ddcb86b7427e268973bc7f3239212716df394394fa535b9fa5225b6191d234a44a126766eb470ade18c469a2d166 -87cba6afb115c0b3a515b08cc842e7cc2c705880c82184174837c0a06e1687ef668609c2ca080840fff80282caec7390 -ada109548c449990dd8f1bd42c9cbf194a62625d165416ca469c334222446fad7a743b1f584ec3f20526c3c44d870696 -a69a0c58fdfac715311dbd37c4464f0475120362234f5366ffc65227e8178e037ae91efa5a52cda5fe28243f47390175 -98e726cf884c6f706fa25fe25be154afaecc0c3bcfe682a85afed225bb44ea07cd1767b4d9f2201358ef19770330f0bb -988ad5bc57f0621e3ce1256720f1161e785371fd478c467c39e554e2de27df5ab8176508658aa90ed7179bc212ed0dac -ad0ff6dbfb397da51fa4d9d959ba5819adbf1a1ee31f68fbd62ae07a9cbce0641588cb1008dcd0056c17d74e83c7114b -94c703cd32b9f52c41b07aee3e3c19b8c2b4182da80487ed7991d568ea8827f0cdbd1e977d482dbc102c4de2058903c9 -906fc2a06cda5d82445e50bf475dc4ff2c17e64c982539c26545798f9e4dce0bd4daa8d55b027cc0a8e1b26c3e45cb08 -b09a51f22a9a24cde25f805cb18754e27d3d168e64db4ff13a202839a81c69dee8372b5872faa0d23fea283609cf4391 -93c908f514e97502d170310bc495d02948d99eca51e71f9a4779ebabae1431e1f7ba465af485546a9fc97c025877df50 -8337859db710ed7e276a47e90cb3912c829151cc2bd3dbbd4dd04acc90c9cb4870c44f4233b407db8240a93aaaf7302a -b13b16ea0943e235f8cb064d6dfaba9bd8dac67e9b6275a4c3f54a1770b9c905d8855517415ef6489843848108dc85ff -b28489f0de1a76839a898b8d2f302c95610f17e893a6e7f2e824fec773cde6f2b219038a3f1fa212bed98c97daa66d5d -af13afb48d56caffa32f941ac5542ec2b7fc0d6dbc3b16e51bd2a8b633f0a041ba1e098d9a68c470da00e630f08f24bc -81465afadc45ec24825cba7c9edbb36858bd2ca8f8b0b9d7240152b58a411b08503b530932e7b6ec3b0f8612869cb244 -b2e6b7438fb6f70b52b8726aa870f18191920bcb213a375817d100297b507908d79567d0c1780b3f25be807a8ddcb853 -aa7ed2b0b2bb2070b5f001578efb3d1085950c19f9d06584a2d31e1c235e6d6d1d7f081ca6fa2b0b0616b01b9a467005 -91a245f1aa8c8ffe03f7db1412e5466f0345196727eb8e6f98b80c01672e4260e90724a538d26b094e678a3d85f2dda6 -b9ecde963c8176d6a726b129f229d803d1a6259533e432eecd7404703c972ec7296ba35015acb1f4b5ab2653a3991902 -8cf535bff6e98f75d98c5d2a691a5d1aa645c7ea18d677d07d3a11a9cfa222a7b8edd048529d163120a5aca411161314 -ad2e51afe96dd0e942a7da5a37587ca1359fc17cf66ab70cf37ab70ea34f90054fa52503d6527e89e464f8058f5cde79 -97337d62f83ecbaa1f402c3964dabfaeb279b916ca08430a61fad6c31d60087c7e3a9decd541651a2b6e68fb2816bf45 -898b7581288bc7f97987138b7481d29e2cfd5255ebef133177d9060790a0973ba07de62cdf38568c336c237cb084b7c5 -ab53c0759663bd976de62f9f98fc82fa4f58c146b8a6a3053d4dad836c762063ad69a54d51b5499e9def86f8d4bd7ce5 -b35ba58109d44c14be159333b999c1e471fb61f5ed48f9d2a6bc689eb045864f3fe88a6ecae12315183703e2b1fc1ae3 -858a20e233f2860c24c5a3f4a820cac7544eb3ce91a2d8284f12013b13120121fea3c4f25427c3524a1e883aead429e6 -965be1a56adffa51f5d80761327cf69656e6c37577225b36a34afc2f8a959d8799ad0ecc3eff4470d49eb22ebf8f198b -8e575ee39077bd865d70fca2d93473f51dbc99ef4f715f4a3b1d9eb21deb2afcd0873b4dc53035b77e05f52029f069e0 -a5c670a73da241f5888c5cb44c27eff2b8ad3f491e0b128e5f1d498aa6d76640c9e625f3c5399ad8e99b666e4b2a9759 -920e1524255b03cbe500edb230696c55b7774963535c063121c9e9987ab74d504f2f1cfa14ba7ca82a6f66745fb0b392 -8a0bb7cb267b8e1e0cddee208734632b28313b3ad89f9c2168f341be5390bea3f09eaa51f8923b87697799a53201dc26 -859ab9b3cd602e78dbee8d8d5c3a9eb4270f130ea4a1b417ca5612be753d20106cb2724097840ca8919a9a96e73f96b9 -a76126d9a997fb0e7e2b27ac682dda1c6b99067313371387084be1f6e7a9a59bfac395e91f089e14cecafd151674a446 -8aeb466c58e2829790975fa08dd31f18a51a63777070d2e24605adb1a77b5e0e5c5e0bcb483076d23a6fddee5f402f8d -a8959f312f2ce0d7d974a4998bb709bb98ff6456413ef4ae9bcaa8d687b8b5ecad91414bce8f704aa44a83d8a0c86462 -b9545c8567827fb28d070624579702ab96af4f06fce515ad880893b97ad9a374c4c91d6288e2a584ef14b1ce4930a6bc -ace41f9c2756ced611da16e21704a367b122ee1c2feb83145103203ace1a5cce0ebd3bf295caaeff05281672c92574cf -93b90e75f56601191e3b568368bf1d24f97512cd42cac1da8b42f0019e07fa04cd5f835b7e9503fe4702632df27ddc19 -973c8feba289eb473448c32b141ab4a6f861222626b3f2fa265a431a54675dfe5eb479100a33c172ff935464d6e85f90 -a6b0798ce89512644490d65ce3d0441ad950f9a25f6fe2c9a766a58b9c8222fa6cba753f314cc7ad6b6e3da881c67abf -a79c560dfa179075e0d1506adf5082318915c15048328b15ddca5748ebc6ed8b10fc5d7a50bfaf8942cf9ddc6912be0b -8841b34df170519d07edffc4d33a0e70c518dcf53ea8d0a9f13563822312a65d16f99cf596bb95eb0daf85435d4bc0a9 -88527539258323edc2c296dc742cc26b9a4a984ca299a81705c702a425ebc7345a79b4df84b2d440a1e73a09fa18b5d4 -88026753926a068e1cbf49a9a0fa545846cc7ca9abc0778e44f5b7510c1b6b73e9a9b1aff754199379522b2a985c0881 -aa2c306ccf91f967b5cdcb50808771ede36acb9a6cd84fa15c6de4c873cc2d0a64e79778a2822a109b41f5205fccc30f -9751fd8bc2a07ffe0566e5587e652d3d8d5250517278bcf8754e14717b8941c07c194f14fa757f9a2f3461ca6376bdee -919746e5eaa18b734ef59c0de09ee8ec65e348efa659219d9eb6a3a77b8edd9449a6dab727e9860ca0d3837b161c0352 -a271c146794d6a65c6fb87797262c22b1d938ecb2624e03809233469296d33ac0de6909183c8efa438b5f3971c8c3eed -82fbadd9049248914a15755dff692bf689eb2650fdc6e44e8f3ae003b8f15a0f2858c7a2a8dd137b3448420c5f434229 -b90992cad6df98d2fd1c75bf90978205280d993d439c44d6721cb95d52eb042e01b418e45c3c48ed667aad577f3fd1c1 -a0c3d1e8b80ed4a979a22d6a9647bd57f22ac8d73c37ec3d56d06dc178a5c9d5ad3ffd6dba9eb7844c1f40b8c89d3d33 -b513aaf2f0a07fff3543d8687426d07773677ca4d23554ca517e50bcb891164d1f5651944a2f6e0a634475f6d33bf0dc -a0b179aa2ecf572ac4a3ed898aa34679be3cf3d8d9bc74e33609345cf1743e915124a59ffcff41bec012ed2a99447e6a -8e991c5549126d64e0b515a03d266e19097eee38d08121d942973d568f8ae23a15b037337cead0686f7c944b9fda3e39 -93cab29e1bb116a39ce1a82897776da1bcac06ea131a7dd141a688ecd4089c5a0b8616d6721b1c6d92309ae0820a367a -8d4e0159fd3534172b2481764cae7746b1a47e9b7b9465fcec0824ef234674fc567c16ca7116dc90ba9b2ac3eef28d60 -88cbd9ff6ca551a7efca30b5f59fedaca8f9efaacd4e9bdd17ef0dcfe4f3449b52c7d3066716f3e7fd478f264d10714e -873c71b2feef5230c31f13d8425f8b0eb0171eacb9225f484a36da3cc796d62594fa4771af9ce1e7ba951f5377e5db76 -939eb99d7fefc9fd5b3dabaaa5b331365121374a4ced862b8cbe0cb3c574fb1f0cf4932106088a1d87522acc31ba7f77 -b283f1d54bcc72e31ef572498821ded40485f38d2ffc67f70bac68a100612b020a538b36001d94228a4dc97da8fdaf17 -b2e4c2be605c8ab3038b4e91bca7e77e127c5c3106913ec1341102e138bc8aa1d218c3d3c2ec1d36fb8e044b4bc211a5 -82e73cb5b2cfd78c17131e871e92026643bb56916ae64f009a009555903df878fa3a2019b82f7e71a3ef7eb503c792d1 -a6d828a5b7de0e7818975b65244f6efeefc712c29f2f17b27f3264e19856d869c350ab39750ba63d6d46afa3aeb369fd -865b17027e9d5bdf2de0afa2f524f67b6defed87b14e0af5f4b6b1966c2de45550fd2b6b39b1be88ee9cb06e755f917d -ac8b47f9b7e675b556445d103271e6bd3b39b94d15ee1f3108fd1b777d439c75437c78ec3b281f7104af6d0efbf0ecbd -85c2f71ae18105fe499aa4da0a835de3e92ce05d0f28ccbcffdd2860898ae9909e1c05831ca4fed96545133bb3170302 -8bdb4a72b06562591ee44799bd7400ebe71f6737290420dd4ba2bffe0050d8ea4d586b7e329541a52611e945ff1b16b8 -aee4843c9ab02026ae723531112170bc7464f51460bd4ba5166fed54ecda0f53342cdf94f4354a5bc1b941e8ab085a80 -84de368006db07c89a7a43b7de54a63637ed72379a41d029430f6b4ebe404866896d2e84996998f7b2c20324143649f8 -a8375f69c01289cebbc97843f417d0146f68c6416981032bc1f42d3e09845d5131eb9b4d68fd0ba7f5b1223b83e51bab -b1ae126dda1a88fee9265ed8e5bccb810014044d83c70e01e7f80059a685067f4204cd15809b230caf5dd77738a64e38 -8177544c7b1f77181735c660102da20fbf9a2ca4efa79b21c92f1cd2b912630aa6c830b7513980656bd275097be59d1b -874fe8038905065ff3b77f1e53904854fa4fcbdc4c8959fd2df2e3967b3b84100c6f63fc44338c01fb26c042c454991a -b19324d737364cabef3d2ee4785e8f19cae399afc06fedff8fdc120e0ce525b3755161183a1f5ad11ee758104081a49b -8e7525bffe35c1f5c2db63ee911e7e0197951ebd25868660e6672a3e7d4fb309738268b36677921be3be2f323ca718cd -846c51c7d22e7d43f6e2addb7fb25113c25ddaa51252a898fc1d7d5b510f772534c4f5d37ed3074d124cb259e2bf8110 -aafe2a16cbc901730178841c39803ed84d3a78f92f42f84a1c01be4aa3b63ed7ad9d054ceaa8a2d56eadddecb287e8b2 -8781c9810ffe3d93fbee3b576a15b8786c3efd6b5a96b75819b1f93daf413d4fd0f56d1ec277e8f5adcb784b17f08371 -ad66011f0e2927ee1924725bcf8a296069f74df78ec66ef6aa8792f68425e48e9d7f717d022f68a079501770ce192fce -acd0ef46fafb06f336565d86e0b22f9e5500d2f73d047c827d6a207af40b706440afdaceb32e6571deaa1a79f5e6fe27 -8f65bb98baaae22e84a3ff375e7598b5c61ebec676fbb5a4f79c8463c427eaa96ebc51b1fb504840b7b0206ca6c2c72c -a4078341325d7debf766e43679b8b68331dc13651455a73912afe062525d2ea909d8829ac08771d9b32f2eea28b64022 -88eb29841b022f2ec9029ecd1a137173cfb79addde1c7cd4be425e5806ea6ee295b11a0459a940ba79f789689a8fdb81 -b762b9923a40a1965847bc7d046723c3b8f0d63323303aa3b25e93b4af8e527f1afb3dafda831f50baaf79926d1b1e78 -a21551dffcdb069cb8f30b625c8404dfe5efec83227e3a1a67ef0c9c9b49c658bbb31240c3ff6f8c68e02f67974c732c -b4735a6610c371754001425772aa5314b759c24da50b38a9390969c27e215ad9d463a76762323b7954756a8d5ee7936f -81bd78e545938f8a3e53ecc2e88dc26bfbc30941cbfd009572d9b38f8eee47a85209a318cafe8cbe055eccd5e62d50e4 -82ea5495db9dd48da97723bcfce02788549c6006773eb9f4aa4f0f3ae13414430edfecb5cd095259179ec2014b6ee1d9 -8493147b8f0818c2d5e75acda498139f95fa6f904b47f87a8c07e258c60f39bb1faa1d29cf0834c8a1ef1d6015d37b42 -a491233ab353f9daad86e60fd48b6f70dce60dbe36775958d8e270725cbbda96578b17a0c4925ba1298e630c6b9ca9a3 -a8c148b9e1373afa54778b6d4f76cb12f40eb6e07404a7f27b271fbce0d18d621675f1dfcb30e3908d7df1d962de2e5f -9826a45c29ee22cc26ae399be25cabd16180a291669fc822a44d14cfac81aa7ce85112d7f2c30effc7e83d131c9937cf -a793c75e716aed4048a2893f11eeba78ec565ac250bdae16594d056f06f4aa7d2a156e1617fc26def4e39984fb28936d -b6c454d822343cd1b1ef7161cd2ddc28145134d4e59e6d69634c010ad1bd44120aa8458eafc28f6103ece7e34b368e1f -a3340a0edc3fa82fe4f31ca2d19d295aa09c74cda3bfc3534c66eb71bbb7903843bafa92f7120de4505c7ec819a89664 -a18e5218cd4349985f412ffc7741b5db21bb14c6e00431daba194771300e740f75fd46aef1876543967e8719bc6517de -885ce63a88617bee05144bc67d08f1c7072d8c4e09b23b7359f020995aa8cc9654378d382de6340ddf0803717687eddf -8d8a0b614be7df01a12e534bac102b1881905a9d084146b3d0cf2086dc7d400129e0de8e48fc966adf9d8ec8c1336429 -8baad19f604bad656398a4010b20ffb6ec6131681d120220dbf2cc5779de1ee146d0b773bdbdf4e8e30aa0f464f2b18b -a39ae3d204491871c2e88d7772055b35af341ba66531ce3575f47c749eb8e380d63a7939d3408cd51356cca29c76d4b3 -813afd593876667ebf0fff2b8a8a5bfd0f42a4fe2e4a0b7c78b6183605706c97dfc40b627340e1d9527f618719d60e88 -a013e458d678fb302bcb6f002a52e3e0ace443009eecc9113ab5b78f4663acadb8ca9cd757a7cab1e850aa23f09ed698 -b6e14f351fc47b9e46a83984756812cfac795cac5ebbc6f00d673ee23209d0d91a6bd7d576c7d35ec3c7e7cafb758a46 -b94246a346966caf6fc1e0081a211f27b38f058dbb9dff915e3e65391dd36d66c51324667e3d7469a865c0cc064589ab -a1bf4bcc7420bd17acba90ee67af96e73502777e1723255a73b1ae3e92fc77e80a287ce7c3d4088040e0edd64577c8c7 -8b6f5eb9b6bc7320349b19876864baa6cd8e07da4f70653d7369740184ad416c40b4395c04750f5d8b54b3b3ba68295f -83250b957d920b1b738f4d0f44f9eefc01b5b0582128f5ddb5a282a11ee207ba1ea7867f00588f8b891bbde2e56b4c43 -8eab312cac9de78c9fece9d67a6b26d58c4e15d5e0668ca2cca2d9c51636eea5210a893f9321c2fb232e09f9d0b40fa6 -b4d1e5f284d50360dffd2a0d21c4b31d81f521158aa21bf333a525cc68e690ce8ce4f0eff8e71a0c2d5853e2fed18231 -b1f194c28bbe217a2c98ca8212fdca744f0806d60e51f9da81548155cfb97a39e2a98e753be8b2196c83f7db8caad2e9 -a7905cbb59722d9463c6317ae59adc10d5bcd6e9788f2a54f4ff4a4de03df3f830d6b8faebcda541d429a7e42d158c9b -8a3b31d0d0b33e7011dafe25ba5c3b7629cdb5dd5b31385d786fd80888fb8409812b96d28fedf6a401a93310b045c620 -86e4990bf50b27bac76926dbc65a1ca34a759d005e56eca56fd0e00ce82635dffed6f3052740cac2f1f37204699bba9d -8f0b6a0b66f1f5fa3d12af444963c6a45785a36dbd9e1a5f42830b5534ca8773a05fb618292e718cfe8a066b8fea7980 -b7f206827d715b33989de5c02f0886d3a457d0ae34931ddfdfe2dbab121b69ccb560a71fdafcc3ff204217611674f5d3 -a6e2ffb0c5f29043984c54f5fe6449ac4b7a86f2982c909606b88316ef1f0a54638d565f44d2fe8cf00279e0eee435a9 -8cdde76212e73f9430cac210b52507583e81aae0bea491f6cbe27e5e2c8fdda373ce8c7a5f16bcf8c6238b282d06639d -8030955eecc9b8e2161d40f1f514d58024d25e07c6710916824ed8982b8bcf7ebebc5643f0260e1ef6150b6901dc2dbc -8938fc90e836d7bdf1cfefb2716cc25aff34e7c4dcf66b349d1fc6681580de7f58665faac29494b30bfa0c743d6f33e3 -b182f9b4a5d838e9d534e41ecbf06330c56a8a64800eee561de1fc2dd9486565ae6099f40d0f1901066f45047641bd65 -81f98b85de7b6c581613f4a42e0cb0dd9e6336399b39d38a4751c2a9f195b65c9e5592fa1728b91d83cac0ebfec7d675 -94681572da95137ce41d913360cd567b570a87c9a439f2b67b90d623561b75bd3dd0486a90a63d49eaeb412cb97768da -8e64922606ce05375556901b8c042d4f41a18fafeca24c1d56998e0bc9054bcee7ab079c3729a67d908d0d7967a85edb -8e10e8952b24125321d0cd9ba922affc93908b3abdce47eed22fb2d44cd556842c31c36de6d4c28b4a1b5dd84e07df81 -b6d464020a51bbb53670c81d5f1474ef439e006851d5d5a3fcf74219614a2a9c983737f20b254d38a2fc7333b35fb3a6 -91801712ba264cc2eb65e8a3d5a032674a89f4c2dff95ef9d80d3a9285f3c2cc108e775dc326881484756814c2a03637 -986e5a00f13326735bfc6b41b086623101f01dd55f2a88bf995a3b81054da86bb2f97fcf647d58e90428e8e9555eb020 -b2875b4ebbab678fcafd270a0238a208b19803012fdb3c23f06c74bfd45929a9856b7a0f9881b75c7e97fa9d35e49d1a -b3d1acb9c844d8d2232834a81862c59548cfa849e8e5408ee66b4c8b86ddac0fc231b2538a752eb6c1ceee92ca443d1f -ad0b1b5d6bb50c43f5f3b692c5d3569d2117b01caa7f0ffff502d5ab727f7702a2d458b89d77d218d3f92351b4c2b92c -95b1b99dc260ae6ac7c387bedd43fba793274b15768d93df13c88ff6cf637732cb6b1719467919b444c3b5166f4f0107 -a0c3c8b59016056742145e7f4ca6568d4393124efac6540645152bf71173dea3d0058bb11b3093228ca4729cdd5b3033 -9278afba60643257d9f21a4033df3b57743c3b43d66d96ccf413154a63db054fbc3a36f2ef378169f4f19987964c0bce -b558754c97f9824a72644de1725127dd36e284fc07ce89006b990f09db77c48ad6728e5c1891a691460bd5416ad65faa -833a02af76172f868a25e850d35f4d164889bab8381fa9c8d9880ab0564a3769ce3961cde72bc94ed73a1723daa35cef -aca496f3e528a2e3eceee138291107ddddd68bb088b2e49ea76d0c4136c6924b3251d7661ff467a36dff29f07ed09102 -a9367961ae88a19038c446df3eadb280da005d120c16f48ffeabbe4cb8e5e2784902cfa1192876ab934bc90606baf2cf -b43feb49373dc36cb46e050e3cea43e636a64289efa3af790dd3fe960446492b858f51b3be62c6b75b510d8e2b985573 -8cf24955965468125fba2c5a5799672845ea6ce97cd307b09236ef1a3cfe55c88958ffa311e8bc8335bf261a84275d93 -88ceac98b512e5bb915554af92318a5d07a494e0b8734c4415e192e7405d6b06d170fbbe254e3bf387759f6d4961c34c -8a9044ddde945daf3e0cb3f897ca00d0d4e6a5f7c99aaa3929f0beb9a44d2ed23c191e37c57140ebf3ec759f50f84d57 -8b2a2c0fb51e7c5fa51e8c593bcf118696b8411bc93e35cfe5de6c5465c6e80bba64398d7c6b71badda616b918bcc7d0 -ad8bba2b7d5577f971a1a561b17a9d8f6b7c35fba55e3e421a0d8d77b520eccd52122f02afaf3899218b652980986a92 -a8d743b56896d44bec838e10ac1ba5a43f58c26655c71be0a5417d936260453a8e91752c87334676c5dd1dcdeef4fbd7 -b0b0540f8d2d1ebdcd74d6e4007324de8f8bdea0531880520d79773c0b8eda65ed49e672c5a294fca6b4560442085829 -96da830d1c1625d002008e9a364005b2ef16cf56f5aa4a758ee963388493cbf90aa75c25dd67d496af17212537ad44ab -89e819577a95195056b872f8f790d001fde3253a23120e2c41b3ced7fe8e9bae0df74907b7d65ddf9bbd6d2efa18eba3 -90a139ffc7dc0992c023651517db4c195aa2f618dc3002f4a0a43013b6c6022d8d9844a49cfbaca543c9cf5d9b2210f3 -a2061f543b216fc9c801d885ed681f9253f67cac40528b23aa8a709f24e0992fa42a10f1bddc7f10af2c22209343ca26 -b5f53715b9146966f386f214477743e2fd2b771bcf90b192a5863c06d7225be34edb6bf71389085edf344e60afd88561 -9634ce27272f3c687035789fa4eaea2aaa71db5b5531b21b8e029645827b40561a5901b33afd80a3aeb5777aa89850f8 -9674736cdb4a823bf982d54876794e99c7672eaea7455be90e815abd03ac06ce1fd9e73bb987a515863c6cb4ae597835 -90379303e285b19fd7816a6d02c0b8f94e6291b56c196d76aa389cbf813dee7ebf64e45555ebe8a281daeecfd7aa5b00 -8a1f759f6cd6e5134f67b96e0edce7170e4be1b39afaa7af1c2de989116a6ec9d38a2c077c8e6e65ce0bdf729f20f1c7 -b416f9937a51a298548e91cbe8fff71585335c00e69602423adc9cd72d18821987b8fb5ede32fd8bd2166e2ba9aaa792 -a423073148046c81f840a481d57909f7ef621a51827e44706da9e1f0e27fccb8f88652097a9880ca64c41f6386aa9069 -a173305a5aa2a17349eca704fee25593f5c2fdc5cd8cb932a1bbc0ef34bf54ec2f867ca93d8e6aa33679cbb71fe11083 -87c6756d14d815ac8237ed4a75fb11206f615585ed527ad582841526371366ab19f602c7448a21722adbf2d987d89b81 -8a1a6f06d6375d2bfbdc7531e9177a45330458da2581f65ad129367c400cd77f548aa748bb470bc560c0b02ee5b802ab -a24a05c30d0fcc8334f6974c30d13a5593bd3b388e2146ba006f232bcd6886edffaf7e48ed6126efd3e651997dcceb12 -b35c5f8a5842d97cbe19105305cae1f971da5662c52eb979975efa0753bb60a050206fc0babac5b5083799e9ce8a68e0 -939ca5532c922d00d08ec5914e6c58f8a1302a1214a1cbd5c844b334ddc84e694768edaf1a2af02289ad74970800198a -911d6104a240f84e0f6502597405b47a7faf5e68717f6d389baca62bf82fbb7207ce8d0c584fd9d57d3afe1f957b7cc6 -88777ba7a4bdaecee78d42687cb4fd6dcf04402b43524e2ae67506d93acfdc29d9dae640c05d01c90caee1d04cf3d35a -9226e684606f8169e38dc21a14911d0306b1c9ce5244500e4b108eb1a0c0783486acaafd2e0b3b60c413bb003448ff21 -b2f527adbb9feef9553bf508f192b5ca211d0e491925a2331bb294fcde7d8e0fd72b441e9f07c838640dd35fba03e1a7 -b474e6d6ce22ea272a93a3c078197f40c01b9121c6f3083a8e587c367200b8c97ad94e156883475603f0a66d0340fa52 -95c4d9896df11d2b5a8205a19d6331ea02a2de038aded8e6fea6d79bf5a6648d5d986bd29430e4cb5a6afde8b07a9a48 -a12bc53ba6b6f8350b400fde04518a741a1d755123a6ad1d435c7642492c7df28f7091f17b254e793561923de781eae8 -8a0578ac03070bc920a3b5a7a33d976b3133501309af5339b0cc70536965465b4f7288af70db3d5be16bc2a1e5c26a86 -a66e27284ce6114e48ab56d7f623dc37a6e79cc5f487cb2bdf0acee099cae744cf3a9de53b111492b5ef99b0deaae0a7 -832a338951022c80444ad8c6d0285e86db54254d2689defecac2ed87f5eb4d876373af6d76e3d613523e32c3966142f2 -81e83f01bac3ac3fb67e780b28de30b32247a774aaaae118db3d45c8e74d1d4f1defbf9c2a7ffdf176f5c1cf4ae4167e -a1b214ba7265f692b4637352c6139bae8bcaf3e7db5806fad0014ded93048fa4a36ac9c9e0b7cca0a86cd45bbbba2fe1 -a7ab6f470a421e72fb703a9d153362056ce80c40264a3ee5698168130cab8e827df5ce3e6321ce9a669c87a2e5c67499 -aefafd219f2d062a378474c48d2650b51901b6bce00e4ba0b509395a6fb39699037577da353cbde187e65de87ad01575 -93db16a0a77d1b181f33ef10300112fd8db5b2eea26732bffa3b1fbebb792c6ecdf2899cf6f26b505dfb46deb81b217d -a63b6d9d1cc2f31ac5f836133ae66bc9de3e07ced5026f5bc90116599461dbdc03cd7680c1bb43dade9218ebfe1bc1fc -984b49ca86d38a486f6315f4f9e6ad521901a06f8862ce1fc095d9c66bb2164e334718c71d7472ed765367db5fede105 -ab49ae93955a38f45f756afc4248a37773ba8d0a19779253fca3b744854715b9c9b10c09a37d3426614ffd3a8ced7bcb -b22166dd64c83fe16feecc09d4b1df2d967ce7f4ab526ae39799dd5a5a4a9ebb1d4a432c5efb90e0875a4eb6b079e2fd -aabad619d887b69b9562066fba2179c69c684b8cc9318c9e39646f4a5381535c024ab277a0f0be46abc95283b337212a -99f5d484db149e9f8dc9c6758647c4e3702d88986600a3226874d612bb4b5e92a76b1dfbdb0909b8f21afc773ec67c7b -adc8bb04eb8c56dc4ce97c3fc1670da10db134cff2edc214ee3221079251b968e2dbc087c56c01c9260b49506958a6ac -ad625ddf5cd211102543e0943a7770a9b45cf3550d12dbb484cb5522b70cb626f9ac795b07a305be3e6949d7ad475f66 -8f9f5b2b43624e89e8535dc73fc54b744f247572b2920679bdf6a3ef346e654ec40fe8f81a0f7c7ce7cd5b48f3975359 -b70b1642f28bad56bb24b342eeddf5c3782e0cf6e0d5007c252413bb44b32586da1e3b4d8b45a72c91e44e07334da68b -81b0311e557c47ec22c5f5d1f757c6193cfffae357dd2460019247178b13733484dc8630fe2e13037a1a3d681c69066d -951c9f1504b19acdac1c04aaf535d3cd3e39c431b2b5d9def9b374468e93d378ecc3f5aa02c91ddb93eea431b327ca4b -a85e1f4c292723d18a49cc9323dc7af12bb5a8d0c95d71881ae235ce123c50018907f46bfc846dda1a01b14ec45dce14 -8a46c8b86bf9890df60de4c210cd7865892d0c11fdf2747620289d73bad597e6b482c208dc310c25955dae8392d8f278 -ab65408622c63b67842a80c4ed665258ab617ccd07871fa3f0fde2e5ddfeec49f01d7501790a60b3a05d7579b087b787 -8706913d42b557d9ea4d7b70697069281504b3c4e1172a2291e3b3e0a0305c8d0bff6b7721356d971d2fe58e32d4556f -8d9b8f3c113ca1215dcd15d4c37913d023c8c5d04f617319af76bb7bab72fb756c5bd992db6b9e765cd7695c316360f3 -942d4d3351b2a9bfaab2500b27d24fc2d7237e791993a7d0335f36fe6456c5a1a8bd28dde9228fb139e95288d6de5bbb -ab014e9cc7d3ca08f1d3d24473ddbd693331f4bf21ebdee0fc997aa2faadb43db6a1195644c459b52a969f3d98a85b8b -8b679da80561955990c91da9093837953f4ff7fdc658b51639c462b578a2b31443421712c6b7742fddbe0ced48c21cb9 -a9132ac18b1bce93e815f6d2f8a0d2f433ae4d6fa04269eb0f5f25864a8009b01531c7c3ebe87f07454927a010ab6dbc -8ab02c113149efc877967c92621a8ef618bf423017e78b9cd30cbb13c51200c6ce27c46be75e19ba843d64a3050d4467 -a881043298341efc28c60d850d90d90279fa6d8428953337ba57b74eefd858e362c6118a82ebb025c9c102c91b4aeafc -92e4a587479c64b8df955c6bf1abf1d7979a978e45d96f05bc1b9648f10428d77890be9ee03bc1b1982f5ae7b926f0a3 -90c21a22826e2e9978dd7522f51353fb33224cb65603779de41db3ba41e01d664e131233bf873e28d6c71294b565c533 -88e8ccbdc54ff06380c2243203d3f8c8a75fcfe638d6e6a010c0b3a39d5cda31f8d2cc416ee5264267aad2b457c94e50 -a256198394b458f6468dc91c35f579da0ef02a55fd93e98b25e43b1bcb650ff889df4899236765c1a6b35cf49da940bb -b5c7d9c03c36cbca068abc6778053727e77d9b58c5dc33b11629f1ade1c228b1c964f5a7d8dea16057e76662c4d79f18 -9588e133517f0d49622222b4de5c124b1aa4260971e43e4aa767fba8055540f2848954886b7f245583ea527fe2fd1de7 -b66025d75169bfc7ea366cd32419e24fbff829709e3e9587d7d59620b3a7b72034d3303106f965f5f7a71d66b7f314f8 -891357bbe44e60627b975c10c872a34b78d6b264380e351f3a86dbf99abf8e2dd8d20c52dd6073086e48e1ca782e2ac1 -8a066a3482526a92476bb8c3e5caf07575c725d72203d67ce98f654f5ee8b7f979187416fe3d7ae0128800b253d7209d -80a9e3d8900046b71fcd5b7034d1e0f57d95d2756da8307a11aec0553e5715518a125a653d356f399409545256a1984c -924a13fb2da7a899cebf2ac09c8c0a183491777100de1aa056a6c2bceffd5a63e255f16a9066e4ed89ef28096a1230bd -866cfc8116d2e0216d8049d5ae2ef0e3fffd377028850716a4bc2cfe16c5a6be023334bd6ddafa0c77913dd4ff0a34ff -95eb74bebbbc59d793e3fbae8e98c258451bf9bc5097df4edd832e9f1c30a1446a59e1f75a44832d0658d5ecc13dfc86 -972517b2d72ab53193db5d682db2de7790a418ce4952c29d64e1f9107d51a782f4084591b7c775648f103445b797e8e5 -a14ad2cb69da568f2f958ef4253d7a6daf574c6976f4f5d771ae7673853ca22eca81e20400092bac84453b6eedf5aea2 -ad95bfcec6c06cdc11d316b7ad33fe65555e985bb33b15c9f481a09caba1e5990601ed6a88038c0ae2e04b1607e2da48 -b7e3bf3a585af1029d83f12cf75acda894fc4441cd7b3d56efb6991ea91b07512bcd7d6d68738557a48f0446b2cb21af -a57efb1e2d2e10e41f356768385375a21d9f78bdb34d618117581bf7a15024eba43570c3956ddb85a025d39476f831d2 -a66d3622b1cdd472a2a4491881de035c2eb4f1c94927902a3bb9f10739f900130907c6b002982e03785c43ac30b8109d -a79f2417d32fd772e46f3bca61ac788af8fab174e1e1e48a84ac557f7e80a9cb4e2d7b467365ad18f9777f4cb5bb2b8f -b952b976e3b6660326c0ed357ff25ee1291b74891f3eb7bcea39dec2ebb11e287d6e26ae0506425a20e5e445273cc63b -8c23929e9740ab51d9b82c6b7840067e7163e6c7b9b9441e1bf867ca2e532926981c98641e6c798ef12d35108abc1dd6 -a519578772c9ed2d691a8c423d360e4bad76afa422f1a5218a7a08ed52c9a5935ce2ae4c0be182eac0712259a43f849d -b1529dd189cbf3bcca50e97199bfb85b42f2b26edd95b35758d988d1d3740f5d0d2e249763874fdfadcefad9ea1b3d02 -aa3fed8d14a4f38df75b9eed7f187a31cbb7a748bd3225dacd8325a71dfb680729fcc91ad8cf0b67ce314e1fa8ba02c4 -b77c28abce17732a08e682491182f63fb55640e60384932f6a9c6d3d7886508c9e67a841cb93e59448d2d59fceec4620 -b7a24c58e3b85d60d654ed14d78993a9cc78c130442c8cca42921ade8ec94bbd0653c9fe5c69ad1fb2aa46ffba04da39 -b7d08f3ce97901261514a5dbae582848e75515c5f9f41f5e70ec17a8d0db3067ddb19aa1c86803bdbb757230b148bb21 -a5b8a6818be4d59079d88f72d7aa4957c48ff5898f3fd01def48ff6bc7aaf9840aa91f2f05617d340092dd9299115c2e -8e548db6b871fb23ca1cb8538d44b77ad02f4cae4d33c8c43228b820abee1aa913ff9acf2483725b195b4e65e2e92063 -9509189e063812fa04f4e26f87b33a2289a05c229ed1038fde0dacecd87aa55ae0fdc678a1c86bf13b81f4b3a872426a -b355f24a5dfb7a8f3ea717111a038487632bf00d67cc2cfa2ab61e1cace7bc7f5bc9e04b190aa6be0652627ee219bf76 -a9b335f235df51b92f40f44f19150e182a938b9abb3bdd8e8c447b2b128050d228e0115a268af4c1bc2ca49552b4e0a6 -b306d3e6cd7ab56f5f7572fe51175ac6b29b189220fe2d380b959d131a35804da5ce95adcfa51d799f18e27d8d5eee0c -aa49cd2bd34c37ce1f05e192fa6837f964c068170ab97989e1cb22ea7e13c2400417a51282519e74d8fb6983ba89a549 -b1d4fff41d95613e30427ae2ae1d3df8c9d06389e1e0f404f8cd40199d6c4277b7a898d06f1579be107fc5744247c36f -99d220454889f476931b0cba3570eb1a8eae30b4c3617513833a551aab0a2630125f72dafc64a766b1a322dd42dc385a -8267ae38c9c8532c7d4ec4455279a5ed4f2e48746cb0f2619937157534b0e5466c5f4b99b7c342c095f71f3b77fd5882 -8bba0794cc4ca00eac50309a92878084a6a22e4c23206c68b8d7268f9e7f615da4b9d0f3e006d9dd84bc3dcf32261e27 -adc965bd7c7bb2a52cd3f4d2cd3fbd72a196876a678863c6a67a25b4a2330d1d3be603220de22c8c3f60c1411df57b7d -a7d5f38a3c4ca0541d5ab101af9c27b04c5bfaa42a1715e882c5e7715e460c4666aac4b6272b9fc54514346fc49d0560 -af94b91ad9b0f01df1d41a459f16ffbe30710325617651cf1da000eec43876161957f079a27b70018ba34d1d5d68cf6f -a0e2a492da4614f41741157d3a1d19a2370ecc8e178d813e22b902cf7454b8237f1ce3c16270eb6f3ead1f92797e36f2 -8dfcd39155d7b8073b0a1a9a617fa75218f569520d4817f3ead375850ea8a3e3dca64c44e83f54afc37173d927070601 -98302358e5b740b73e1a6c568b99affc6de3c7245ae96d9c712d377fd363d8b8f49dbb714aa8d39b5b947b6de341ece7 -a2fe0f9fad663cbbf4bb05f61edfc90716564d5ee5a9529ac3cb8f06f96329248cda85c43f24a2382a9056e9a53520ac -ac50b0727ca2ba80692c0b7f564417916695ea3760ce9fd71593050912bb97366d29ae5ed05ce52984e52218854b8e3e -86f56bea946a4516336a90328fb4b24cc7f82d8710d0d1e34c2e27b6af73c4f4a9d6a848dcc56a87d6259a99ac444557 -b33d0244948c430a58b210943e41aa3cfecc9a823dd3e160634ccc45ea2680987db2912ab2a173ab6cb9cc2b7e16f7d5 -8808f8c2c2377cf52e7314820d88234d7819a6108fe9e1c6a675dc47cd59f81f95594ba2f5fa10e3719580f53edda641 -ad34a814be6019931972a76b3300a4fc9ce763d6f4fa1ea131a67d575c00c827b9ae7260d88577b4b3689e90a845137e -9370abc67ad0fedf30b929d1613e336c6e99e4bf83ce969e61e5d77061b48a1a493f28fe2eff436d4a979af700a83b5d -b0db136c8f4ba2fb7148b1451b18f694769f5e53650d68342f15817b04734ef8ae59681a5754df617d755a687b6ee45e -9149909d24382054a05fc0b057613d059721f132a19017a92198b30e48fbbc5f8f0b5f5db55347dbd9d190ca88f9a28e -883d1d170fb0fa95b55b10b32ebed24b1232dbfb5c783148a63a765fda200e796aaec52747441704967914433a01a323 -8f55fd5ea11c4fac277112d72489ac1de28fe163a756b125f27acb78aa6651c70d1cd8c45e0daae417bf894149ed2d57 -8d08685f99aa8525b008b868f5486e24a08568a5afba9b729f7d26370fb1b162937db28b935d67e4d22f7fda69a3a6a4 -b1882e23d784ab48b2f9e58114c5920bc9d0c4c01d2d7fa5111561df0cf2d738e31a32963cfa58939af87e79428659da -a3eba902d376063e48634c9436802cdc6b89d3a7c7cd03b26a3fccc7218dca85a3ed939eb53956d2e001805aa5c2d63c -b97330c40d51a4b71f91f56292b628379ba735509a66c7df054112578b9df40d3aa32598bc64c03c78a3311a17997bd1 -b84f3d2af2aae2aefdfec9a0693f6bd71eaf4d477cd72d80f4919235a471607c5483b354c9d46628a76d6b6fe7c586af -8a1c39bea7fa580de967d8ced7e3860a9031b07842d71f8c5941b8877cd55ba15ef7aec6116ba38ba290b887b4530685 -b120fccf939e7d7959c2c1e70d7a7aa3b84684dd1ca8e5cfa9d281fd06d23eb67a629b1a27052614c3ba639ff9c90dde -827a8e0dc841af0e2c4a9ca36c84a0ea60099aecfa40294344f82878b6909f5581f7b34fa9510883113795bd09b5e4bb -88c24cc54dac5a2982be5ac49684d99f95574bb8cc44afae4f6e18231ebea0f2ab65b49870840bd3e8f2c9247f62c7c0 -b91fc3f2cf743f4ed42e49007514d43dea1d7bab388a18de6f71367fb8f2e9b8e88ed9f7492b647e548396ef3e3d7765 -a175000c4765a57c57b219b21f8302cfd85aedbc3340fa1690119bbe7cd93dac4fd0ba676b1784ebac83efe3e78d4bf6 -881a373630ebc24dfe17e27b3f176de6651347ae741d55675675e9e6904ebf157e787d86eec42ecebfe4eb8f28de6fc7 -a47c8b155c8ce8e16f38deb345a051fe0c9b217cb7a266fce78d7694134247887789645a82c0ac24341f51da8ee6ef00 -adfa5bcc682d4449adcc436649b444dc61157154e24d68615b0ceab50eced1ab55e15b45562dd8e00785806e9ef2b7e7 -b7d2ecddf47e9fd25dcb283eb80e323300bf5c3ee3344abbc3a1f2a3296c631577a1fadfbf685abb336d5d7059d17166 -8833f6b388e46e1f8fef1086777466277cd418051ac0323e2cdac5902d7ae45eefef93ce90b088bbd618e0381c1ada78 -b6abf44c5aee5d0fbfdbcbf1e77354d5a2ccc239b894e1e06d7ffa76584683f707384319ab0e0d17afd93a854d7d26b2 -a8c61859a9553a83bac398c14c987b20c8dc27d63112115b8aad26bca275cf98913783c802ebe3b7c3d878c130407b34 -a5de7a519f8de4daad9137f2c2838544219834cd70457ef09467d869f4dc32098b7a8d4fa85e1eb283632f6d09971318 -98c33a315a66cd8ab9ca8a58c87e5ec588107a6416c4ea498d0b91bf7597f53a405e437ca0a9d9c6acea27ad0ddbf4cf -b2909b1f8752f4eec25180a17163ab215fc20c4a931d4471d3be0ab64207a65c7e462fc0707791286a92ff2f2b7dcb0f -8b96c2fec34cda02e98510a3ed80a980b0cbf4ec03e3c4260f84027cc7453acfedb5f708c401d26db137032c6cb4a31b -aff645dd6ffe8b5076c83a823daca4149f0769bea3293b61330ebd97a17fe16758e4fbbcb5bea7449595c6e261127b34 -a45f8b3b7196449f9952cadc8d87a787a28b4ed89f8c7599e7db361cd0f0aac6bfa464024ded5c0ffc660e417594fd41 -85016b5f7ea9863557eccb0e742cfbf0b09630f0bad3de55aec92b95d4645055cac60d03602586b34f774bd356dd5554 -94fd89dff2fc6099e5ab90149458a4c794eb1857f1dd9a2c84b88099412477dccfc2996cca2abee68d23a05265dcf271 -945a52621ec19d26f7c8abb5d01e4f5630924b75a349ce74219377a137f4a0d386172da523edaa522d27902444023cd9 -afbd452dcc57f5db6b3fdd55368807320459c16559d944ee8ecd1af6acfe9d58c13f37961f78030883f8ad7dbfac66e7 -8ce96b3be871a1f33d559a6e55e4d86a0b92ec3954417f8d98676264596c3296296532097b9b20c83c341527a0c929b6 -ac6a4dcd58486d25a4db1751a60ca4d02b80c939b39ca165a37d9a0a52d8675b3753719f136a59ac400bde3efd036c8c -ac87a37a14a5d48842d30432935929a0e9dce5642142a8c5b95e377ad1bf52120dc64697f0508b7c258af24a0ef484ae -859f0ba02d496861455d9c39c269a1ae5bd224319918fdc3648311c93303c0e13301ae7f3f77eab4ae43f1184a912b64 -96d9b1d2d2fe70b8fcac136a65b62a4ded85aad9d350c19bb955750a0b24f93174e9cd00c0e0a1987793e1180dfdf66c -a7f5135873a1c08c7c8d46adfed19d0ed0e33168d463ca74f75116168355318ad588ebcca1946d7669c5106bc9f5a8f1 -830b0587587b80df078ecfe0857a4b4cfc05b722c0f4f3e1217048ee18749e9940cd0200c1f7a0f60de832a5a44e9f1a -b6625ed0199097acc9aae20611f02d2fb837e4695762cdeeb4dd722517ba5a344e5011f14d5076783f3c32bb5c4a027f -a17be2e528c463aa4ce4bba2df5b005f88e363b87be7324239413ecd5bd68e350d290370e1080ab9911a0d54856536da -834064460f0e5f38950cf5ec197818712f01950ee1f32b1987dcf7f4098d20e1d91fae6d48e8a054390693a2e572f888 -86217b9bd269408ac92b5cffda5716bb3bf8674b7e222668d72939a626f4ab64f30efddf85108c0764127cdbcbad7d69 -8d7cf47b0648be0bcbd3ad1062d90010e5ee84e397895ce98160d5a568d60a19582c985944ec27bb284459789ad8f6eb -ac056e3ed3487427142b3a4e4f9db53f1a752e1994f178577c46dad71be5fad4d03d24ae7019804c41232705a4bffaa1 -94b83d67af6735e81b2e392e6af8ee4dbafb0071d84486389f36f222dfd015da718c621acdc4360630403762dffcbe3f -8ad27bb51c6cb860c21954f5d09dfefcbe3a9a0bff3e24fd1f74850edcbcc76b5b389a616ea0c0796b239b0c22357a44 -af9990dc4c9f536385811528f207a8352b083a4abe6dc016eb5eece0ad74da65b2c6c475a78cd0ecce0b2b550e4412cc -816dcb8ff8556540b54dcc1efbd2242dada0acc1e3d3da13ae581d905a9106bdfb8c138eee93992a23e7740593e8ad80 -b8fcf8e11e5924d3d38643b2a4bed4b54e69f816f40d4020e76655eba8ffee758c16cdc2d970d3c8c1163cf501044c03 -a50e0ef4ddfba6d969e7dd864a20cafc7fa6aa232fa7a806c3d53c3e029cf110828c5a9c354ea42aca5688896f27e6fb -a560435900c48879ff3f89067daa8e512482f061c68474d951c608ebb5a69c7863a28fd1e216eb4b140e32124e50fc73 -b9202d152b7b708ee61c4fde6cf423b481854538d2580bc43462610f12141b89ce779c7398a35c27ea6ed0afa5332bb2 -a9b3f8be28f9546bc70f680dfb9b08c1eea6fc381cb6f3ebfbe33bcab48294347d4e64004c11dde5eb409ecb19941ad1 -8cb3086d265060f8e52a96fcecddfd261886002c1821a8f59a1ddde19a6bb1354b17cd19a9cbec19149dc219a4c394c5 -906e8dea406ba0f0ef43ff623f8521039a9455a2290cae4ca9bb6494ee0aa812528267d1349bd5d339113dc9d1616b28 -b9b5212b76d5824d66b8df7cdd5effcb05ccab5df6ce67558872c99d1e484ab8d21037bc0e22f5c4082b192972b80acc -a1fe817596bbb5bed93a5dc4c03e14eab627484cdc7ab7e4fba569ad0aaa93b34c4fc8680c4f8180d8190113218d26fc -82fe7a20fe93564cfaf7eade8d4d1394d1b4e36048cb8632bf366d3d8084ee52c74d65c4c69d9d24208f7916278aa592 -81f42f9a3b8007e5f02c26770947f884c715bce1e600f38f164a390f159e2e5b6f8522ef566bf36422b14340bb6d3556 -b53d3c89bf2a4b29bdd8f1bfc001c2533f86d869fbdb383fe9cd93ef0c49da0692361baa9f537094e1af662a3461f8af -8fbeee613823ebfd514e991d81babc05176d5c115907ec36dbf83a69eaaacd622f1f36be2e47b984cd6ac66a6b35816d -a9068ba463ac13d4dba25f9bbe3c93baa35828563f357c53a7009cf0c809a23502e023a32f651e29f14424c5daab2884 -87468aa4c942476b3ac3000e740c4dc72d320884357dd99eb25e81d7b52a859b9ebeb55f3070022bcea3855a9a198e9a -a5f1219eb902234ffe8ba809df590080ce8329ee574eb346f6b4372892d66b0725f048465221655b70b3d4c2deba9fa0 -8d9663d4b48cb86201d343b20a8e7a6ec47a4bce0e85a905be31121a01fbef95d9f29d83530faf79dda163c6c76ec514 -9921ea9176744e15f64b20ac6e95ec132052eb853ef47e9334108778fee60d9d9b53fa0b8011c6a4aaae472eb11cc61f -a04c2c5e2c5a7673652919aecbc5fe09a636fcae2d06003ca6775018112b606e50bd2d6ae6ec6131d2a9999837186bd0 -a00ddb29776d2747e3a6e68eb51a7cb00ca0066a9aac5a2da632f355db515b32e2c441fde870c9731a9dcc8d9834557b -85afeeae8bfd92c51522320cded430c2fef57b1950f9f966f47ce6354e492e9c40f950a7ef6d5202fc79fc020f7a6260 -b047d214201744cf7e675af5fbd29579c3b26020c5e0a53e2ce078778b3d3a673f0fd87eae8af8f0fba3bf0f8341b63c -b8aa5364d914020158d11fe82c2b77197ed2b1a12492435200204e20a9209d3c0b4fdb6fd3f0b1db71ee3b986400ff46 -a59a903fcafaa8b5876a3eb1d79a7db17c37457dca018e393324d8db3be7c2aa3ed2303eb3530d6fe1612fd75dd92e08 -b1929c1711ce44465daada15808099234c0c5c8f43b050b2792b6ef9b77825996a74abdcd84d6ef08d648e77cf804357 -85bdc33f8dda0d853074e0657688899befb6356c38f0ec2ac27c46c39fff06617edbb1c5cd220314335bd1b792f1e240 -862047e51f9119f5a0a607469496c0574b0087d566bc58cb5b61a9a841a3cb693b89837a7c927c542ca03d0106055438 -84ba54c002150e5989f59064b68989413abb5f289f3ccba215b923f86f76c19718be51d503ce3bcec68322a7c7d5446d -adc9ea06c11bf3f0d704b321005020917e731e6706f18a5aeb1b56dab3de39a94fe8aca3c248a47565ca5ce82face9f8 -868324c4ef80bae55510316f3a8b13aa40e60c8a3d55f4994439d1dca6f5928c4cb202769d78c21597d8737e391536d2 -a6e3b57e9909b5fbea2114c352b34235a4d4147417e480580c291308b4b9cd696b36278480893667e8ba01fe3bce571f -b92e1d6ba0a2a244ac5ae2e7b20e152591c1c466c9b4c658c72cc5985ded0392b04ec00e32291f1652d21dcb633919a6 -a3e2bb4dc07ffb1e8dc9055ab45bf22864980f64b612548ca7feac85ecdc426f773d6d48bb7e6c7a578025bfe99307e8 -af764cdb70d5afdbb49dddd519451218db4e97ef3ee622585880425c3d85a8df88613f4b51ad40a1f6635e45b2efa5f5 -a426230b8ed77eca3d1ef7f4735fcfe0e51ae37efea5b96ea3bf313c241bd703b91a592f035e98056315c9822ffe8c26 -96a3ae7f1b80690f97372d086d2d13ea2b40802bd053980f73cddfd37045364ebe38064a8cf3531e9bcbfed421040f20 -8cdfbf0663bde624b703d7e6c36c5753282487147e10e5a24fdec75836f7034e4c38f3fa3df373476af969a4f835cec9 -b7f7a549cdfcca30b78349b831ea5173bf5b91d56dbb999b2dbf6b85d8c22ca8a9a62b38e37dcad7ee5136a32edd5743 -82ca90321c43d616670a7d85447afaa9034459b796b51792c970fd5b8f124e47a13ef661291a4ea58a495e68aa36dd87 -a824a36e4e2db2bbc513d39e4e2a841fa81106437eeb4fca9ebd78050667d0b284b7217a35ee3eac67d8be58c0af317a -9370dd0c0f9c7585761eb5f06e7899d75eac07e13c140c64d4c506b90495fb8ea914f222608c478708d4b47163dc9907 -88c07e19252e905faf129e3e877dff8dfe93e81b3903b150aa33a93a7eda2820a8471be935825d709dc662d06c9f99b7 -81e936c00425f7db8f0dd88b16c3c5208e8d95a5072e69524f3b5de45f4e2dd25f0aba8ef17016bd914bc8f5a42fcb6b -b23227dceec18d6dda92a15b7dc8623d9928d545db93b3547fb068c99cacb3fcf3d7f88e4357801de8a652b919dd907a -b23f1627219587773c17070bbb190e1280ab27c5d7e98b43adea0e1f5017790149b71f90c3691301bd514d20238c5e6c -821b7bff6349c204ce50e00e296982536baff68031165ae4c639122195e7295ea0c82ce66fe32a1b762f6a311aec384c -a26c15bf1ef4d5543c4a006e4ad2a450d44c93c62c0f0b035698530cbbf925f6705d375e1dc8b2c6fd9a2c69f4126b77 -b5c5bfff4697fe13a5177fd87a8e293fd1c6782cfb3d1f95c5ddcb13c309dd1ddbeb14cd359c9f3029b57ba52996c9a1 -87a0d37f04155bc22ade44f567dd8a81445facff15d643886cbe6534aa44505e331bb75c9ea2f27624154a5890aaa2cf -ad85c0e6345e2333a0ff76b769592f2b24fd0661984498dec6fbd2d9b0cec5f139bd71331a28b13aa490baa7fe27b635 -a9e6298b90aa8d3f4385858e08f393b3bd61376ac3dc44a0907ccfb372813bbfab1388d544c1a4907aac38a87dab2abc -b5cfc8bbe4cd3ac1a66b1c8138c5c68e643f7f4c310cbf1483f6e48d4f7e2d1cf24b2704fc687032eb03978f18239072 -9493895ce0c815b60b0ab3a989f63c6ba4c752976160f3e52290a724ddaac9075e07dfa913e113807e0e57725b1cd593 -b1e800c2aa32d34d34b24dcf890f6ccde7da60b98c4646a5471fea7cc6df8862b7a9c4c40f38d0554e33e2984fd564ae -90a18f877f149a314767f5dc15c8726efe5d20a8e15ad4922c6042420a2cd82018be813debf02c6d69b96e8a27c0c5dc -8fe35142442c103e7bca602445b87cb017c76befc83d66894d4f810e343b3a571f3fba14d94521340ee7c5ccb13338dc -b43547cfaaae899fc6295f496f213916e5adf9b0d75805c32df0f969fbc1b4f8584759b2a06b81546b48004d72f2e8d9 -9410d55865098325c7b559eb4e84fef8a3ae890e1d6053b3f173ce22e60ec6563041ad8cedaa2dedbb59f3dd645dd1b1 -b127d9e4b8280e10434d53207a7191782464ae83b4463cd8a32026e5d8a7a8c5306ba43ed9b7ea637d65f64d6a08bcec -87de8fe67524c7d107d7033d4107659206c347c47cbbdf85e3441b53c933417feedcfb049465c67f4c4156219a4f63ac -a582f976e77b861731595ea8450c6b525e371c6548cbf7911f05560d4c7a4b62a425d5c785190628d1aa1f8f27c43b51 -a195e358742d924fe2a7f955eb21ced7b211cfcd5dc3e598e0d2713c3639b72f986aa586b7a22a75f8547bfb46cd52a4 -97c249b70ca2f9da728a256d18d600bb923005ebad3e1d541ebd580af3fe07123fdf87f4e8f98fdf9dc8ddd826ab7344 -8fc7891e2f540d8f20464a36056f227ac2ef3bcf2b6edd4cd2d9024a48fce19480fba36afc7f5c4bd7234787b8d17f31 -9047512fa27e2d8d901516b5714133c1845494b6f2aeb2a0570dd8533852f00a8d9a8ca64979310e83ac73fbeccc33ef -a1be9cba454617af0dd38865ec29e7d0777d7c68968c856f90b5bd63a7cc4274fd8b179be54143bed972b921864424df -b086ccc8a705999184f51e9b45c76975ca8b108b32a3955e122711fc1ee007d8417a85c9cef217f28d6c7799b60aae4a -ab0938a72118ee2980b28dbea9f7100c6f54fa82d93fba8bfa81b6bc34f9d2033a987e5d6d3816fe0bad53cb88bb8c2b -90fca0bddc14f70282f11998fb4c289fad5c0e78c8e8f9e7a811f20413459a05c9d107ae771e9da501854022d827f2b8 -84cc69b7200f63c2214375a7a0a5ccc14bc02ae45bb6f3b27f67ac538d01e628c66b40e5c40cee38bc8634f1a3c3cc6d -8a07a1cc0a96e6c6da0d27a540e235c2ab6a95d087e624c90cdccd781a9bea6abc0456d896574950a9e21e7d87fdc582 -87f2084a2f2218d7f9eb7725617ea37db0a19fb0bcfd7c95501f62fec0bb6bde3950690420a40d93e26f426fc622c825 -8c9fc9b470dcf8e576af943edaad28c29f53ac7e24657618c21d910eeba6d7b16f16c418bdd5cea3d639c3919e93b7dc -8f026883d9d8c7c2a5c04e4c7220ba7061a48392a8a7794a3e290a94967d14caf040a3da3513fd9b4e695376e706006b -83bef852b9f387a2aed0d3537e77c895799c639310cac98e7b699e9f5d74b2b21cbca58ef910c6583e0b849d665ad379 -b08a03accdc64474490706edce9df7853b78b719ee731c195f70871b7586ed274778d99b84ec3cb8cc0b5e38c102bce0 -99fada688669b2ea8d9b7cd730b057292ec3fabd30cb733ea3f7cb76f756b244cfb26df03b9c087b6d9c58f5233dd1b1 -8eb0fc7ab6b4238f2317620191dbe835d4ebaad0882e22e8f0857053d25d6d9077754251202472d875303669dbb806ef -8fac2cb38c3a1e361aae5313ebdc1c7e0b7d1a440482fbbe24389a7fcd381169fb325c79e430be170452326cd4931732 -92bacde1472436209032f0592973a5a40d505a9b2c9de648eed1ce392d0c18e23aed9114a9634ad3a7e6afc4ea80ff21 -a28b394018434be07323a2356fcfd6c70b3a4b1c6b6ea44da1da66c389a659235e0dc941019bc5053ca41f10d9b6db2e -a6d23d7fe7ef475bfe6486ad4a99ea376c6a6db3e70a0a7af421ef6e6c4d6b9cff68d03a7239a56eac784769f63b2bf0 -a1232e6747573e19df98a088fdba57116745612cfdd4ff21f8df82a66c7d5df7e0a6c0cd73117121a516dfaabd0f5016 -8dc574376016b73f6730103cc45c952c5df5d047d0b4ab3da0303f66f43f7d147b5eba5300750e885c621e72b4a64b43 -a66e9eaec79c958e624655fc2adb7b89ff3da0393898e028bb07cbd6511ca8d9318e1d60dc11cf0265a498290e756ecb -8e5299b661dc0e088527904d2c2fc0256613a1fc2b92bb92c633acf145edbeeb053e82b468a3877f6f14f0878fab57b6 -969943ce7b54f6e728724b26cfdf4df90faf9f9796bafb910ba66d96cf34062fee6ed9121abd193c9e322950c8eadbcb -ad29ce021d7fc875d1e61ad3a99e112ff092ffd7900a608bad30517e50e2270e0f8dc7fb5cd42f1bb995c17d86268f48 -a55fd82520f4d35434066bf93a9601c96549cb4714d9ac05c32e16803daf8763e23c3125d2005eb229bf5d7e2a91ec3e -a95eccc21af531c5e1a36ce88eda6b87732f5fa680e851bdeaef73421c1c87c8e66bc314b07ab472ecb67a08ec53cd4c -8f48b5a0636bd89a1ee259223065449523984cf3bd9be78c9242276c848d2140bd94d1a6670e446b51b178ff694b5c7f -8a58b340e30f0cbabcba1c565b68eae66405fa2242b43a7f7d3bdce279af42fcb4ef58c85fe89cc2dc56a41a51f058b9 -99103a659e26c9a4d19404db4220dcc5defbfacfdd969eb7d70b4fbf9b2c91c92112c0097e8f0c32ddcfc35741da21ee -a088cc15a45094cffac52c38df427b7144d621cd1d12ae87d74c00a039d757e36fe3cc2fb35fda9b33b375553585497c -a0f1d15bc388f6602c975b4b9cb23ab83fe31124acd946195b999620c3c20c6610157a891114a43e3af551d7b8c3e4be -a571057592f3a9008bdf726254c364975705a71bce4e084a37915c5317f635528088a2f50afdbe7240c14d813e8e979e -a31e425feee58f8372e2bd4c21c48c299850df34044f27db3e4df55fc5e7c042cd19be59500acb375fd3478379f06053 -94645ca6400f80d9a90f5b1c5b515816d6049ab04a552109c9c16b41366a7f3931d49338d944ee8eaf2ef5c77062c362 -a61fba865027b7ccb03a4ea966081325eb64db5a64c5d765d2893f6a19411d40dd957d8a0b34733aeb3f002a4e0279bf -8199b89ea13ef8eb2f54d27bdcc781a5a7fe5bfef4ba4444bd651ac6021f4d90250b2f2cd8c63fa3ef237ac6eb1bab36 -b39e1e98d07c95a4fc19ab175147547e5a20e66c044f29e4855818db4a7d0e7e2c24192aa8c89fe378f8d8ab3e9f0e1b -b807bb0069474e190b40bb2b34165351e73a392ffb0de83879ddb181989a22bccaebfdc90748f54de81c41ea244e7ebd -8b058266df90032a1a9befc7abb759b64a23ab628edd051da8b81db4211c72fd63093dbd94796b0690ff2b0c0fe16cd9 -865decd95200fe45947a4249d2d8551ca5d7b3d7955adf10f94ada3e69d684e5c5b8939fee9a4457f22d21bbd3ce9670 -95fb5ce7af13976320b36422b5cd9dd46379d13110fce619969308ed6a250cf3eb84c73e8ba1d32edc01aa2f6e367707 -a1a176350aed82d5ac01a072ac7f3cc1535e20fb597ebc7e417921537f9bfc4cfc0d490d4df831f0f8ecedb6be970a15 -974ddd091c1aaab7ed356b65c244748a713e98b133c5606436e531c31b31f6ccdcad2037b12c68fb54af4b19bd1d82ab -8ae9b7a8cd856087300ca90799ec3265b92f84da8ee9e98c6ede1be378dc040d0fe68b8ffc94b146f2521b9fe3d19e54 -ae17df60b83e4530af584991b545bf4b3cc1045416dc15250a6b75a9a04defae4c0f60b8bfbeb54c8a21fa84fee58e69 -aca1e75d4a05282b0cbe6256925c0f269a4a8323888bece4a48aa0b5e7bde7fbf1d3e4f5cc38fe6a38aaa091ccbba4f6 -ac19171d3ee2f2e5021418c37a0eb25c083de6a6396290ed35b4771abcd07fda745fd082e3c32c117bbab7d9fec2b67c -ad8a35eebd3bb28e08b9ef64bf2d8b75ead69db29c96544d71686ccc0819ebc6823e49b3b879ce0e5ee3131153900632 -9479f12dab191269b020b70132996cb32059ac087e2a3f3e559d297494189e1d6849c340ace032946e12bd4923a3908e -8885e680de6c158cd67d66c142b2b4ac42b96e97eab8e2dcb90c3b454dd214bc530fbab6b5d5746064b9813775b6d5a0 -a16d8d27d9b2fa04c7eb8436062a53ee0a4d679bb205d7d7cfc24e5f28e3752a9959847e9e31496bb0cb1c11caadc30d -951b00c69dfd9fc80b17733b843c440c58095989bb8744fc9db63a4a6116f24d5f224a279478fba8cf57753261bde217 -8a693564994a1dd298f0b279e618b46bed349c53236fed9d8e05ad9383ce55fed02b8a361fb8c09ec5ffa8a271cee015 -a09fbd62995a33904b4a34ac55c80f6d4cbd39a902f5db1038d909f1a2d385c3f5eab04b157b5662558bf35ed29cabc4 -8662373988373409a4b31d45c5110afc32aa008bccbeab39d5b09a0e10370dd879684e722a8856b0da278e2bb91d67a2 -8980d3cb8a82b3a827ba65f44e50efed0a6f37d6c150d70e4dafb67b1db173b46ca29d487ef9db92d37ca8312d246008 -a279558faa11850aa4f0dd9ca8bddf69cb98bcd4edfbb0c19f22d1bff85d808e8f2cc026d95afd09fec2d15c116bcf73 -a3fadf9c3066c93aa6a31d2346ad0a1d012c12ca7a24630aee46a087eafe5fa518d20647856d44ac03576bb3a9f81a76 -8a8a19b09417e1b1607aeb54841fa69f58e094b46971c6a5cd0fbeb2aaa98c56599ac242272e6973ca0a9d2c09ff8d77 -858a636f510b494edc76e86b1718228f076b8a21306b02abd086dc2a96c7a034704d743ca5d89b17903fe7b2e43e6fe7 -b031b789e4073b82bb8c78f9d3fc2b901d75278733a4fa0a5aaf985a298269a735217e85eacc0dd554375d610a425359 -b8603ce7cff755f5e07eaeb4d74dff179cde405234bbd7b3f62fd903054aaa34a9b868b04617d7d407c2b8e377227f07 -aa41829c941acb3f9f0e2008e852fe855e153960cd3c85c4b8ab9f97ca91b7a5aa18f997cd023ba9e03a653f238a4f46 -a35639f920619dff592176aad2b4b071d5c960f149c3a75311b16841d1872f29aeeb7c155cc9bff41ea7ee56f799de78 -b252195aaa52e9a34936ccd1aeb40d28fc262cc4570d4f9685da8c591080e97438edf64d4d4d074491344bb5e86b6b23 -abe2e52d10620b503dd1aa584e005d857294565ad90dd89217a77fcce4bea7b0c72d54dca7a1c31b5a9042a9602557cb -818085f2f1b525d9b2322c8785bf27a6759af9aeb231b0977cdcc7d7e77cab5de056e522dc791e72b8d9b93a9c41e833 -930f64d40ab26be006e91deb854c5b22bf6951308dc406b2c7c7791d5dcec470529957fbcfd6a3c9655d544d974de7ad -92b28bdbea8c7588ad3a27992c19d73bd3a478b276f0e11c4e82ee2482e4e167cbcfddd17a1ac6bebdd862be65f54098 -afa6a85fb906f5ffe52b6e9715435dcdf9f7892a396d740d67560fc42248d23bef470989663a73190ac9da442cfe6a82 -82d3338e58fb316d66694ff4674a5d99bf0b13204dd251fdec95d48382f2d2ac60176a19e5ecbaab5e00af2a39a338b9 -b30cd35eb15b3910b8b8f91cf04c223d79d587a7ef713030f0ab93f446caeef52c60ada365f8d3d645b477e7fca61d94 -89554d2a9a11dd7e56f0b568f2a50c72d86362d95eab5d94a2386397012e18bef7c9e01a2d71fd325c0692e4d316dd16 -ad58326fea1c00e0f8aa92923661be4b3ecc79164d68e91c4d1366c9894b6d049a4f31c9bef6e5f21466ec014ba6b94a -8915a16afb0e68a84fd12a9203f8f348954920126d88136ec027a81f541b67c421b84ebb3d6e8f085c38c2499c28ea61 -8e246e1acf655572863481367da007e94bc1bdc1f28aeaa1fb163dc05a51c3526a2bb9bda0a14fc6d658d85a9322e44d -af83f9ad3c7c1504fcf60084e0948624fccfe3a9892dbcba8f166d0d67b475ce57ba008f286069da20a0da0cffe3b4ae -aec86d2d803612e8d27a01e3382e0a876164baaf2f3b8c4e9455ea00bc2e525378018e6a41ed9686c6408148e852bec7 -871bdd8c84abeb1456ef73595360de6cf9f92ca9e6a8b6b816ec7497be60a9f509ef2c91332d17cb5fbd347bb0113d2d -9503ce513df28b61d721fd5e8667272a28f210ef787bee58538f786acd16f04a412387c6f5e6313c43f426a70aab65b3 -b2cb0526e7e524ca9fe918e951c19460aca911d2b5ebf97c2bc74aeb69778a28316dec8916a4e3628b46bc51586c1bd9 -98f52ee1896b632dff5153e3d1fe389c6200b14cdda6b27e12d4a4182763b63e0f587386aed78c97a32114dc286b975b -abbea974929c9ba70551231e3833d5cecc71c60988826771f792f190ca77c80efee7607dc1d6bf01a53796d8d9b73017 -a4cfea1d06cf840bd599b14c011b6b204b2cf6f57fc7d7f310052062a4fe8870f02504e6c837c2b556c925921e543556 -b957529d7e5d1fc45c5a822a6e0e480e46af2f5cc3801c31996b9b1acacfdd8d142265148b3e1453a0df0c5e6cffc5e6 -b7411aaebb1b6a6a75568f81d052e60fa7752a64c20dd7cd5457f999f0185807987de8fb72ed94ca9d1148c19ecbe1d6 -84be67a5ca80a1fd0f43cce4c00a465f167445e42232c2d2cad5e1097a62d3ad564041a55f0c76a340387503f15e0ac4 -98803688f8e7b445c7ad14277b9f5f12acfba4f9a4ba6df9e2b7dadb726f1bee5098fd15e0b5308b6686a38864f84912 -b085eaa421e566276bcd45d8b9fb71475c4530d63e90914eb2a33c17333d5628c1ec8a45691cbae82ccad97d4addcc94 -a08ff7dc59dadb183dd0b5d336b6174464604bb2b49315e0c42f34ea08a8bca9dc9207750638bb7ebb6387257411956a -94d72607cd8a75b2fe2e9333959bb9d5b54d74ec36fb8c123c157b19a17f01f310b3311116b34bcfac305e9deabc79db -85fa61a796226ce555f8195c792ff6f3d483f62dac41c17b7e8295bd49ae6039574896548728fad4ce966be84a62a6ca -829ab1087ebb61db05c59e3c9d03e7010f8c546db117a6409bb813f6fa04061833771c8aa4c5e2981bd1ee551df0ea59 -97f5c5261db0b130bb8352fbcf65002327bd6d8a7d4fee2a9bc293173c8c54be37ae229c5488c1983bc1f7857c66188c -8756439e5978ba19e2cef95dc55f706d53a05d1fa964c64d89b0e95470b5344b2f8d44680080626c37c77a00ff0e6b00 -915d33f90980089c33f403ba4fc5c689ea7f1656f5c4e1110db987c59eb981b6a46dd9fe82c8efe7d1e3504f1d2c4d2b -ab5bbb84884ef036c9b00a84f7d5ffa2931854e2afa5a63121fe64d548531af4203495b977bfb9301bb1e4679d42665a -9830b846a9041e4539eb858a179b4db6da89b507424e6d858ca4334d973ddae255bbfb04ae25c3276ccbe97c46f5816d -8e35f4563b8a5c9a76cc1da87ab21cd894de393dd61bc977cf22d3de454de350836e032ccf7d6ea55e2e6b83c4424146 -b6338ced0f05806c625905cc51b7e772c5db3bac144e897339f67b6949f4d648d41b7d23bd3f299f4879507951ec031a -b3afa470fc71b92f415b879a814feb0702b6adfa08e395cee4f7d8b0e3537288f16c83b28ad4e2db02c1fd6d39e6afad -b4fcf7af3196bec84fe1f6e3bbebb8abadbcd46de02a37966d0ebe20972fd890803d570e4a201f2a89f479e09f19191d -a21fe1f8f57691165d0c7d8436765562cc935288f24fe765351be335f906c6c4dd1d0714b134c51255b14511c957319e -880a3a8f6b4ba410be06628a011e6bfd38d86919cf8014b4b4e1c930f8e3035749579389690f21bddc4d4699de8a4b1c -907d93a7666d847a140367c0a0ff80a96d6a8295b07cc4ee52d3be987f431d8dcb95d3717dfd248a5643c5395ec2891a -b8f38c78b8a2c487874c1a6a92d15cf0dcfd26319d4cf65c2f4fa9432203ba5ffefb02b7324022c34bfe0da369d96d65 -8bd4ebb6d720fe52d626a621670a06c8a304faefca3846df1f619f4d456e14f8bdc547fa7210b8639b89c6584ea5c5d3 -8ebdaa288a71a2d3188d6294ad0948a4f72c1eb6a2e921ec82cecda4d315a86e3e6233b5ffdc7219f34a99e9b4555317 -83320fb9dc62119655bb0055192471ae06b7641dd4af64670a4d9475155733555ad06a93ad2fae72e029049601780654 -80b3d022738318238dd32f122bd88cf2f734a61e315ece521e9e038f4a9bd7b54b5e67784f5949fbcc5fa911dd4b048a -891a23b4bf5cb8558b4540b66fb6b9fa54e9d0b2c084f660c8bc77af5ddb97cb5d8042b538f61330d9fa8ccbee6c8a41 -8e5651d9c95aee23835bb1a06eea76efc9d5c881cf87ee847ee5149fdbf3d67dcd8ad0675dec8fca6cef25368348abaa -86bf1d094bc4fc7c21b21cfc7adbc750db0b27c35bb160d306b26fefb2699cbbb1fe624df1b9e7f6f895f1b81a829361 -aebc3cb2623344315875029378c71ab7ed3cdc9d3d42d4b835b373c8420adefd177a44e532f3f06f74f0a40d53713e5a -9527f659e93a740b4c50d0d3d9aaf1a85936f04866ffde1aed30ab2fa1c1d565b46bec5fdfa510fc3ea934137bbd46df -8488673a4bc29c3ce9133cbf41c546fab4ff28c5d46048a21e710a8df4f2bd1c77d0ee242dfd962a30d646e5ebee8c01 -8cf29773c0e0fdb75bf6f52d7066e7d6e9a3ef056bbb70a98026464b32316189addb5766822f57df63bb68b78c85e1de -810c6c1aa53f9c3fd0018651b1bf25215fe24687b568f21a121e0bebee576a75e5f0d08ac9c6c21085e52228b314c6f8 -b529a87fe47402aa9ddaceac63a060a6640418891f931036c6e4098a1b308821a6f1a244fd5c1c22a6ed5f72f6bcf825 -ace9284ce89b5c81049d329db2376a85feeacdd9f735cf00038adc51865bb78bd9bd5d060efd0b727c509ec19988f99b -a2e7a949c951bddc99e68d80b3f3fc4ab960b682229fdd794f9eadc80bee91dfd5eda0052149d05c74fa33bb40d75ecb -86bac22daefca9143e0b1d25534900b1f7711ade4437642043c4a8c65f0d963cd1f0f958c7391e5a663dd3c59ed9de60 -b7d2a6e2d44edcaad19498ab3368bfb87f9ab039cf2249d6e76091dc3db0c3bf45012779c02811cc818e95796e6ad9c3 -ab474f74e1ebb3dc696e7a6bfd8845ef15fb6411fa28426c486f7b0f789a6af3016ed5f7da2a36215729f5cca0b36b4d -86616a1a9dcb50d1896f3eb937bde67f213558feb401aae9898e41cf1fe33b443170c7c2dbd1648c9e3cdd0c24289286 -a466169a2d95a5fadb6a69c7061cd2911c3eabc0b1a2488e216f8cdbd2c5bd87e80908b002b9efa51a67f02d7af2155b -8368af8b7c0f55f3c4f7036fbefc9d6a0ee9ff61197cea8ce48546753bdbc0b61eab604b8fe2c1aa91ced7a879e5899c -996c91779ff9767232ae603c5b1da5bbe0e303c4c2c72ad2d5944ee1297af3535f6bb3548fd1fe8a92cf4b281e1d83ab -ad4a93d1ceecedd27389c658b38dd71cb13c729b27e490381d8c3ed4815b11ecbc37b1f82c0656e0ebf77e5bc35196b1 -a3538c7ea3dddfbae80d67caa9fc547938bf77114559f9fc5180d9d0ab837d7fb1b27bc37405686f212f2e98b0028e59 -8abc9fe135fbd48414f2ba28344d9f49ec2d5ce94fcb314ab8dc31c754f3ab7e6ab268184a67dafe8b1fb811a762c112 -99ace100d8db88a83f1727b7b48baa1cf45b971d08112e452f5003566815ccba0ac3f8b1df6504f55a392efac8e3e70a -91ff50978ce629651f1501708908d75b490c18615e933191cd37613a83d4b605b0b48d024d27807637e662056d76276e -8e4104331ff1a40cbee9f489a814cf5bbd6fe4eaa1cbe1e13625fc3e6697b27d933265e5ef8728cfa8fc4ba5b19a614d -a442360d49bc9ce3e75eb40bf2ba05e9437fa594e8b8de34bbc822cc7b706dfa0dd10bd6bccb702d8556cd1320924821 -b6ed6cb0aa34d5793e929e0d9b9651e41da3457a0b20c1bfa93a8f65bbb65bc07c7507482d71c1c285f5f663ae60019e -86d64df2dcd36d0c7348c77480c8af33dfd889bae7bb045888eecbd317cf3e4731b96ac18f410a99ed33a3f22d448f77 -b8dd25415275d5ef8260bf5195ddb9b15b78a8799e4d15cca7d6317a18eab7bcb8fc759be61360915a28a8fcb5d6ddfe -a325a334c84dc1d9acc0a9315b399d4be93351c7049f474702ab58b4cccfd69aa50b8731ffd598ef0144ca96477c273a -9012a2dfedda5147cb9ceac681fa9e75e2901eeb3c94d87465a44d11250de4bc66d1e00ff674f2da1d800b43f686df9e -a1049d59da2a942d4d2aabfc0d972ebf3babef9c5d8fc5598ea23a048c2e58f7f17b4d860e437276bdae221d9e41e3b5 -8c9d9a8826c812943d74c4d4f0fd2f1c8087135c37bcd9647b722b59801b01775a644e38c24b43e8e70f83bccc4afa27 -b9cebd7bc7b041c18bd35b970f87e9b5183e4ace034e21117001fff8a05b2a7f9ab65cf6ab8b818b8192d1db5649312c -826710d6432ef97625db25104fc8dc3225bea594a10cdd4473d5ab72be57b74928ff356d210032a61ca590bc68509880 -a18422ceb8c61af305277628e154d3a9c49f47e230a44c6216128d73db7c3ca9eca9f87e29cb2126f1c312f423c61463 -919d357886de9eaddcfc46cd43e2b3dda3f82e926a3aedf02ebda9159faa00736bd2cd7aa044c76ae238a3a95a5bef38 -a822d5a726f5c38e9d4a750ddec80bb965a6e5374a3d87757e2e48a18421f3142c3985450d1833f3ff4ca36e3b838c89 -86bfb86eece6f6ea8f51985e312171b9bc821e0c3ab4cace556da28dd7bf89cfd5be3fbdadcacc19f2371c6a11c564d5 -91b42643b297d8eb2c1bb3f16b57ab2964de99dd22bcfa07db1d0010715ebde94d11851df575f4f1ae602644e454fe0b -a5e444ed3d5fb3c5afd2c9c24d676adbf396f5d1d47bd532edbc72c83845970582ec49ed026b3b982c9c1ea725192cfd -8448387a14d84aac6afef682a27be67e5b05d31b59346748d2940072eec771adb53339f335daf4463f555da2d8543f18 -a5034b66a26bad0f753be56dec722fc98a072bcdaeab0bb9cf35a56a573d9424cfbadbbaa8ae30690f7c6c6495331fc8 -9317ac32da1772099f41564ddd8247e3532528b240db753a1fa6fb35cc039c6a4ac4546597bb2fb28721684bdfebdb88 -8b4b0001a6234335502c8b17c4de274b83b0610960b5c46b9075c6e41f357ef0d8c94e9b14bff8be7849435512626ce7 -b1aa903511fe4219acabf8761a8e4316cc4f8955ac8640c68a7b547cfc65365a8fe0843a4098f9f17a4c9beb75624393 -8384f4953395aba4939b24b0669853df78f2fcc01b2145c08d3fc333ee2a7d4adc12f2d81c37d0cc187ef45b5f69f59d -92beb5a3c14637f84ee7a3c9b4d9b305b10af8963c087b86047e9fa959f41ff362d56eaccfe887bad1ccbedc488abe2e -8c60e16dbdfed2d1c8cf3f1bb0b0f462489293892f9d2e0221b1691321a771b163fbb599daec4cbd917da75f5f662de7 -a8a6e3041a0c2a12c76f51139b221b03ccd1afaea3b72ba2c3533b797d5f67d8b90d3474b4f6f8e19a77894fb90842e4 -966aaf74560bd4d164ee46c7d393b2c628e307019ca4289dbfb6a9a991608ad80efc1ee6e9847a19382ff8f3004aac8e -adeaec475d4bfb6075be90cc37d61d45ce14da77f8a9a508b9f829ddf2abf91683aa2fd0372d3025a660c94b0f612685 -b3392bd1ad0c202d4a95912e0e06d8c64d7e2a8818dba8f895abcd0f6932efa9a0bff8a2aac107046d3478782fe42d33 -ab38804443da16d32f11c0e364449ed351dd36b7c82b5c7ababcc33a930acefe09fdb5261da04f6dfab29421fb1cc017 -a34e0df9e953841bc44c09e16d69235a26ff390a6d128339ac97aaae5616865f86153d8d7466519dec6c52ad592dd3ad -99581db106391e6816403b1e9d13747aa05bfbfa5b46696cdfdedd1627b60e1ddb92215d138e007770512e93bc6184f7 -ae60c3b1ae3594aa4e3f08eeba3951157921aa6511148c6d32003d42157654d4a3a39efb1bb317135620f09729d134d0 -adab0bc35ca3fefb14729259b16907a34e10ddb6d78a23f28596d3d9b244709651be7719537df33bcf003c0e43bb1a66 -a31b7b2f3411f986b3415870ae42f90bb678a9fc44c942f6613cc4f90f3dbffa4b5fb8bf3abfa4361dd8e396d9a3c5ab -a69b188a8662eee48fc98201fde6f0d14f6b54db83ab79c2ec2f4b6be809773231704fae2cb281fed8b05107c63f2fda -b79e1e7a9045af6537981f54dfeed0a1335606301b73eff001880798f01ae9c0fef6e427e171afbb1d0a78135ba912cc -b1b883fbe379995b3741836a849516a0f21b18f42a34db2c8cba01f86711a2baa5d14910a110f1058e36431dec163cbf -87bc463b90123cd9e177f2284d72a7f4a1d4151659e1e4e8900bc21986f641af2f9a3386aba56601e6fb64da630b84a1 -97a51bb7d717495f943db162837d3bf700ee0653da9a94b36153443584602156e168fde97d77407d0861641d8d373094 -8b02561709564d0721b5247775dc66c6c09cf68a8ea62fd7dd361905ebcd98bdbb2c554fa272de71c6d22b04d33e6902 -a914b9406e71c09deae875bbd628af3f54de5ccf811365cf229dfc69541d996689d05679eb02d42a0adda02be6e32d2d -85dcc5f3f77f72cf0818bd04c037cef560f0b0eece3191e06fcbb54228d11f7afbb8d9f8675b404bb39ffd04a3b65bae -b15bcb96a98bc6cc7b802dc29b79a903223b1712a10a22e776f45c530a4f767665dab1a3c6d1b52157f4b79055d5ac81 -965e353e665b3734042b61951e105c1800718eb3c46759952755321ff5c639327d045c58fe90befa896e96b826910298 -96776a5cd26b69f08a68af0201b2f739cdfb9553b466271063a6c8b8307f2a3f51294ea12c7e8118c0e6b884886e1bd9 -a369453bfbe7ef0b2445231704abba25527b073bf735a968758975fad789c74110a573bc7ec50001368209a0ff385500 -8e54dc4f2a557703b2d8bdb74ff107bbb239034ed363818197b2569c03572c14cff21273e94802159563d50205edd651 -a1c66a1a82c60dcbd139b8ef4de62be423e7641a6b94ce0d0468e60bb1b000d268755946a028d3961d8b4d3722016ad1 -b14b3c26dd9d17d6fd8eeefc7f706c177ebbee9b8d05f9b01174deb37649f77f97ef1a1abc0cd4ca7a13618a4036067d -8fe8f9754c5ee102bf96ba6b6f29a14fbf83cfe3c5f81b5358ccd4db87fd8c5d88760172373bdfaba7eaac98ab1fa863 -a8c308c15242bd9c7b28e110715315a1f9818ebe03662027a6f1feac13a5dc9bb111d29444d13546d8e441e49960b0a6 -85d87035d74a1f4662f42a8c6d26782daceded0aecee9232b78139b1b50fb764e87cdc5d1ca9d6905735dd9c3dd00dbb -986c31370f594d4c8a9096c091cb1484c1c0755804819a9462ad1b67937c6b378d97f1e4c27900405b21de2646be70ca -832b4b427f3347b0073c24f54e17ac16d5a80d04261c1d464f89dce89f42750d69dc8a83ee0481e410f94cf1d108c0ab -b13e54d91d5d414223caf43a7fad36930300594b8cb3ba97c0c873cfefedc165d05f05deec8d74a0412d5f0932813088 -89c931d595849c8e54f50d550ae4a5d71c4bc74af436965bc32adbfe829a48ab15c856a69070b4a4602e0113131ce4cf -b03731793db466b74112a1b9dec3344fa952e81bfcc7fb2bef3cb20f566c3b2bf60c16a93f84f77f4c83d8f2a535a2d2 -92e8fc80d49001139363e3201c93db8326c41322db51937ab641ee7f1b2f7d03089e20eab19afd27abc23de039ab4b0f -b27d95c90dfa91886aa91c9c8c85ce09fc875279028bef49abfeaf44437a0528ade620c8c2b3d712ab594e73c5c032f5 -a42e2598731a792975feb5b24bf00b1e7cba1620922f8c2319dd5878419ce6099663b448299c0623ce400875c48e12a1 -b062840f63b555a254e3bc36e9075d57c816ed2e9cb0e262f9de0f3692456d94eef702489e5b11c9746b949b5e84c06b -886226745d906664c476615dd41deef6c338ee10380657fdb75cf9ef28b4d9f56e69c8d0ef01e9cb80eeb42f3e5773ba -854a3649dd5b22def4f246eb0d1f1a206d3dfe42b5e44b5fa963a7c5b8bdaaf7f35b542b3e9cc53187e66a2315ed9f9e -b5a48cef68a056955ef4c080c85e4044e9f8a562f2beac9fbb5e19f8d618718c86794338c6dae8f94b6f5e9f8e98404b -8f8bea7304cab80d0009b417c198bfffd166eed6f6db19f28b7616e8b0733cf0a4d54d204361d7f8f179985c8c3a16ad -8af81f10339e2f75f6b6fe22a641298bf90c8676260abeeef90bcd52f46ef013f5aa4bd9d0b5ec15be61b7c3e0f32350 -b0397c64034598c825f9ef653ff16f680325546695ee6e9c2957d3c87593161a063c5219304ce6a16b7db75f1a2c5f7f -8d2e7677ab6fbe2b0f5ab6dc356190bb3ecd7fc468c698d512a6c69f22ea97b71fa961c88635897a5b539ea51b70b4a0 -b4e91a693cca1007fdaeb7e679c6837bb8eae0bf61aae447560ca6eb5ba918cbd9952b41769657978413106b359e169d -a8331a907ba7d95a5e4090a7680d1bce3cd803db49fb84a48996e96514701de1602c4eeb4b5e0b1c2a106c4f678a72a7 -b54dd28a97a5f934a34c2817af91a41e57f88d7eb5fb584d3b6692f2d1c4b2a4e273c4de5fa33a0fd1fa02c9d7cd1fb1 -b8b780e0f6059ea27aec9f3693ac9adf0b93f75fe7fac5230deee1e7471df0bce9b5b2f260a6a0a346afa723860471b2 -980e9847ec83d61442a86cf8c7464b357694dbe67aa5de3a8c88ccd1a038256453101366dcdfe11a565065d78ce89807 -9350a17e397bdc3d2bfbb84ddc79a48bdc6ef5c3d8c1ea39251e762fddf9962b69cdd42c563d03f64615b72c9dab07bd -a34d24b69089cb5ffc5f06eb2acfeba13c96a1096d1af9620aea28753baf3d0aad0bcb30037ef3a5ac36b178816e878d -a7c8b9108fceb4e0377eed48af9846530114df986cbdd35f6d54026104fe6bfb3b58e57fa2b3a750225528f8dcb8bb9b -b0f71f6a04cc7119db96033f89530853d58a445565de2efd269b1e3956397c35a49c328102325b780fa5d0cf5adc2a4a -92be082f04722fdf3abca7ebfd162b7062939c3410ec204d5478dc8de2bae2b25e2654441d29fe2c350895512d333ab0 -95e7afbcac22dc2d04c5635d7a8c6293f6ce29bc6c932850d24ab5216b449251bdf7aaea838ef40e0e4eee1de8f63bfe -ae0a877b488865f21194470677e12ea7e357c5d63f6bc454f608e33df9a3b20e9aaea5b6aa42e8999779b8b445831c39 -98df977479667e23b897b91f2db8f4cdee7ece7fc3ecf8a07d752efae090d8bd34d781353ec1394550d8a207bffe582c -aaa0f1bfece62a63f3bc76862b8789e2593b4bb40b3c413956e9e5c4eec604e39d722cbe1db210396eca7c2293489099 -b362703d2b72909d06407d139531fc144e68ba94e55643cc3cbb9ed24145223aff460b1627b41eb9a3b709978aee5a58 -b020025128804bd642fdb1d2b70b07d181e5ba30a5ee16f6bd00d7e2d0c6af782e454cec107304823be61647e65221fd -a409894c0030081a2c7f8fba27bd0ac53997a31b35a33498d78bbcfa0b7ec0a89b9efa99dc1b8770ba889060f39d56e2 -862f9eace3f54288749ca8402c22ddd7829f0454d17ff4891727c86eace899cbf72d302065f5f581169f00186c23b4dc -91432f2a823c3ce95bdeb5854e8dc7faea5031fd65c82dc69e4adbc5ead2e5a5b58a9cd1428d3f526cf94a217f37d7de -9543a9038fdecaffecc4d3023fd67f7976dcdbc7014e82edb4573479b1789b4c610c3964643e031f69ac7a3e3dfbe241 -b4f31d580987f47c550eabd2d276678a294a612ac26806a06634b8812a571391151d84c29b6b82218cd84dac85bdcc88 -8d922ae4eecb45ebc23eb1a8404aa1524b281d0f0ceda58ea93a0cfd4184efb894c047f0a46e2d007704f5506544907e -98973979672d1d52e561cae7331b730a577c422258c22720edc344aae35ce071be1b017816d58bb29b9cf5c433fd64b4 -a46be974ea72c5e5bd16de591bf27087d97b9030fb4a74743bde5e480052a0de58bd962dbbf0e0fbb0559566c3d9780b -b2b4464973322d865207949afa4dadbd888c9b0230737561c3b76a1953a85ea9439fbb1db9d0d42083c62419db512450 -ae811a9eac5f4ee6cb3a4dab456a3e5d95cb1ab303c19e76fc4b36ef6b4c83ec0b2803ab8680ad1663bdec0ea2f19aaf -95a426f3d2ae6c6069f888010bb20c392bcbb65d0986125e0f0066d4206f4f443f70dcba8a789da042b57a36980e75be -a9ec01a5777d10275153ba7441f2e27ba3d6f1a875f204469220ad999bb8a0372369278bf5a11640ac0709771b814a31 -adf1091e24bdf10d848f1a0920eabca0a2087220fa0c3f8e5b4c72ca0424ff3e0c77ad4c259c12c3cd1c0eb0cf32c67f -b9a57eb8642729541088164b9974775934d7a4c56a3a3ff2a190d549b294fa87002810f31251170b0407c7e9695cfba2 -8625501e5c56948812b72b3495747412e03ede90096be089cb8040069e49cddfe697766ee72505bf715802fc77c08fa3 -8a745aeeddd1be100474d96aedc737208ef19a93a8ad72c10bdc0218073fde6209510048eb46e271553b04d8e6529f46 -8b8d9ac3b91ac0333094c85e81fe2b8cd5c2207073a33f66bb1939e8f1c84ef064a8b2ee984a9f450f0a6e54bb56ccc4 -8cace31444da99fa5dadc7c46f689fa427949d8c089af3d90c604fbdbe0dab052392fbad4b5aeab707e4caa9e739f366 -8750c8bd1f1abe5acfb29ecab0923008cb4455ae8a1db01bf3317df05e1e02f9df3c74e879d9c57b8f59877591939ab4 -8904a39ad86cb42c06692d4801b3718bb63a07a2dc5ef13de16f668b08968db34966457ff2e4cb770dc61a216f4abc5e -967d1750b0db53e977bb9ba65aa820d7970f8c75d5355cf12a3f4c509dee7e9b6c0f7a828474b167c25b15d74f0e9cb3 -b37297bb6c2d9175e0a7654c5bc6d248f47f7183c3b10375f07e21e9f3e66f6581caebfcf468dc0f8c04132a2a0ede55 -803862e6fbca945cb6c0ba202257df5c7e1e1fadd78b842970206575f70c9757d4a54e9b1a0a269dd37c4f830a40d2d6 -a7a27f2fc7a1e6d276522177f0ae6630dcf5205d08c19319c315bacb165b687d125832d97ed689960885bb7cf42fdf36 -87fbc08506fdf980cdd534d4ecc4dcfbd381f3937dafa09db402e07a67e1cde579e680d3f77865b5669f35fc00901530 -8fab8bd57f76d187f1cc22e40b51736b1b0234e70813ca02559ded9c7835cb3dc71a24c8f679081510c32f330d6ca45b -8fb917b7dd71e1728bbf32fcb55343890aa6fc890740f41f42e9620b5bc3ef8b1ec67d9c047e4a9de0863a5eec18e5f9 -b7429e758850bb7f69db000d49763df43d18af11460ee0f158b741dd6b7575527c5c8068cf54f7f78098f9ddb92a82db -8bd3c73c1b6f88ed2696d53d2a0617f74bfada964d2eef2afb5e1cf00bfb646f552643c55d5453cc622c9ecfb23ad492 -8e025e91b30b0f328cd6b79df9603698f1715eb6209e64ef8705cdde5ee1c4ec737a61d9b8a4e72e83b2157c621e1590 -ac0b91bbb5ce5bbc8e8d6c0d9d4e51b3960169c608b6220a352aeb13072133aa9d934b4e69d7c5c39fde68d467fa8069 -88255d08bde3b967dfb1dd338dfbdec12a2079851aa796be070a1d70204048c34f2739b7461840136b03429a8b83b1f8 -97a83477e765f3f17eef0d3243ba9bbdcc50fc581f904e92a853a076adeba917279fc0e01aeca42de1aed8af9579bca1 -b0d9f1afb807e0e6f839632393edef25731ab2141cfa1cd965e986940a4916c8788733a39def0cf67afedc516dcc6ce4 -b563e9ed9ba2134011d7bea6314af5d71f63caa1bcbf878c26d7162dfc76343c38308955215252962fd0c9c87200f1f7 -838d4e97bd67822c22cda558f0d35f971a0ab7debd3da3f15c27f7d4b3301b2c17b60cdbca0da8e067f23fc97d136ae7 -a7bccea326cccbbc4773de402fdf2cbc21a028197be98cebf6e691a7679fc948e6bc4981a14fbf493a254eedc444dd7a -8b2687732f7aebb153bd6030dfca0b6d257b8f2945eb8221ffd36ede50d463172cfc4bb17dc30bd21d8572aae2540d6f -a4a3e87ec5984c3a755cb39fb04472583a0d2c771552b0701788f03b4618c87690a13a905420358701777e8b5ff2d190 -904c4dee5dfff129de3fb8cd0a6e0576c18ed3d77f49b8f0601997013cdd4ecadb86690389555ebe8a436d8084024f2f -ad1d9c7a6236b22474fe8d45fde2e1f072101b5cb7018ac73c0541c0f9ebec4d5c4469e0570cc188cb5f5ba1d8958be1 -87fc8ca6f737cfdedee973f1586b94d971564a1fada0e4d65894222edcca6552764f1ca0b02782066f19f871ba5842d8 -851829a8b39eb6b91523548ad600bb876408cabed98d30958056367c686bdedbc876e1903b8af8ffa3d3618e3580e3db -b99270859bfe7d8a4c1a22e2d88a644dfd2f100c54070ffd9c4e1044140fc0d21d62c61214a2b81a9cfadf944327ef8e -b89a2ddc91c59dc2ed9b8d11e4838002e731b0bcc576e0e18106238cd3282264b14cebebd8a64f004521cbdc690c4182 -8be96bb11a025d265b7b3ff3151e9e227a8416e6118595ac29bf836ef751504eaa3a9cc05bbdcdeabde11f2dc3d20c3d -87185ed410be571fb532e32d0ff4ef68e98ba2d3d5fbe92180cf1fe8ddfbcc89fd1e03694a9fde1a12ab905db89323d6 -97ef023f71850ddb282f244b3f39579eab69ce5bf3fe5dd2159329b7def4982cdbdb4e71476471acfea0f7ba5a7fd061 -9944324d804fd3978e7e137e6e65348d7473ea23c591136d55779b5a31f45f9e4d866d8a18c76a3a0e8cf2ee61cdd041 -b9930c9aff260105d4d15fb749aa33436f6fb52cf9d50e39dca19d9cc7938d752773f06756af86369e1f5fd5aa71d5ea -a85ac6bc027ade2a9bbbab2b231241cbbe56e562fe621ea19208a8ea36e1baced89ec9ab8e2f83b602539e5c053f5764 -9917d40d37549caae646848e18ffcb49f5c6c4e396ebe7e74129a41b0cfe2726b4dad34d51f4bc706063e654da898824 -a25f8a4d8ab34724a732dacd2b316c80a6544d4b8c1f45115c4f55c3efae6129b83623ffb31da80e2601f70ca51ead16 -932b54b2bd26670936843a92346d231f2f3e3659542f4d4def73fb36ac0350733853130a5e5e9d8e386d34f817f5a91d -871bf29d7263bce62a02690681d4e1c3c2f9c2751de4e35810ece13c9480eab93b80a00230ef0ffb858a829ee6bd96e2 -ab9643bb1c32dc2e8c05ef49bbde9937072af214c19c3932be137b7b75268edbcdd81d1370089be44462b8032bba3c57 -b67d510c460a2f14b7cebaf9a15642a14b2542c13ebb1d1690596447ddfce6a86327ffa377c28891f6bbd8febc2c17ca -93a5ad5019a8e680bd053a524e0ffaf8cb18adfcdb22ccb6cbed67012316bcebed65294bcc0cf4f4e2915dbf19ff0948 -ac7a7fc1140b1197f2aa424b053e8ceaf48abf41819efaff87a2e63cd6e962c278942c2b97742ffbbedc5cd426a8df50 -af0115d9c2f887ff97ee15a1116ab06af1920f2f42700b75cc010d4c8038eea941c9bcc8e7cf4a41036813143ab3e8eb -90c768d880b6ac17ed7ff9bcf76cbd5c1c4879247a757d8cc8b31c4c7bb0ec763d746e6e06e361afa8ee158e36ccaffc -b3f10561432a97c95d02c1a6f317bb1ab5b98cc88cf5d56e1492ca84eb2ae1db92e9e31fa454de562e719b71442e69f0 -8d94729b5fb0afc196064991f9b3c8e04c0858199aa951f49421ab890079804179fe00707978f15637b8d16246794001 -968515d07a0f0eb52adf439d8f70ecd1f6655072abbeea45431dad26c8937f4aaeda552a22a420598d2136f576a966d9 -91f50e6f292e2bbbe226b221cedb9db36bcd459bfd74fd6356b0620766d96869266315e8503435af1719d8ff765467ea -968b328d79e183ec560e8f0de113298755cb23a893a631406defdd26ecd52e4b6f28934ad2e219382837fbb8f87f4360 -94c126a9035059d2d817c4fb16cb13fe6047c356fc495aeb369acb1c45e89306554631f50d313707e82624b6107d2fa0 -90ee85deb494043a1cb280d687e3f55345085e576484308755df1bdb6f734e7dd25fd2489cea746be5d2c6384e7986e0 -92a4f64d98e7e633271bdafb1eb88474013b5ed2c65137c243729df0d79ccdc6b210118ed3587ad00d3f0f757400e47b -af31031fcc867a53760216cc1f467901aeaa3b28438fb3ec90d6a1c8a46590062c40fac939bc3c7e7a7deff8f83c262f -94306afe09f20d5de9ea26f37f5fc8df1e29b3a6963caa94df031efd428545493d53e0d8d7af12ee525e2e21cba23324 -ab6285371b981d5443ecea699af9da916f9320b3ed0a11c15503f3b10eada3ff5dc95d24a54f5aaab97d3312de5b985b -8e9735364ae128f790dfcbedcfe0e11b991602dce0c90ab3cfd4aac74526c30a798fcb51a8ebcc5528d88c724e9c2b02 -89a3c12bcc68129b14fdc1d9b5db8d26d11c6c9467f5bff7c40abb8ec23b193746697421ea4400d5ebe53bb3fbfe59d9 -8368e44144947f9ecfa5d126f4a57bb1d3728fe3c5d3bf83310174d638a10cea02ae79fca91d5489ecc9fa679feab49c -a0474ff532e1a6a3dc8f16ae27e77d6ab72b62535ba0d3ed09da5c692c6fd34424141cd68470922e1e147fb7f7479d5e -b9ae0e47fa8d999135f78c733cdcad786b96087a340f86e4cc2bdf019b07fd4a76f9b4b041eb397f61bda20c31d27838 -a7262ca18a7179924d28161d64e6b6cec5da35b7eaf695642dbc127a7bf4a52bffad82b8d3fcd010b308dd72eb567f26 -a23ecfac8a3f978f9ca8810458973f528846de6bb92fa6422b9547d55d29d7db7d8bdc5181e9ee2257a458466f714449 -b04c32403400f82677d831314956acd3cb507520ff14d856cf8ec4fab37a4428a5d24ecfabfd2c6086e4ea6d26b005e5 -9669b2725cd5965305c6ea48331e693086f4c1c4ca7dec26bc6290e9a8e70f9f0bedca6e36985c39ea35b412abc7f4b5 -a6f68cecace45317a758658463c5fc1f005283d8c3d3de9364e7dea453007d8d4bc849a21205d61ef81019e0d25858fa -8ee19ccc1c83b2c4d7c7b712bb370c129201bfb340c5b49d991207c995f870de2d0efaa88e05bc9eac567c4c36e20175 -8a530ece1992d1de92c4e845e71a1ab24e53a8a0679aa5bdeefc60fd890ca3cee2121f66c6f4b29c437440e7644e65d0 -924338d7f356da9b8477b3aeaad6f754a8d8f6a791d70c3ff23c2a6d4488efde9b9fc351319f3ea1f545dd11cd23ab76 -8eb76f86e057cfe9f655ba29bac89cc97db07f0487c86e7b41555b5549897bd3d042cd2ede35e312cbea357df622c6c2 -a2c0da965489d15ced574f5e27cd4781a1dce8fa4f17762a25fef1320096b9eddd92a007d58a194ef57def3aaf4e925b -a3fc89753e8896d796859c9e5a00d184be7d37c4d5741ae8a60cae9a7a30c5d840325d6479701e1f61e37065fce81870 -8b2f90cdb3add567b94f4c7fc89a8a57a0f06877639c33df2697f7c39e52c1869aadc98a2f8b85a58fbb02bb1bc1a441 -aeb2c22d9186725ea40d3a4bf551482bddeef42c0ad33801e35361d3695769429449c2a13955cccab55778d3ff29b664 -80bce007abd8ebe2238d465a312c2d125d1a695184b93108d728075595c7716786f9188e90ae37fea89009d087e71b07 -86f5df2b83383c737bb6db4e435f496ebfd56b51300612c402bea9ac2f439ee7e98cbc2655d31646472ef983aa6ccbbe -880e8a19af5ad76f14cdf94396b8dacf061e02eeaba02d4c29ddf0d07c6d2a737c987d69ea2eee52f0db5a4dec318932 -8b82368968f9b5bb175c95862ad403beee68d199a20d5dd618395daf11ff0c2e1fbf3a31c23d3e582556276b44e70b99 -94a062abbdc5ba740077fb9de722ad2ccf3f6ffc8b4a9dfbb0bf2ff789bd529e7b9d8da520d0342af91808fc00431638 -890b4ee1e9837a4c215616819dadbd3c6ed7586ad391498012a54d735c6df0b72c2dc3969d1b24cf6fe822f37f9c10e7 -a7dfcf43c9c22fd22f47db490e8f0b8f42597a5b4ae3e7bc4a9b12252b32f89412a2aed946eec19b133cee89b4a70322 -acbd9e85b9d9c3b068220f893d7b6368984f6cdb1cd06a784cc9571f0c632775ef890dbd51371e8701894cbf667d04f2 -a9b1f84f053ef6f41c59b1758836a82d53932cc4b8ee9c2cafe705150e1c717e3f5c15fc21a2532c071e9dd9bccb4dac -b2c63345748a28d04680e3e451d1f7d430bc8ff2031b6bd4237a1f55dfadaec20d1854ac158cd6a1466dae525c1b9b06 -a23e7b2e5b8f3e3b0e350e1a461708be9c1434d49fe2e51473e2e360bb0be140a96f8ddac99e3b804557cc25d3e44776 -a4c4729a38f5f32f155ca4d1994b61802ee418b276486e2dcd681fec13316f3b6d4a8e76eb9f48e2df0339543b11326c -93be67dbdec2655edfe40dcdcc0a7e761b7259a9d909ebb12fd7c9a5d4efa10de065d2eb049660ed01ede2f26388d43e -932480849f97e32fb14d4a69af4073c377e949af7293951b3ca371a306d9e2096157f51c8e5036a44eb73c7c842c5aa9 -8b5e79ddafd675ff88d8f65176321a08183429d42d7fc1e7cc3cfccdef0dc5824ee40f279a05edbf4d50418a4cab2126 -962bd6fcf7c7f2a9c569d584658a735bd16440de2ffae236c68ccbf2ddc5e13836efb163690062537d52f7d8bbb24222 -af80793655c0b3ec3029673c50a7f212d297f9f80d7d1c7cb1409d292f3bd7dbb8b24581017d9f3964e3432f46e79ca1 -94c8cf3c737c102e9e91216752c82b17e4e42074e08ce44e701c2f8ac7c08902b911cabf38c4c5bd41400eeb1fc97acb -8708ea7af8c86b2a1964edf64a9e9c56c7febffa742c3ff2e3088a61d3ccd63e135811212878ba7ad8a819e1859f4e95 -ab8e726d468417c168c892c10c7e2297e50c67e4283e5b48c3f3b014981ec482e211374f779faa0c1ead906f5dd4114d -a93911e672aa3d8dd686280cf062f128bd8eefc058fbaea52cc0a9bb255fda84e65ea546f662fc75fee4c5b24bdc61fd -8aae6d9289d8adf0f81e7990cc79cb704d0a975f03b9ec02be66089d62954fd9a8b005c5ba8179cede366d25ccf40869 -91e44ca55de8ad3ab42816504813cd9ed9c6d64abf6373e8891f909cb49c8a951ee823cd1f947058d542f0bf6290a11c -a377f97e075b66e740b8476f085d50ce8ac21f206802384e2e072f6b9700a5f9cf0e6f2236307775c0e0d6ae8459d864 -953c08d9f2a9d6ccb22cab906efda69ec1c228aa5c2ab93822b6f71c007fa3bced68c6a70ac605c6145e4af770b60de0 -86d8dcf5a9ba81cf6a3149b2fff96e36639767e9de461bbd3ccc870634e8db331b98a888d7e8d3d70b6ed241d8ce54da -88db73952866ec07c49b484c6b18de70d439e67d971c1b436684d489253cb96d793cc4d9a4362b51dffce837dbd03bf6 -970b7aa9070334b0649bea1f0b4e53fded64665f87e055e3527e0e567cb57a0e97d369aa16a005155cb69000073d7695 -928c8aaf72b3f51e38c866ab457f75cbd7131b676817a3c6d522fb8f876b01a9ab3a84238eaadaa0a095ccd6c1ac060b -9561e78d16061b5361ba0be11387c3f6029415f83bcc8477b8729e88c55f4bfe74b59c1b24bec0eebd9779cdfcfbc96c -aef133788d1e04ac64f573f3ffab473209dfdcaf2c675fddcff83724d17b91d6340830409b391a94405d6ade005cd01b -b8ad4ab0a1ad6383e4cb12d479cde732f202687ebf886184507371ac277446b3bd1648c49c89343920e5d57fa6b255c3 -a8d00257e331f342b79b3d25b74d300b070326b358f690edbaad5e325293d8b55078605a43ecd9dfd27206013db4c286 -aa71abee2720052cce7a5a0c3968e64c2c540cc852dfe08b742fefe005dbfd10397f66386744c9bfbbaa40779c2ae190 -80c6680857b88afd3ae8801677720100f0fdcb9e49c82f74b8ca5a27aef34e6df03462cf9ef5f80169c72da15be567b2 -8c2f2865e132869fca5232ba5e6844ac0540a53a66971ad54ff91f186e011e5412450df9099fbe0b987be443867dfdb6 -89cf681e0506baaa528043a15ab3bae09b8817853e889f0b3de138992e52612fa3e50d54b3686cbca6428a7644f58208 -89ddf69b72b9ddf7d535f742bd3c942000061a5a54987f2ccc7a09e035be978cb32f653df9568526c5857a5df4321f59 -9908a3288b9a9972c3f3f0d5923d9840756b74f31ae0b24ef2188465efaa5247b1ed13b774991bbe4c065c7e71b487ea -9454ea9a664390fb1ba79fbb5c0cc765d8ccd32a02d946a14353290fa2a1ba911605ff2e302c340e9ed6fbe8543ee6a9 -aa4f4d9ef843ca3ba334d73af634a0ee800b3393f8f7701cd152274f4296eb79d63869d452b5e83976eca246203d6f03 -8fce1e2e59dfc4fb46f3741d27772579fbf2f48acf1a38c49b0e5dae7d35f2624af3a46a48b89bd835b7d452ab0cec80 -810ec0e58504ed556e788e23067296a8e4b4ef31257d508f05e5245bfe6d2c2f658fca8c81538c6c9ea6ed05a8f249a9 -b6667bad0a7d49cd2dc60af85e373fdaac2af0d34fdee51a9fbc1fe8b77470c162a04da38228fe68b7d5247d43026734 -8982971d57bdf35e0f34e867fecbe0c140d94101484ef4ea01b796633beba184f980c3ced28b24ff42de1dc504dbc854 -86d8d1f3edef9e61058a58d966169a05f07fed0d93bd4f4a7cfca5a872b2aad0d1a78f8ec7784828e5813c8da577469c -b491624c3d5e517c9019258db6284d7533778e44b1a0060dec5f655a7b79057141079115f5cb1d8d97a90af33cd7563e -856e1cd4f9ab7cf323f5988bb5d272857d2fa90527f800362569a39defd93e37be2a60c11f498c482654f55560356f7c -a08884d0e642c479fc8e5a9837d1babbe63f3165c02a57b19d0547fa1fdc18ee382ea82a86cfd3135dec8f2aff793f53 -b1a4de5ea703fa5ac8a70ec515bc65203a9415f6da109b67fa32843a39d7fa6232c9c13920d78c0f16e99fa5f6a27e83 -931a2ee3220ac7888157c426d1b33b8a56f8879fecf1461af4cd6c85f94e193bd6ae6f8dc3946fc689e42bee213f0027 -a844a78e65ea6f75bb55a5db1e78b88896caa1d54b624f218eeb302397dc98a084a2ff4b964acd0650667160928ceea4 -b9c214280a15b423654a36b11646c928fb42ed2a692aedc01441c67522760df29c6ae7bbcb9237938a823188ad4d83f4 -a19575f9bbdfccf970bb3754818e49c709d1bf0af015541182fc7203f7aab51cad31544072d52c0234a3b649d03d9a52 -8cd1127b7485ea7f349e2c89a4b78fab3e5fabe5a95ff0cee10a3f4fd48940e431ca5e526f6342f7da93e32e8eaa1448 -9906abc725e445092dd7dd0aef90f989e3c78aee96f3c0a67ccb62fb2a51363c71d783490fa5fdda0ff9ea69f5b9233b -8996df92e014c226e5ac724075c19d19a9204b2e086ed5e75a9bfa1f8391c4c77fd5c0b85a29f28b302a4af29d38735e -90225c9490b39d151a80a9f4d9a7f2595961c44779a54d5e195ec95096f77e30157c6c629cb1c36d995f6c3ee129ad20 -85925b1dfe3884ae3a0e993b67b6c49685deeab6cf0d9997309961b7f727cd6133797bf04d21ef7b620d1d6392450b64 -88a6c518e577a820d83f87e9d5f236f43d262756b1bae0fde72af241fcc192417ca9724428d17a3f9dd813712a772cac -8f501fd5634fddd00a8411c0e9c6947bab0dded26339821bc3543a64c519d9575c3129f6619c6079d5e95237c11cfeac -af2b42945d7c81bc422a1bcdeb80027a1a243f89c65c173294d6c92e4cb3cd650740cac17408e7ba1a34d37d865b9bc5 -abfa5e76f1112602ddf152aceaa9f588beda3aba1115d0823d6a6b074d28389fd4c8178e8a845262200b9af024a33a88 -9732a0e3efcef5ad4d43811bcaffaa1418c791d3fd6ca4489d6cbbb7c44b55156d218f0fe86f2ec96ac306fefab2e694 -8837a6c4e60839ffb0b59e94b37d81bf1ea392d44cc81717c1c9104468d31fb5fc3c35b1efd9991b5e7e9819c66a7221 -b6545fd0b455748ac3482e0ead3b0157563cea7bf6bdd5ae2af7afe1ade921e5ba80466885ba73a89657a735c92658a2 -b72fc49fd3be541bc26cb968ba4eb3078ce7c71fe0ac06340f7ac25c0befb86af03c4cf8f31c857f9e5d946401e86bb0 -929f424548e29c3b47fbbd59ec00d17b00ee1c4f6b966c1fa7e0f8528d52078278f2852da976b8931fe813b0c3b71ac9 -b37861ba981001aa6192cff06c13f041410aa60f965ea03dd48068b4295d61d2fa276c3f477f985f50189e33308c1876 -a73c7cdffd646cffb255d2519d8e08dd8d9a9eca0610211177e259230b8f8c7ec8727015853197a0f11eec8b59d4f2bc -8da1260ce51220ad107c3127e871715bd738639cd90824d1c9f5b6181304f363b8bdbdb42c21e4e360cbdee496b573a9 -aac6bbc35bce8b54820ef8d7219a4092c49aa5d4fbb187968cb91ac04bc44fa119766f8c630a727ba184cad19278d9c8 -b964de0bd31847ada13dc3f6e1bdc679f421e262c03353e39f0ef1df720ba05e6d806dba15b6e10df559519ca125fc39 -a62e4336b61f85eaa415f57e21cebc7d54c68f6febab02de76bc04a69658ab1d2f7cf0104da79448e32e2b7c92b684c8 -897c6ca595bb2884b643ce8e69078431979d7e6e1b2dcc6effaf5a62fc906db6466f85020bf5930597adbd99e2ff90d3 -932956e0ba09f6499f1ed231732a444b0adf17080237d9345d06d4262fe8a5fb0f704c919513ed42473751069c57dafe -a24b9cb4ea9c2203a95b0056bb95342c4fa0d91bcc25595fea0161e7d6f45595f7ea171e0ac1bbde13a6d8ca6ad10bf5 -a7714728bc3318f6ac005e350de94f59495ef3972b328c673c5e608fa9059be3277b48f03a5a9634c3d03397af7d089f -b98732aec7a0a9a7998ba51e2b76e5232379482d0047f4876cd39918119776ae2683590f7fe5e44d12b3b3efdd916e8a -87700c3fe20cad8fa3041976c87ee761941d323f2d64a9818f20fcdf0259f796a11e55cdee31446bd19307cbe8becf09 -a37cd03fd348694b2ea5cf081696d12dc4ae108da8d48695bf74c921b90612d18c1aa71b1071bbcc02829e05ba1363ab -830e4e7ac24fb3f64294e5c64563ab5708ebf0e133540b35b985390d68c420a6d680d779fc87245bb1f5c58e59c5ff39 -b5922242a82565753dd2c1438008462d531f820af1b565756d4d27a30e3406ecc503b1e5b628012ea0329fd75561dd7b -91068438d2bfbb0666824d3cc2be488f2eaf3a8a9f21805838f9f2d582ca6bcb103b2f0f313b57bc86f87704aad7c7d1 -a9a2133fe55e99114e526904f5fb3e2e141f31963562887a9fe6a262496dc405c756bf6dfdd6acb8853ef5a0a5146037 -8e48e79f9eb1f8757b4c4afc4e3d6da4d368bb25b4d54e3a1f34f3af13d8037b0d465b29894f68272b79cc60fa676071 -9378b90495b0e6468dce3102a97e9965a5d21fa4a6494d401888b8777bd58616b99d49177f2eb2796476ae84d20b67b7 -b0aea247d7d7c7767519b87dd66f56c306d9eec88b0db8060bb97370099892957e2c950fa2e05f24f8ad097889cab087 -89d0d48769ad81699d5b83f26ac49a29c3e835caee03469e93c11e5f4b8470eb02b52290bb2c37f06afb0746630803fb -94de42d8554583b24317d9ea283dad5849e2f124f659d0afa11414898ffdc4347a9c4ebe783dded21679337b58b67f4d -b76c3047eaecaf4a4e6fb6176c7f4a1d393fec3a360f4c711d6293a993aee39d5aea654fc6429c2e4d4955b12fea5c8e -a307fcef0915e3e3a27b94ddb9561e5d210a091714b73afbc0b3fa5e8140e8c3818f4914903975e8f78d0492d7784c25 -95079c4a5008fb6ae0d653c00ad901a108df0b8c442a68492740eacd15048106b7c4cb5ee88bc6b1dc089987935bdba1 -b65a354aa8e92d6ca2e11f4ed3c1ed011852bab8f0e5b8157a10c26db2748be688512423c11d582b3dc1da57b9d6a826 -a32c2fc62c38eb19dea24b545d2537dfe596423f8ae530e562ba7eaac34139fb443d88f18f39d65d36a65ed1277973ef -81b83b37927e9a6a7c34cfe587dc9cfbd560db3ac57a8a88161fe4ae9a7c66843d32f6f568c927e2ff8f21d8b4299475 -8b6993ef73c2021842060ec0424464412242aeb711da2c43d3985f9d15e4d936eb7a1b5098bfe892fcd3b6ba8bf42369 -965535b46a18f94a1203fafa4dee5963742511ab77e98e471e03376847850357d543dc6ef2dbb765cbc1f03f66ebbc14 -a9386ef496b4f96bd591847baf6dcf8520f7cb5aaf1713025ee894b40b10f243aef06c553376663488377fb8b1b0a022 -a6bae4486fc16ec1f12817f2d47871c8bb61f5f1a2db5f828c6e2c06bca64b1ff7cf4c059a10d6bc2f561fc3a12aa38d -a2b6cda6a75fac16f324935cc1820bfdf013ae02c209802befecac0288d90263a7f84762dfb7c9aa1351415c03288714 -aac87216619a8c50b5d54432ed5681b1cbb2c7084f33e9a91889bfbb94fd18c8071b79ebdb403ad81fea495bc1e37dcc -8bb3b3a7ceca82e4268ab52c00322d5d0822427e43c1d8b88b2f43c3dfae7100f6a29832d16454e093579cbaa1074062 -a2363b4506b1464391a194412a73d47d0cd4ea1ffa541cf8b936c97a46bfeaebd1fec409c6aa2109d277bfae0ea7f0fb -b56911be2bbf1e564715191a526c2ae73bb6e85c45e3dc22bd9dd87cde620de93875c48b11e02ea66eebb68f533f353e -81609eacf4b2e78a9d7f469e0882ad24c86ad98dd18f466d321aa32a762171cfc334dcc049962ef5e63248ef48244229 -866b26d3dbab7837edec84217c85653c6abaa617e0ba2657d67757fd1c7dfc0c7f83f6198fb85a49b402108d6fedeea6 -9771f5796d5d47d22100c7ff7d191795677d53796f4a1e1aada949b372ec12decb6c49e28f2662e729d44f0e09eac063 -a9fdfbfbe114c7f93806b988c50f8ae4e13a4d433f2e40c72b81d0ed7fe879db5e89216a0b0c8392a6d9d54f57760ecc -965336222244229fac41336464c36dac8700d5289c0aba78016db76e436289a0797af8c96d52583618f8c6dbe7b3562d -99719ac482b72d54fa515395847e9a65b733da84f7d10a0be82f34afc20159d64411aacca15041726251fd90ae06a9f4 -ab96b7ac88842ad0ab61f7550b7b4697d6a3b651cfa3c10ad404e7505c742e2c1364bbfd08ad0039ca3b81ffa9d6a6e5 -ae96088cf12f76140888582f6f6404b6f2666c048950166e37bbe46c1398fec343fcacd3e8f332f7afa222ca13fbdb87 -b5b5c1ad493b2e72ce8ba698351f596cb85841f7f7055e31325cadbb4fec3e8045b335643190d6b97c3049d10551764c -85f066c7ffd2bfc4519f42f0778ce0e46195466768322a22673a073ebb66cd77c7b8b3a14157845cdb369d3f40911421 -99f4f10397cb7ff47a2d9d2f29021d1ca96f0da01f8afd76f72457cba6e6376f925fcee28ce77475b90c9466042ac414 -85116606b18f6e5404e9176570bf6d7a9d86116e5a29721a1b20d6b28a733886e2085a7563cbff45d1f11bf3d552ea12 -a17d81b236fb138ed820d335dde2640ac3a44cccb5f11fc6bea5fe3132c4a9247b874e75fba55bdf8093f0f56310a999 -8a16a5cfe10c5dbecb4fd9f4b0c370162071f88198e016111937199b87d006d1b24f3f412d853d7c6541e1c68076b70a -8cb83fd2b1afbad7c454430fb9dbf6530230b782c7dfb01443c2c16563e833c5b230f4c4268dc37a55a681a5f0bef420 -b8851a8dd6a3a17619e7c84b18f29ac9680b456c03e8c8489376e6de9a22ea75d1730787ca5d269af44eeae47f87bc24 -a8f990c9290456e849ae4cc0c320580fcfd50263af8945d01b00baddf801aa0a7bef2ac119d4d1b4be6290615c781656 -b0fa1c28c8c67ff87427691047c362aa35de0be9b0121d83b116b23170ad2b712a0b5bdf6a57a25c59201ba165d5f0d6 -afcd2f5e66a277cef775b636abb598ee9d7e3bc1b48b521da787dc561cea8d7ad963f593c3ac6f23a66a27c15876b775 -92888863568ef01b40d51f467e8364cb1b09808238644bbee5ed118b392475e90c6a1e03a0ef826dff5ada8d10be716c -a8ddad388f2dc94294371d0ebbce02016c463a65bcf3a5366419a7a910d3d24748fb5716ddd81cbab44a2362ee3c077e -8b8ef4f818ca3de1683064ea7e968edc8d9fe2675b8bb2ae637a5784a20cd909d18eed45140189eb9f080c53c06376fd -a52d9c49db4819cf6280c220a6cd306a5851b771de3032f28c7f8750c20e80cbfda57323a55a8c03085b41f4f236b5ba -b01fbfa0f80ef574a1d6733899002a8672cc309e1014fec8e81ea1e96a7be9c247a570f825b7862e814e1f006a8227ac -b07e163eb0f96a51d74aa8a7fab5d23e44e37b1b1027ae9c4155280d8d159f0cdeecd3258c098a7358c5bf2fcf1eb7e2 -80c4512a5bb5e8255488fed7b7e297988732473f0ccc1192cab716a88d035e23cc374a937fca7da87e18048ab026d9f7 -b3e343b13c1d4c98b7706edbf362eab12b1fa87510d5cf168e510844b24c8a9624f1e7e0babf455c6d425741c23e1ca6 -83e4b53953ef683c512756b3fea37756b3c562c88a15cddd902eeecf0de82d0345fb05feeba511e8a6de91aa1f722ef7 -922512dd5ce444df62fded2c53a73385570804e7305cde401116c06dff5ec7812b776b8cccdfdafe422f1ba53b2b56f5 -8d1f7feee880abfe9f09708ccf72f376013b2910886edcceb76018759b88b95cab9c0e8f176faf042729b405a10242f5 -abb7cd087d0cea2cdbb47cdf9be2c6a0c6ec113e1ad5fac083f66a027697d477ec69f46b9aff40c239ad9959b9854e11 -b10592443daa8708f8c882da795da07465efb9829305170bc3bdd781cb6651b503d3b21eca027486d413f1748f40f068 -b14dcb895ab22335373d2b736628c1ed0e815072fd3844867ae24638aec60f8591c6885869ad0bfe509fa3fa3101a5f0 -89631708996651bba6b2113626a2fe1ef0f2ea2f21857b2a1e5544ad31e8a53e755b6d611546ebbba4b2213acde65e72 -82e9436700fcc5b842ac2f0482de4248ec9d1f206db3dd36917c00c7749bda257fedaec513d8a9ef3765057bf5aff25e -b1c2b26d93658451fb4e9cfcd77209dbfea909b2212c000fcc576ef29b808061c9f58827682cfa09e357c1722c3215b1 -8be32f59768777a785d8b257f941215f37db8912183aef4a39a856b88cc680ae7124789c58cb3c6c6f06a951dc96a1ce -8cb60a3d0c9a1efb89f89f78e6f0e4bcf5eabeae6cb215e98cd7f9eb58699ed70dabed73a8b95daf32a5e4bf0d411d3f -8ec7156d6b672e631ebd88467f40caa9ba5411ab727602f3146b468bc00ae54fe44b3228572670215a0dbd59feb66e2d -97b7162101d740aedc894bd5f74b8cfa7ca7e7fe8363b05491c15e8cd54f21b0b09eb41f756b9089c379ea0ab189c468 -8524c9de6be47cb6808df761ed03c505932ba715e757dfb3c97b6deb462433d98953ee6cbc7a576b6837e68eb16d3188 -b024c8fc3fa4f602ab73448418548d9896200065a95e8a001f6c8d4cc3f53f18ec8b85524377fd93e2d2a18eb4c48b57 -b344dc93d3057465592460b7f35dc015f4f8025fbcb44a645dcc3dfb37044d5681d8abd81bd544272dc57cd50048f29a -a7b270b94d9870f8afec3bf2ed58afb76f4ea576a2175502630d0d3f92f9152c1ab0c019f175f566eed29713dd97712d -b86dd953c40d4f5574bc7489323d71e9798f7c6f2dff8d41f6295655c5a275179ffb4bb8d2408b88226c98583a7c26b1 -b73074289a5b08aa695de03ce2f5b106107c6cf2bee8061e3195056e799b0bd8b4172deff7f413ce8e477391ee6294cd -98b801a58ac7e083da541ba058c64b00ba709d4d0ba1683e5d83dfb80a29272fc2a33a18f32351b103b227abd5123da1 -a7cf232c6ec6b9dfb32d729b9d4216688f6d2b6e68053ddfb293ebd5774218c69133baaccec7ba3da9b221af619c2ed1 -8cc1d33ffedcea05f3c593e5b63dbfebdf26d05a5719cbf642997be929336b92457fd9df0d6be6c063918ada8fa2d322 -8d273497dd9f822984f1d8dffd471cc703d03c342f022b2bb24492209a3889f010c4f7ec124f9fb9f884a1a11f84a414 -b62cd013944d8d9d72fbe54897a94e804c93eb84a24beb0880cd98fd5d48fccf5dedf5076abcb1b857adcc986b729cb1 -a1bc703a67ee709f7776b2871f2a88d8574c9e2910690c9242c162ad926ef2263d5260f5c19015ddd5ee1c8ad1a444ae -87de434e8ab5b1d067188cb9c12ed936c26ddb0ee76c4c9cee9bd1ea916e411a354bfab2ce77ed8c8ab5d8c62038f933 -ab128e9de30bad31dc2eaad851da1e39741ea61bd203b48e5671e37f7b4e3db86687574d3cea1f561bbea84f68cd17c2 -b54576c9c4bc3b43270b83b89eb75cb7e89057c99e14021ca42237dce393dc6a8614c5af5c2f69160001b2ecbb407c9f -93adf38f161ea886f41e4af8e42c69c53a51074db9ecd7b7e4e36c858426237167aa49b79737625c9f9826dfd22f39ed -a6907c8dc4073d3d4d40df8302c1637c15f9197aad8511dc95c210f6a60b06f3aab2622b826d16596af27e42f2c9d5b2 -a8b0c4a3a5d3dd5b6a85802039f48fc80350f6f0be2e55bdf75e3197a22f6547ff4a7dce38ef3667006128141364625b -8a5f4c17c729509309b2ac7e0dbadfbf0baabbcfb1fab02f91d055238faa3b66aae850ac9b8d7b7245f0a26bc5253c99 -8bfc5d594700287da2a85a78630c616af8e555cbd7864ea604ba38eb75742fabf6aca12ed99a2439e2e046d8f048a29d -b0f91b7546613341cd95ea112e04b0963fbf7795f118c393fbdc37e37dc25244d10d987c13d6fa6eff3c4721fd0a328c -a70b6fdc66ce4c2e7f1d830b7765b7f0640ceb7306cc85778488964cbcc336ac378b74b9c4ec27358f27378380b3dec1 -87387cd6b643721aac8e1a8533c27602d9632168d3a3532059163dc5e4613838bb4f07803e6852b23c58f7103d134f92 -888722a5a56f5b6b00daba53991ab6fccc32a029a7f1748f779b57732285e56e09ecdb7d4848abb3dbf3e167cf8033c7 -b7f5b9ffa8ba66f54cac387c197058eb9025cb3761550c78429db95f9e1e3b49c208ce86b6126c162a62939e1080895a -a53f38c068233b584211157c66d9d2452c811bcd340d8cfafd32b070c326169306975e558745d63e1617f4b4528a2399 -b1c3e9b0f19993f973f038bc45be6a834b1cd3d56f112c857711c8e6c30303eeb0b205bd5dfe75e46b1f4d4bbb68fabb -a81fc28620e640ccb57dedd40c79b73b0c51565dc61097527b2341bbaa3e1c9ccf20f9d8da1c16704e881b24df0b7335 -910a7f4960a0ec2aae66cbe2ac98f43646b017de84ef3d486c19b7809aa16813400bc2dccfc80e09c63422a9d4d88f56 -a463868e3a8c2d2a7c49850be2740e01c7892c83063d381f405282b4c521cb6e3317361abaa92042c38bb68695c10bb9 -991957100ea0f66cd4ebd23d9f6bc7aa62220f6ecb71ac947cbffc6f36f7891173670977bc58a6f57b9a1e8766100c2c -961dcbd2e6cb94574a33fd48b5d87e0623411574666d5d37f4ff7dc587980e2644cf056e002746088c3c3b0ee7044510 -a27cdb374cdbff217370015d78c7f5c4674ec9948339475cc80a5805979a4c6a2614b6904f943374e96bb838549ea517 -a567bd4a59f9df9f5f30a70cd9f6cea7dc0e19b7fca37fef5846aeb1697dcf7925a4735367be0828f2ded5007f711f03 -823937a900e3b8705b657d40470357d91eeb339324f0fed58695ad72dda7c64f2a6b7bb7ae4a20cd1b2016cb9edbdd1a -b07f2248802ba7dce15b2698a60a4896323d37ecae6666a71cdf85878094bbd4e9c0e4733bd8bc6e9c850e57727e1d86 -adfcdea69c5608f02630db045e5679f9f0768fbfa9c8e97bc9cf9cafe1f747d3813e7bb1adc6085cd57102afd71db133 -908153d3eb2eb2b93c15aa606531b08981bcfc8b76684c2483bf869f335f9d8773a9aa3986ee54d9392856daaf82b684 -8fbb2acf533e7d6e96e9b68e77f7a1df2ea6c652cd8862b946c93c084436d7349ef4a0c453197a9769e986322e9174b5 -b83cf4ddee6140c9df0a08a39bfda79c0d55516fd799c1c24b59397b87a33ea5a0885b2998dadc354cb6f65a4bd946a5 -957a52cb24f19106d80d4115a8a0843d047d157c4a8535775593c1dba9be24318dd434bf43a82aa7755897f895d2ed15 -ad93dbc2c055f9d7e42717391cfae64962a78bddbb9fd102a05cea520654d4a9cb6634234d3a188693c87c5b4c78959e -8dc4b8e49de9b05c33d2a98973e223c01ed5745eeaada3a4c0e474cc22430644a53a60c3d6efb1212ca298c4331763f7 -948b0172df27db83e70fbfdc896ed82696876ac4c51842d270d9ce1e7f1fcc9487d781eab97f40074861401b809dd7a0 -ace190f75cc102a79412fceebc013bda8cf329798db4b4dba658e63228ca7f141bf0849d30139ffdededf98986f3066e -8f968dd6d7e06008a1374743b965a6204c11a610ad92705e8dbe6df3c58baf36b47c5d9988e4a417c80ffd5e7725da7f -b8ba0d5b36cc41f6839543d43166a08bf512f7b56040891ab80efefc774db28c833ecd444a703c75547fa1404fa1ec22 -a29944dd0e5c861eb37c744c429a0dce596cdb2e5b0b2d2438a259a0faaf3d261faee1434bd28ebb2e6adab59ff3951d -85c70422fde0ac6e7a0574512eff2a19df8049757bf78b5a7d7870848626850f17e8b0a5661e5292f3df0f613886306e -a5ff5c3ca2c70b88d15633f9c38d2e065bcfb0e447adca33301a0d4f05b761049c8f795444f11e39357fe6bc0d7f1880 -a2167cdb114d7707f1010e0be9cad488fe56cef65941c35a5878a100adbe522a8abdf7eab7bc689b8727fafb174032c2 -ad3f526ef9ed367b2a25c95453135510472581a758760d47eb9f9b57b04f8c061152e5a792584d6ca7124dfeb7e21703 -86443033ece13fd386485115765aa95673be72b0543fac2138e1488d22419591176423213ec06e5e4549a025eb6aafd8 -887e4ccd58603e6c9cc99bd2740bb1db2fc4127e8d3ec9cf41bcfa3589b0fe1931ed2a6140ae1199d323d2870882ef6b -b701f7d7637662ea7024d31e94245a5f745c7ca889f4f7a8362537df82b0164eae83da5a107a21c0ca889926aa50de49 -ab6bc11d6049cc5945011d3973eb2dbd5a3d786b3824bc125786e734887254a6ed61fdc2a97ea34e6b37b13cd97eb781 -9901a1f44122bf5aec7cea28e9405c33567eb118752edc60f3cf6c80642370f86557cbd76478d6b0ea33be92a22c746f -b9f453650996f14629642bef8fea66c90105c8523f3875d86694100f8022d4fff2915ac9f9b9efd6f425751b113d5623 -a5bf9385a1c94c09ec326c49b6b603f2de987b2878faf0263ed109410536543095c07320f762fb6fe56ee72a082daed6 -ab003c86dd62c801cb16b727fbd1037aeacbec0f76e8abda4c6d87066cf0a33dc1c61721f2134c3b78975efe013cddb7 -8dd8c580c288168f896fd7ffbcf5c8167a55d34f17b2c362d0ada0f33a08cc0568b37b01cf0cef1fd5e2c2e250fcdf7b -acfe675aca83a774d3f526ad461f0deeebfc73a15ab3d37b224f8740ac2d9df238373e6cd1f03ca78a9daa0a796c96f0 -a45cf3242600fb9733dd5e0dda1994e8d37fc483885a34a76cc16bd245f6d9c8d15bef360ef59d0a2c3cd59114280b87 -b64097145d97cdc8b7a84edd1da7e84f8aa44c3c2a4823e6e8485fc3a44d94cde7d7ce8bfb3da5d583386461ccb42afe -a10ec5859c274c0972ec39ac80e461c29995b35d03603dc97dc30ff826ef24c5e52d5dc9296319ffc672b9e1d57d7936 -9702ee805b70a1bfac7318e8470667ee20739e3db3030bbcb9a08568e96c9c8d2af2cbeb26837c43e04997457c623486 -acb3f5a663333d1b4d54dd76a23c6601fd4540e2b050ec2a7fbf0b850b6f592837155e6bee5ca942406643f98bb2ca83 -a577b96723f64d2671f1253fca72df86ef3247006c92cedcfb26eba4b4f4ba71bfffe1d5eb87b0192378d0303177fdba -8c397ac56cb723df015d0ef202fe486d1acb42f8129d3e4b37125a7ff9e81aefb1e19f477d528be1e6b18e7bced27ba3 -a7a6e6994324a80ee0a85e8e8cf818f5f8d16d299f21b2fca8a9f65231982584afe921e76723701abea873275ce0c15f -82c8ee7a39e49528efa60ce1cbcb3017904de6beaeb751c406b64a94aa73af72932e32b63c1d3fa22619498fc46de6bf -a1d0193ac8bdd44ffcd37092a5dcf6e775824e5dee4c0aea5bd46f2e25b312fe58e1e6b9dccf9dd14f240d7ced4fe071 -82c48967f22b8aa1dc63dbda0f66ff2f40f3ca9a7b3e752e1a950dd7daadf9afd81ae1fe3d0e440259dccbc1520d4e22 -a69d43e6f962b728d223f6d474a923dd13c04eb8858f7fdd2df2c25dd4d13a0a69e71132f450613e8e2d9a65938f31f5 -a613b731fe0d23ebf376cb1f3707ab9b2d428d1ea3a95faca9988a1ff4fcbde0a077b38b5942590e594307acf88c9db8 -a7d2f249ec666f59dc51f9c31db6168f33a94b17ab95123d4b19aa00dbe9e1cdf340dc6f64bffc6dabb11912e10edbba -8e64b8f99ada5f317c6e2fd64ac17c4d6e5314c82848efe1eb97a5a52e6bf08923360dcb44c05d3fa59a82119610a898 -865d9512ec4a18ab31e4062b2ea6c43ef32c7c58d89bb0afdad9fe57dadaddd2150f78a0e85086454812855bf09f31ef -b2d23f01a0d182abcd6862ab6f4bf924ccaac399ec143fe2614908dddec102e2feb8555479bfb71ec3476cbdd71b1137 -b50d176e628e06258b518be78c6dcbc3c9b2b4a1ed4ba10ee822b3ebfeaedc4fa69c61c1985e1bb20ea9f3d6df7a27e5 -8174953f4023e31e39f1cc3bad674bf2f1605ec9fc053948bb60dbf2cabade885376f8c76f45b638c95fdb14f5bc562c -92b95a12d1fb1ec489943b3a2a1c8e3c8c6a30d0767125b87fb491f9d4f8de0629afa39fb5c8a84078b08bcc26e88c4c -93f4b80d76689d5936aff6cf195d579ff5328ccd0f04db42522a225f96b0bde2088706356675f185186548006940898e -a5f7f4577943741def19df611c2ad3d459c386a5e3c765eaa5a0cb6c192873675cccbe62845418dbe47d7a9822e4038b -b59bdb196d59928326572807b2ff2edfc93a28632542b270ed462567d32bc36cefc40300619aafe4cd1e91c38d6c9c30 -90df4b921e13ca1e63e8a5c9968ff64bbcc5b829e3421d74bf7f678aa1dccc1db9ed9dfe5aff05539bcc5379dd59e575 -837b0b6813249c456631b2f2fea9402a2303a454a114149bc35efb400813397366eabeb4477f2cfe037f722d78a5849a -ab5b33ae561312d9791bcafc8faf6d65f2c4260f126f11ab5c20c7626d88f2c00177588ec62ca763a7ca44c6ed60eb0f -b0ed2e48cf650a4267c3da1378b8164cf6b774200a5898155716f85f7abda093a60b802ce549811644e5f075d2b26067 -8d47a4e27f448773fa2d592f052bbdbdf30cbef152db6d8cbeb3d7b1a0dc0f2c820ed7572eacddcb51c19a8268426b33 -a56ccd0961bf238ccd197e5bbf430d7c637ff6e01590febab3529776403682ee32d0a776c3dbc6581f60002dac86c38a -9163bbdbf468be88a391698ab1f40a919517beb6c780062d4bab3bf8fd42eed6546a8c743e249fd61c3c347ea60ee185 -8d59f46606f063e68198457917004ae50ebb99cccb07755825782ddb25b96c3cf8973a6c5092c9db71a4b8ed075876af -8ebffeae4fef7a83d81f31a88589e05f885dd0c0b4360545b22a18369a3e6762f187ea6a173f25419e70031861936463 -96013c6b47119e017c8bf473b3d643d0bea1cc12d84d412c2b9f6f55f22543a6e15ff7e818e9799af43984ca2ec3bfb3 -af46ef7696d9908fb343a6754de37e31cbb41dc1a4ab8203d2a2483d1cb0dd3183e5015d8048ff146ec34a6c3f2eae21 -ae047ec4584a962a7ae9359292c98f4d8e0916dd98a414e2e15429ff30ffadb3e0296282f0f7e257495e8ec4bc0e5328 -a16de787896a056d31e3f174418aa3882c03c879a292246a43dafb81f8e0e05564f1cd3ecfa251cdb159f63777fc6346 -97d1c4a94182ada88aa3cac95520711802cd3889e3e057e99a72a69589fd222b241d35a54b04f42503756ec3c1a3d701 -86be4ebe8b92f5bfceba757e1e2eb649f9803c8cb10130b88b13caab6bc04dac4e26d538b7adef68413b047ab9031252 -95d4c0b08caa283ffa9e307f78db15470fca5b577189a33bcdf14c36d4ae3f571d004c5aa1e69172a4068e72b7dc25d3 -965b7053a1d14f9091de5df8bf033a07b9f8d39a6d66979ab5424bbfa32b803075afc2d74e71235a0f881bacb6704689 -a93e72836e2efc704f87065dac0463ddd4b063eab125d834df583d8833873f575a0179781b72aeb2a35533a34a395481 -a2997d7c377060d910654550316ea7374a0329fcf30e743d613e2ebaa15b1bc6c936c2529f5466ef0e60ff53aa2b709f -af5259d4d08617d9be068d1b79a8209497972910938831a435487395512187691d0cb021bd57eff0f694f32efc1487ab -a78b8318838b1049f308200782c4409fc6c97ca5bb6af28996eb191027c8935b7a43a41961ec046e6c8539376c1aa293 -a4a6a9ec652d1c95883d21d3767b13a7e1dee73be907dacad197cfee025755db3cc7a8fb9f40146912f8a3f4c2c49c14 -a8a8ab62334a3c67793fa0691a0d2e80ac1681ce64a02df93b78e4a2f6fbf3af9b160d9ca6b4e835d58ed60d8ce627d1 -980c32e492464a6f36ce12ed06541e3b2eb098934c0ebccdcc984cdbfee4a506d15afe1a30a84d642322c2987d9d51a6 -8ea8c1adfd73747db98705e9fe1aec441484d2e4862b84817cdf1262fcce91f56cd26073d4dd23b04f836e0962428593 -b0f20edb8552d2b08613cb574e9de1c4dce1eae55ba9ab05dd7f2ca3590a7496d63d55af88b3dff881e16d8bf9147037 -915af4e9a28b12ea126668db7de6ff0c2cc9935b138022fadbb1f385f327fdc927388c945b93d252cb51803c242f7e1f -a553e08f67c61ecc5c8955f7251cfe18cde02e6170845e70db1761bc00f42a31cc10de26d4c904200166311f32a3e56a -99f4b066a805512e16addb0bcb08d76f017213ca6aa6afb5c2fc621805c4e123bbe0aa85eb5a0f89d3112635905093e0 -9236c5b0f4d2e58033735d7bd5d53ccbe82c05aa290149286a16a318043ffedfdca9d2d07817601d4216fed50c1082f0 -90a4c7898c58c9af83f94095f6afd5ca65664f16c0af4c8121407cf0864fdeb09958500b2bd0b78950aa9051e3480928 -a589666688e6e7f8e4d99b84d21a1f9ebfe681fad346a237de20a11a2b210eb99c4d3e2f645b23a85c93bcccd51f63f8 -a010849ed4df0e3a8eb61f7fd114d05a8669bfa36cb95d089bb1964ea8f5fa26be0cd10fcd9b38b259722c5a14ba3a1f -b21f974a10a2dfe9987370ef4b6af294cbe8f4bbe35ce9400d0538c5f71287498054d73606e26f93e2f19584aa18e285 -81fea77bad05c3bfa8d5d8409b189fd5c759613cd69ddb19b2d46673d4df944b2c7293989f79580d229d20959c74b18f -ac962b0819a03d2a2fa42c492f54c3d293c6d5ead403c50f7a1ccc2faad58beeb0dfe888a928e505fea9e09807e13a23 -b78b913f2ad9622d20c175ed23f80f235b5336343b0353f82383fa6aab99aef77cb489df822bb168e56496c1854f623d -8c06abf72913ffcb6b59bb8201c00034b447011880733aa6b563acc423e90bdae19f2a7a286943b55488fc863d09269c -b34168972fcd90c78286bfc6078ce559e3c216d8d1885ecd5044bf9f23a4ad15bfc9830aabb4273472c43e2980048586 -88350e0ffe9b5576dd0afabc6d8445d25b2b9a0945c71e6b9a5587649ac5d95cbd722db5ea1e65d3fb8230c794fda5fc -a3bec1fc362a33f38795158f1b869e9ee857a7f2e1acb92c6a7dcfffa64443a5b7f6dffb656452e7f855051ae849be3e -a21f64c49334720883e1243a27575648f53637a644c308ff24f5c26bfe65cc690a5e46b8e432171f31c4229aff4db416 -85dcd8ebef8f7f44372912b4a3a0dfe66a56f16c3757a8ec01b71aa81eeda9f8e5082f92e3ae8cbf3c1eddf5e6ffed03 -af3c1a770f34f2acc504f38ffa7a18cc4b38f8f84f310cdf2d7346b18824ebc7c7663cc0e00b44cfb5494fe6081aff84 -a5dc7c5989fb5cea87c2d878d8436d858458171b667ab5200dc2cafd8af2d9c2bfe2515b0c002cdc9c3e61e4cfe4b444 -b136dcd4577ef3a3a8bc946cf2ec79d3fab301114ee2a692a6c219e252c9128db63fedebc6bd6695a8ae58e7d28501e8 -91d3a1ba625632d59dc963ed54c0310d0447df3e1d9151299722d10f8b26161bb73e0020d408b748fa6fd1db51adabd3 -b89f1a2497b04b3f1b018dc88b52133e1d7470f97f846965fbc934d34dbc8d38f2d8b07d218e62c609de33b61831cc9c -92fec43fc5af23fda5dfab78234f5ea7813d8de34f8ec269c5fa35dd916b9143ff0033d35e7a284c0ef4f41047e98fe4 -8a0b89cd35ecf5b6db26c39705b416a4b950aafaf3b00a9d75f864955e9074aac03826ff9393456871107563eacc024a -b04db63ebce71161fd42bb878e89155bc9e887329e164481077c6a1db092477370a362810d291444f5463437e0ec5906 -88ecd5275592f8b133928770e2273a0e0c23424d72b9e505130b0599ba28d1c11eceb2318a49dee054a8ba0971874357 -8eb0271197fb9f1eeedaadd8eb603b8753ada11abf04ce90950034f51f756ed6ec6a6182a47e1f3ae51e3a1f3ecdf467 -81cc996bc6b12ac56a1ae3add4483ae4f2e2284e9d304f5fa1723231d0e5b196813b6dbbc20b70f5d51fcbb65bf284bd -8e1d94ecca2928c4c68fbc13199b6281f8782c75c119b763e0eb122f81c35f8fd079d1bd76b498393371a08dac95dd1d -a92f98bc09f8a91fd165bb8d05e3b5ec50121d760b353d7e4ea23c0e04ff29614ad9028a4a16bdfe323f2af647e515ce -82e8dc99a14da065200699e458150dc6d49ec0e098bbd91ab8f1fc1767e8732f53855499c8f24da7b9dd681100633be0 -a67b6cb4eeab4fe5f4ebdf5649b7d61bf5fbf7b6cd2d357fdf348ba32dbfa9d6830b1265ea76a1c666b266e30d119182 -a64e3af1d0e600bde18d7f53a4e8d89d296eab4bcd9cc3a9f476c5b8425e6e8082066948fbf40689f626e27e4830edfd -8f66b59782cbccdb31cb1bb2d6385307633ba4db31c375c0a8424a497b2fdf309e7ec1c95490324b9a909bb43041998d -b93f4817eb1d91ac78eb650c110f7c29df40df47ed1d5d3209c3abe5cf59a5e7aee3d1cd232bcce77e157b1a9daa2557 -864b6cd72029640fc041fd3efa71bb210edb40589a26981724b944192c3c2543352b4b757836a7b0b13bf830f22b8374 -9064a0ac94f2f133e287b796363f6d27e9646a8b531cd9ac0eb45b99fa73f327238161a43f7c4fc914036d69abd1473f -a40e60d4aaf9f50f7bfebd0e714fcfeba64e0f7ccaa0f4829144a7efeaf15a7cda2d62d771a76f98a45cda9196b0522b +8d0c6eeadd3f8529d67246f77404a4ac2d9d7fd7d50cf103d3e6abb9003e5e36d8f322663ebced6707a7f46d97b7566d +a0d2392f030681c61c2a867862917e10f7678d882034bb89af3db87e6ab3883a304034643dc9688a04e41a5b831582bc +94298073048d70c74f36685e547d04b7311479daa05912e18ead64b2099a194bf48ec344273d58daf0b86b1d8f1d318d +85c4063d13499013dc2ccaa98c1606763e6b1e8cca20922d4cec12ecbaf006ea81ffabe6596d1ac7ba1daf7e63e30898 +84c64bce36c6b5145c6880113366025ab9a8f88e3948d374e27be8b8f9f87402c70fec9b3c621a2d1d26764a84370d0c +8b206c823acf5294552ee54579fac0f45ea15bd273dbacd63b88cd7cddbcce23b56e52f8ea352e1e1d7dcd9b3991b413 +b70aaa4038ba3f5ff306c647b4392d004950c53ad8f6713b5c9c21ac99f5c56cf57323dac500a1f4e9507c4746b07a2f +895f6d1fc70b52f838d81b24f4840729cd5988b649e9d6e6f6dbac4281d8818f39ebdae7e6ea139d7f98a832bd6f29f1 +a71a2832bbaade974c9ef7505dfa24e1ba466a9951b7c2db56886be31c9c7b871f3ee76cb1fcc1aab4b906d6502bc9b5 +9530ba64a21e27834609c00616bc63e8fc2dc7800e478ad728ec39c624f65bbc62cb48f59decb7fbf605ce1920d02622 +8d0609affaf8619bb2f6c80699e5bc7783becbd5973630cdd227ae52d6d701c45f4270becca97701b40279fab588cf64 +8f5d5b4c3bb8dc9a19e5a0f84df6322a79a00c7783c86254197d313a5b35d3965a1f7c0b9c4e39ec1e8f5d02d3aa0862 +96aa47a3ba20b1cfe81eb26bef503225037fdf4c9df53bea1b520841875cd1db6aa8e0f34685da08b55a3ce7289e6de0 +b4c27ee3f4b8c0031837160f0a75632f5b51b5850d52b530096443f54c2b264aeccc5c61b4fcc8de7074475f354fa0d8 +acfd735cda20be1d6f425a7886629c91732fbb5a4e0350ca740a8fb5b39f2001071cec0b2a0f6ca35e1f35a5ea18d00f +ae44d87b1d16d59504c602cbacde2c2791f1520391ca50154e6036d3953ca466cf93d6537da2adb729e6f9f4ffa87853 +97b492872ce44941ea4668ffca83b82fac0f4021bd47e0a5ffeaaacb1b3fc924ee4d53b99f7bcafe0985caf0fbe5d1d3 +b3fbe2f9103d293f49c6c6016d5913f041c9113295397388111a0fdf4245d8edd6e63b9a1a1c9c8f868d6e1988116880 +805efa08fd2046c44c427b225c17bed8a1eb3320cdf94026fdc24c6d345a6cfebfd7475f85d2d1bf22018ca72d2761d3 +9888bae0d83077d1dfde82fdffb1195565c31c519b80cba1e21aba58ee9ccb5677f74bfde13fa5723026514a7d839661 +922e19d2646ba90c9f56278bddf74621cc4518ae2f042fb8245843e87cd82724c6d7c9a99907ac6de5f2187fd2e77cbe +a38f0e1faf97dd1e0804b44e4d150dbfa48318442d1c5255eb0c14ea56b50502f3c7cb216a0336e7c140398088dc01cf +93598ea391c8735799a1d4cd0456f34994ccdf4883fad57419f634f30fee595938bc66b066dade9ae52578818c00d899 +a528dc920734cfaee9feacbc0baa5b73befb1ec6fbd422fcad09a9c1f8f8c40b5ea332b2cf04dc1d6d921e9da9ddfeb4 +b38d45316bf78d11e796a34ee535814e6cde0e642f14108329c5b21f4fec18cd61f84a3025824bb8dc4cbd26b2ecc9bf +8eec35a7404c9a35dc6ad0260b7f0f7fd1bfe92a2e08bc72548b99ed9acdc378728a8ea9c6879a6e47e37edb0d28c193 +a68a4446274ccd947c61bf736c5219dad680b99c6085a26719793e0d9dab26d5f8a0b28e71be6e1b9ea4ae39139f7f57 +a0acb543f41ad12e3b2e096629ccdd719a001d0ff53bb151e9a37aa57852f7275a7bbd06dc2a06af9144524548164af5 +b271e74cdbcf8b9143f8472174bdb068c23308ea807c60a554c185f7be6f231aac13347139837514171a876dfac5baa5 +8195a460719000cd1df379ebbf7918f71301a50a2fa587505cc5b8c4534c3d2343f63d28e7ee991d7a1cebb15d380696 +96202b60426773e8731dcbedbf613477f65940a19fb4be0f4f742b0c76ae9d88ecdb6d36cd4f12bb404dd5d360c819e2 +b0a80fe60b71ca9e80157138de8787b8a786326179604b8a15a744e52662645987e5f859ef5c76492d560daf4624b9a7 +a331ea8adf87daa5e2d458d0113c307edae1a84927bca7d484aca5f8c1b6378ab42981c44b0d916d7249f4b475f926f1 +aa1a8f59ae0912abf191ea7e209ff401628278dfb2269db6d87cf33bd52af3dbffbe96513a8b210e965c853a554b787a +ac4f4a0e1b1a155e1f22a9085b0b047fe54c8437dbbb8e9720fd6b0cdd76557d19ca2e885a48890f0247b1a72be0e287 +a428465505eac7b9660eb0d495a7a00c8cc238de3a02ebbd2eb07e502e9868086e9584b59953cf1480c0b781295db339 +b7b77e21e08f6357cbd3dcd3035c3e8ec84cdfa13c7baef6c67e0ef43095e61fd549694263d7def8b8adc3a0fdcc7987 +abb991d17c5bdd264c592c55101e265cb3210c4157aee4079173fd51da1e0199eed1d6c890aab95817ec078561d771af +846a8e4f801faf5fbec078b09c362ee30a00b2b58a4871744d03cd118b913464233ff926e52b0c75fbfcf098ad25a1e6 +947e91ffa32f38c1ccb72cca4bfabaee9e63ab74a16f034cabba25e462f7331ebe5a7ba393f69e91830415fa75b1b52e +8dc5e26adc693f4e300cab7385edca1a2fe14c8ee6dc0cd6d013cb5aa154dc380e9e81e259cbc59c1f38f7c4a57f1c7d +9818ef6605d6ea3b7bf4da5c6d6d8ed540bb94df4d14c974e1b79ed2fd1a0b897b8cf1ff671a181a697effd66b1644a5 +b5eab6baf03af994fc32cc9dce388394c18c01cdafe7909fde948f3e00a72dc8f30d15977d0f114bd7c140f5f94cf005 +83b2e9858d3b929f9a2ad66a91a2c0c44d15d288c17c12a1614301a6f2d61d31eaa540ca7781520fe4420afae0ec0208 +ab338fbd38bce4d1b7a759f71e5e5673746c52846eff3d0b6825e390aeeca8f9f123ee88c78fe4d520cc415cbae32bf1 +81adb6322b8db95d1711304e5b59f37640ca88c03e6c7e15de932be5267dff7351fa17664113ecc528e8920f5bfdc0d1 +89e2e0c0d769e4107232df741678a6bacb041d0154385450aaca8be9c3c18c42f817373962e7569d33935c35666a8a6a +8f0756fea8b34a2b471ec39e4448a6a6935e5432ec2859d222964a4c82777a340e1d702777aeb946fa405afc0438221a +a2bf90c505a6f03b3dd09d04e1e7cf301fe3415b273e263f15fdfe5d0e40f619b95e8bf00916d3eaa7d7f8c0bae41c8e +91d5c76b5542637588cd47279d0bd74a25dbda0d8ec0ff68b62d7e01e34a63fc3e06d116ee75c803864b1cf330f6c360 +a9958c388d25315a979566174b0622446335cb559aff1992bd71910c47497536019c6854d31c0e22df07505963fc44ff +91d82b09d5726077eed6c19bcb398abe79d87ce16c413df6bf5932b8fd64b4c0fd19c9bf0fa8db657a4a4d4c0d8f5a2d +ac6e0a86e0ee416855c3e9eef2526c43835f5245527ed0038bc83b4fcadb4ea5beb91143cc674486681a9f0e63f856b1 +aaf00d6efd0c6efb9f7d6a42555abec05c5af8f324e2e579fc2ac83bdc937cc682d9bc2ffd250619c8bb098b8c84db80 +963f5fcd8476d0dbeb03a62cde40e3deee25f55e7ded7572d8884975f38eddc5406fc4b0adff602a1cca90f7205a7fdc +a3805ee01512f644d2679511bd8607890ee9721e75ac9a85ab9fd6fceb1308d5b9b0e9907686b4e683b34aed0f34cd81 +a483d7708465cd4e33b4407fe82c84ef6bc7fa21475d961fe2e99802d0c999b6474ef7a46dd615b219c9c7e9faec45ee +b6b5f9456f12d6781c41f17cdc9d259f9515994d5dee49bb701a33fa2e8dcbb2c8c13f822b51ad232fc5e05bff2f68ef +8766b721b0cf9b1a42614c7d29aad2d89da4996dc9e2a3baeba4b33ca74100ab0b83f55c546c963e3b6af1dcf9ca067c +ac5e8da1154cf4be8df2bbd2e212b7f8077099b2010c99e739441198f65337c6f7ef0d9136453a7668fde6e1389c32c7 +a9d6d2c8845e5f1fec183c5153f1f6e23421e28ce0c86b0ce993b30b87869065acad9e6d9927d9f03c590852821b2f9c +a320ca07c44f7ea3ff858fe18395a86f59559617f13ec96d1e8b4a3f01d9c066a45c8d8cf8f1f14a360bb774d55f5f18 +b3adb00e1312dce73b74fbd2ea16f0fb0085bd0db10772e9c260e9ed9f8829ff690e3dfffacaddc8233d484bb69778b3 +87b0c8d8a167d5199d0b0743c20fb83ec8a1c442f0204bcc53bf292ba382bef58a58a6d1e2467920e32c290fdc6dae7c +a74fa436a5adc280a68e0c56b28ac33647bdfc8c5326f4c99db6dbd1b98d91afb1f41f5fffd6bcc31c1f8789c148e2db +8a37349e4ba7558965077f7f9d839c61b7dcb857fcc7965c76a64a75e377bfea8cd09b7a269ce602cc4472affc483b69 +8af813f62c5962ff96bf73e33f47fd5a8e3e55651d429e77d2ce64a63c535ecc5cfc749bb120c489b7ea1d9b2a5d233c +833021445b7d9817caa33d6853fa25efc38e9d62494d209627d26799432ea7b87a96de4694967151abc1252dd2d04dfc +8f78a715107e0ace3a41bff0385fd75c13bf1250f9e5ddecf39e81bacc1244b978e3464892f7fb2596957855b8bf9fc7 +aed144134dc1cc6c671f70ebe71a3aadf7511eea382969bc5d499a678d2d8ce249ebf1a06b51183f61413eba0517012b +b39a53e82c5553943a5e45bc5116d8672ec44bed96b3541dead40344b287a7b02dbf7107372effb067edd946f47de500 +b383844c3b20a8bc06098046ec6b406df9419ad86fac4a000905c01325426903a5e369af856d71ccd52fea362ed29db5 +83815a7098283723eec6aa6451b5d99578bf28a02971375a1fe90c15a20963e129372ac4af7b306ee2e7316472c5d66d +b426b4e185806a31febd745fa8d26b6397832a04e33c9a7eb460cbf302b4c134a8a01d4e5e40bc9b73296c539e60b3ca +a6cabf8205711457e6363ef4379ebc1226001e1aaea3002b25bfd9e173f4368002f4461e79eeb9f4aa46f1b56c739ab9 +a6e88ab01282313269cd2d8c0df1a79dada5b565d6623900af9e7e15351de2b0105cc55d3e9080e1e41efe48be32a622 +b2b106db3d56d189ea57afa133ae4941b4eb1dc168357af488e46811c687713fc66bbd6f8500bbd13cdb45cb82c14d1d +b3a74780ff949d19e6438db280e53632c60dc544f41320d40297fe5bb7fcee7e7931111053c30fb1ed9019ab28965b44 +8c67f32b9fdc04ec291cc0d928841ab09b08e87356e43fbbf7ac3ff0f955642628f661b6f0c8e2192a887489fddf07bb +b3be58bd628383352e6473fe9a1a27cf17242df0b1273f5867e9119e908969b9e9e7e294a83b9ea14825003cb652d80c +a867acf6ab03e50936c19a21d4040bfd97eb5a89852bd9967da0e326d67ce839937cab4e910d1149ecef9d5f1b2d8f08 +8006b19126bd49cbb40d73a99a37c2e02d6d37065bbe0cfcee888280176184964bd8f222f85960667c5b36dfaee0ee35 +ac50967b8b7840bf9d51216d68a274f1d3431c7d4031fbac75a754befbbb707c2bb184867db6b9d957f3ba0fd0a26231 +b5a794c928aff0c4271674eb0a02143ed9b4d3bc950584c7cd97b7d3c3f2e323798fd5ccc6fcc0eb2e417d87f4c542a2 +a2ca3d6509f04b37091ce6697672ee6495b42d986d75bd2d2058faa100d09fd0a145350f2d280d2cb36516171bd97dbf +92cfa293469967a9207b37cd70392312faf81b52963bfbad5f9f3da00817d26e10faf469e0e720c3bb195f23dda8c696 +a0dd5135da0a0e33fa922c623263b29518d7fa000e5beefc66faa4d6201516d058f155475c4806917a3259db4377c38a +8fc3ae8ea6231aa9afb245a0af437e88ebca2c9ab76850c731981afba90d5add0ea254053449355eccf39df55bd912ed +9727afe1f0804297717cec9dc96d2d27024a6ae6d352fee5d25377ee858ee801593df6124b79cb62ddc9235ec1ade4ac +8bcb2c53fcaa38e8e2e0fd0929bc4d9ddce73c0282c8675676950ff806cb9f56ebd398b269f9a8c2a6265b15faf25fca +a8bd9007fbbdd4b8c049d0eb7d3649bd6a3e5097372fa8ea4b8821ba955c9ef3f39ac8b19f39d3af98640c74b9595005 +92c7e851c8bd6b09dfcbfdb644725c4f65e1c3dbd111df9d85d14a0bb2d7b657eb0c7db796b42bf447b3912ef1d3b8c3 +98c499b494d5b2b8bea97d00ac3a6d826ab3045bb35424575c87117fc2a1958f3829813e266630749caf0fa6eeb76819 +8df190d71e432fe8691d843f6eb563445805c372eb5b6b064ec4e939be3e07526b5b7f5a289ede44ae6116a91357b8b1 +b5010243f7c760fb52a935f6d8ed8fc12c0c2f57db3de8bb01fdeedf7e1c87b08f3dd3c649b65751f9fd27afa6be34c7 +889c8057402cc18649f5f943aed38d6ef609b66c583f75584f3b876c1f50c5dc7d738dc7642135742e1f13fa87be46c1 +996087337f69a19a4ebe8e764acf7af8170a7ad733cd201b0e4efde6ea11039a1853e115ad11387e0fb30ab655a666d8 +902732c429e767ab895f47b2e72f7facad5ef05a72c36a5f9762c2194eb559f22845bbb87c1acc985306ecb4b4fbbf79 +8519b62a150ea805cdfc05788b8d4e797d8396a7306b41777c438c2e8b5c38839cfec5e7dc5d546b42b7b76e062982a7 +862a53ba169e6842a72763f9082ff48fbfbb63129d5a26513917c2bca9ad6362c624ce6fc973cf464f2eb4892131eb04 +b86cd67c809d75fdb9f1c9453a39870f448b138f2b4058d07a707b88bb37f29d42e33ce444f4fbe50d6be13339cae8a6 +8cf5d8365dbbafc0af192feb4fc00c181e2c3babc5d253268ef5564934555fb1e9b1d85ec46f0ca4709b7d5b27169b89 +b48f11a1809ec780bf6181fae3b8d14f8d4dc7d1721128854354be691c7fc7695d60624f84016c1cea29a02aaf28bfbc +8b46b695a08cb9a2f29ab9dd79ab8a39ec7f0086995b8685568e007cd73aa2cd650d4fae6c3fb109c35612f751ba225e +8d2f9f0a5a7de894d6c50baceb8d75c96082df1dcf893ac95f420a93acbbf910204903d2eb6012b1b0495f08aaf9992f +b334db00a770394a84ec55c1bd5440b7d9f2521029030ef3411b0c2e0a34c75c827fd629c561ea76bd21cd6cf47027f4 +96e9ff76c42bcb36f2fb7819e9123420ed5608132f7c791f95cb657a61b13041e9ba2b36f798a0fdb484878cbe015905 +99f8d701e889abd7815d43ba99e0a85776ec48311fa7cb719d049f73b5d530fa950746ffbbb7beb9e30c39d864891dc2 +98169c20df7c15d7543991f9c68e40ac66607cbd43fc6195416e40009917039357e932d6e807f3a40bc4503ad01ae80a +84bd97dd9e4e2ba75d0dee7d4418c720d4746203d847ce2bdd6ed17d492023df48d7b1de27e3f5cb8660c4bb9519ae1b +a54319e06db7f5f826277a54734a875c5b3fd2fa09d36d8b73594137aa62774b7356560157bc9e3fdf1046dc57b6006a +90cfff7cd4e7c73b84f63455d31b0d428cb5eee53e378028591478511985bcc95eb94f79ad28af5b3bed864e422d7b06 +a11c23cc8dce26ac35aea9abe911905a32616a259fa7da3a20f42dc853ad31b2634007aa110c360d3771ff19851f4fb4 +9856fbee9095074ad0568498ff45f13fe81e84ea5edaf04127d9ee7e35e730c6d23fa7f8f49d092cf06b222f94ab7f36 +818862dec89f0dc314629fffbca9b96f24dfde2d835fa8bde21b30dc99fe46d837d8f745e41b39b8cf26bfe7f338f582 +831819d41524c50d19f7720bf48f65346b42fb7955ee6ecc192f7e9fed2e7010abccdfdeac2b0c7c599bc83ac70be371 +b367e588eb96aa8a908d8cc354706fee97e092d1bc7a836dbcc97c6ed4de349643a783fb4ddf0dec85a32060318efa85 +b7aaef729befd4ab2be5ec957d7d1dbe6178de1d05c2b230d8c4b0574a3363e2d51bc54ea0279a49cc7adffa15a5a43a +ae2891d848822794ecb641e12e30701f571431821d281ceecbccaaa69b8cd8242495dc5dbf38f7d8ed98f6c6919038aa +872cf2f230d3fffce17bf6f70739084876dc13596415644d151e477ce04170d6ab5a40773557eeb3600c1ad953a0bfce +b853d0a14cef7893ba1efb8f4c0fdb61342d30fa66f8e3d2ca5208826ce1db5c8a99aa5b64c97e9d90857d53beb93d67 +910b434536cec39a2c47ca396e279afdbc997a1c0192a7d8be2ba24126b4d762b4525a94cea593a7c1f707ba39f17c0c +b6511e9dea1fbccedd7b8bb0a790a71db3999bd4e3db91be2f1e25062fae9bb4e94e50d8ec0dcc67b7a0abce985200b2 +936885c90ebe5a231d9c2eb0dfd8d08a55ecaa8e0db31c28b7416869b3cc0371448168cbec968d4d26d1cb5a16ebe541 +b71c2ac873b27fe3da67036ca546d31ca7f7a3dc13070f1530fce566e7a707daeb22b80423d505f1835fe557173754f8 +85acb64140915c940b078478b7d4dadd4d8504cde595e64f60bd6c21e426b4e422608df1ed2dd94709c190e8592c22d7 +b5831c7d7c413278070a4ef1653cec9c4c029ee27a209a6ea0ad09b299309dea70a7aef4ff9c6bdeda87dcda8fa0c318 +aa0e56e3205751b4b8f8fa2b6d68b25121f2b2468df9f1bd4ef55f236b031805a7d9fd6f3bba876c69cdba8c5ea5e05f +b021f5ae4ed50f9b53f66dd326e3f49a96f4314fc7986ace23c1f4be9955ec61d8f7c74961b5fdeabcd0b9bccbf92ce8 +88df439f485c297469e04a1d407e738e4e6ac09a7a0e14e2df66681e562fdb637a996df4b9df4e185faab8914a5cef76 +8e7ae06baa69cb23ca3575205920cb74ac3cda9eb316f4eef7b46e2bff549175a751226d5b5c65fe631a35c3f8e34d61 +99b26ff174418d1efc07dfbed70be8e0cb86ac0cec84e7524677161f519977d9ca3e2bbe76face8fe9016f994dafc0ff +a5f17fe28992be57abd2d2dcaa6f7c085522795bfdf87ba9d762a0070ad4630a42aa1e809801bc9f2a5daf46a03e0c22 +8d673c7934d0e072b9d844994f30c384e55cec8d37ce88d3ad21f8bb1c90ecc770a0eaf2945851e5dab697c3fc2814a9 +a003ed4eb401cfe08d56405442ca572f29728cfff8f682ef4d0e56dd06557750f6a9f28a20c033bc6bbb792cc76cc1a8 +8010408f845cf1185b381fed0e03c53b33b86ea4912426819d431477bd61c534df25b6d3cf40042583543093e5f4bb44 +9021a1ae2eb501134e0f51093c9f9ac7d276d10b14471b14f4a9e386256e8c155bef59973a3d81c38bdab683cd5c10e0 +a5abf269ceabbb1cf0b75d5b9c720a3d230d38f284ed787b6a05145d697a01909662a5b095269996e6fa021849d0f41f +b4b260af0a005220deb2266518d11dbc36d17e59fc7b4780ab20a813f2412ebd568b1f8adc45bf045fcbe0e60c65fd24 +b8c4cb93bedbb75d058269dfccda44ae92fe37b3ab2ef3d95c4a907e1fadf77c3db0fa5869c19843e14b122e01e5c1f4 +ac818f7cdecc7b495779d8d0ff487f23ab36a61d0cf073e11000349747537b5b77044203585a55214bb34f67ef76f2d2 +86215799c25356904611e71271327ca4882f19a889938839c80a30d319ddbe6c0f1dfa9d5523813a096048c4aef338cd +a9204889b9388bf713ca59ea35d288cd692285a34e4aa47f3751453589eb3b03a9cc49a40d82ec2c913c736752d8674d +893aecf973c862c71602ffb9f5ac7bf9c256db36e909c95fe093d871aab2499e7a248f924f72dea604de14abfc00e21c +b8882ee51cfe4acba958fa6f19102aa5471b1fbaf3c00292e474e3e2ec0d5b79af3748b7eea7489b17920ce29efc4139 +8350813d2ec66ef35f1efa6c129e2ebaedc082c5160507bcf04018e170fc0731858ad417a017dadbd9ade78015312e7f +83f6829532be8cd92f3bf1fef264ee5b7466b96e2821d097f56cbb292d605a6fb26cd3a01d4037a3b1681d8143ae54d7 +87d6258777347e4c1428ba3dcbf87fdd5113d5c30cf329e89fa3c9c1d954d031e8acacb4eed9dca8d44507c65e47e7cd +a05669a1e561b1c131b0f70e3d9fc846dc320dc0872334d07347e260d40b2e51fdbabeb0d1ae1fb89fba70af51f25a1a +819925c23fd4d851ea0eecc8c581f4a0047f5449c821d34eccc59a2911f1bd4c319dab6ece19411d028b7fdedece366b +b831b762254afd35364a04966d07b3c97e0b883c27444ff939c2ab1b649dc21ac8915b99dc6903623ed7adaae44870ac +93ec0190f47deffe74179879d3df8113a720423f5ca211d56db9654db20afe10371f3f8ec491d4e166609b9b9a82d0d4 +8f4aa6313719bcfad7ca1ed0af2d2ee10424ea303177466915839f17d2c5df84cc28fcef192cbb91bb696dd383efd3b2 +8d9c9fdf4b8b6a0a702959cf784ad43d550834e5ab2cd3bebede7773c0c755417ad2de7d25b7ff579f377f0800234b44 +99d9427c20752f89049195a91cf85e7082f9150c3b5cb66b267be44c89d41e7cc269a66dacabacadab62f2fa00cc03be +b37709d1aca976cbbf3dc4f08d9c35924d1b8b0f1c465bd92e4c8ff9708e7d045c423183b04a0e0ab4c29efd99ef6f0e +a163f42fb371b138d59c683c2a4db4ca8cbc971ae13f9a9cc39d7f253b7ee46a207b804360e05e8938c73bf3193bab55 +87a037aa558508773fc9a0b9ba18e3d368ffe47dfaf1afacee4748f72e9d3decc2f7c44b7bf0b0268873a9c2ef5fe916 +a1f20cb535cc3aebd6e738491fe3446478f7609d210af56a4004d72500b3ec2236e93446783fe628c9337bcd89c1e8e1 +9757aa358dfbba4f7116da00fe9af97f7ac6d390792ea07682b984aa853379ac525222ac8a83de802859c6dec9182ef7 +815daca1eded189ec7cb7cbc8ad443f38e6ddb3fb1301d1e5a1b02586f1329035209b7c9232dc4dff3fc546cb5ac7835 +aed86dfaf9c4f0a4b2a183f70f9041172002a773482a8ebf3d9d5f97d37ee7c6767badfda15476b3b243931235c7831c +8d032e681e89e41b29f26be02f80030fa888f6967061d2204c1ebb2279a3211d759d187bce6408c6830affa1337fb4e0 +877bff5c2db06116f918a722b26422c920aeade1efa02fa61773fca77f0ea4a7e4ee0ecaaa5cfe98044c0ff91b627588 +b9ee5310d0996a10a242738d846565bdb343a4049a24cd4868db318ea6168a32548efaf4ab84edfbf27ce8aec1be2d1c +b59f6928167323037c6296dd7697846e80a7a4b81320cfae9073ebd2002a03bdf6933e887f33ad83eda8468876c2c4fb +8167686245149dc116a175331c25301e18bb48a6627e2835ae3dd80dd373d029129c50ab2aebeaf2c2ccddc58dcc72ec +82b7dcc29803f916effb67c5ba96a1c067ed8ca43ad0e8d61a510ab067baefd4d6b49e3886b863da2de1d8f2979a4baa +b43824cd6f6872a576d64372dde466fef6decdbb5ad5db55791249fde0a483e4e40c6e1c221e923e096a038fe47dab5e +ab1e9884cf5a8444140cf4a22b9a4311a266db11b392e06c89843ac9d027729fee410560bcd35626fd8de3aad19afc4a +a0dbd92a8d955eb1d24887ca739c639bdee8493506d7344aadb28c929f9eb3b4ebaae6bd7fd9ffe8abb83d0d29091e43 +8352a47a70e343f21b55da541b8c0e35cd88731276a1550d45792c738c4d4d7dc664f447c3933daabd4dbb29bb83be4a +8ce4a1e3c4370346d6f58528a5ef1a85360d964f89e54867ba09c985c1e6c07e710a32cdda8da9fa0e3b26622d866874 +b5e356d67dd70b6f01dd6181611d89f30ea00b179ae1fa42c7eadb0b077fb52b19212b0b9a075ebd6dc62c74050b2d2f +b68f2cd1db8e4ad5efdba3c6eaa60bfcc7b51c2b0ce8bb943a4bc6968995abe8a45fe7f12434e5b0076f148d942786be +b5c7b07f80cd05c0b0840a9f634845928210433b549fb0f84a36c87bf5f7d7eb854736c4083445c952348482a300226a +8cfd9ea5185ff9779dee35efe0252957d6a74693104fb7c2ea989252a1aa99d19abaab76b2d7416eb99145c6fdb89506 +8cc8e2c5c6ddee7ef720052a39cab1ecc5e1d4c5f00fb6989731a23f6d87ac4b055abb47da7202a98c674684d103152a +8c95394c9ed45e1bf1b7cfe93b2694f6a01ff5fed8f6064e673ba3e67551829949f6885963d11860d005e6fabd5ac32c +adf00b86f4a295b607df157f14195d6b51e18e2757778fde0006289fabba8c0a4ab8fad5e3e68ddbb16ccb196cc5973f +b1714b95c4885aac0ee978e6bbabbc9596f92b8858cb953df077511d178527c462cbe1d97fdc898938bae2cd560f7b66 +adf103f4344feb6b9c8104105d64475abc697e5f805e9b08aa874e4953d56605677ef7ff4b0b97987dc47257168ae94d +b0ce6ede9edb272d8769aed7c9c7a7c9df2fb83d31cc16771f13173bcdc209daf2f35887dcca85522d5fdae39f7b8e36 +ad698d1154f7eda04e2e65f66f7fcdb7b0391f248ba37d210a18db75dafd10aedc8a4d6f9299d5b6a77964c58b380126 +904856cd3ecdbb1742239441f92d579beb5616a6e46a953cf2f1dd4a83a147679fc45270dcac3e9e3d346b46ab061757 +b600b5b521af51cdfcb75581e1eccc666a7078d6a7f49f4fdb0d73c9b2dab4ce0ecafcbd71f6dd22636e135c634ee055 +a170c5d31f6657f85078c48c7bbf11687ce032ab2ff4b9b3aee5af742baecf41ea1c2db83bcba00bccc977af7d0c5c8e +a9ef1cbb6a7acb54faf1bcbd4676cdeba36013ca5d1ac1914c3ff353954f42e152b16da2bdf4a7d423b986d62b831974 +aa706d88d3bd2ce9e992547e285788295fd3e2bbf88e329fae91e772248aa68fdfdb52f0b766746a3d7991308c725f47 +911a837dfff2062bae6bcd1fe41032e889eb397e8206cedadf888c9a427a0afe8c88dcb24579be7bfa502a40f6a8c1cc +ae80382929b7a9b6f51fe0439528a7b1a78f97a8565ba8cddb9ee4ba488f2ab710e7923443f8759a10f670087e1292c4 +b8962de382aaa844d45a882ffb7cd0cd1ab2ef073bce510a0d18a119f7a3f9088a7e06d8864a69b13dc2f66840af35ae +954538ffff65191538dca17ec1df5876cb2cd63023ff2665cc3954143e318ece7d14d64548929e939b86038f6c323fc1 +89efa770de15201a41f298020d1d6880c032e3fb8de3690d482843eb859e286acabb1a6dc001c94185494759f47a0c83 +a7a22d95b97c7c07b555764069adaa31b00b6738d853a5da0fe7dc47297d4912a0add87b14fa7db0a087a9de402ea281 +9190d60740c0813ba2ae1a7a1400fa75d6db4d5ce88b4db0626922647f0c50796a4e724e9cc67d635b8a03c5f41978f7 +ab07c30b95477c65f35dc4c56d164e9346d393ad1c2f989326763a4cc04b2cb0386e263007cc5d0125631a09ad3b874c +9398d8e243147de3f70ce60f162c56c6c75f29feb7bc913512420ee3f992e3c3fb964d84ef8de70ef2c118db7d6d7fd5 +b161b15b38cbd581f51ca991d1d897e0710cd6fdf672b9467af612cd26ec30e770c2553469de587af44b17e3d7fea9f7 +8c5d0260b6eb71375c7ad2e243257065e4ea15501190371e9c33721a121c8111e68387db278e8f1a206c0cce478aaa2b +b54ac06a0fb7711d701c0cd25c01ef640e60e3cb669f76e530a97615680905b5c5eac3c653ce6f97ceca2b04f6248e46 +b5c7f76e3ed6dc6c5d45494f851fa1b5eaf3b89adac7c34ad66c730e10488928f6ef0c399c4c26cbeb231e6e0d3d5022 +b6cd90bdd011ac1370a7bbc9c111489da2968d7b50bf1c40330375d1a405c62a31e338e89842fe67982f8165b03480c7 +b0afcaf8d01f5b57cdeb54393f27b27dc81922aa9eaccc411de3b03d920ae7b45295b090ef65685457b1f8045c435587 +b2786c0460e5057f94d346c8ebe194f994f6556ab2904a1d1afd66c0ff36391b56f72ed769dcc58558ee5efaa2ed6785 +965dbb0cb671be339afcb2d6f56e3c386fb5d28536d61d6073b420ee15dee79c205af2f089fbb07514a03c71bf54b4e2 +90f2003e2286bba9cebff3a6791637ca83b6509201c6aed1d47f27097d383d5c2d8532bff9e3541d2c34259841cf26ab +902142d1224e1888ebbfef66aaf8d5b98c27927a00b950753a41d1d28a687a8286b51655da9a60db285b20dc81d5ea89 +a5d364448bf0d0849e5104bdaef9cb2cc8c555f5d6d34239c68671fbe1252f7c8c75b83cea10159dee4da73298f39a12 +b013a54c5b99e296d9419ad5c2aaf4545acd34405e57d13cb764e92132cc20d1a14b33e10caf22d898b608670c04f273 +b92976dceda373331804d48a7847f508cafde8d15949df53dbda09d03908678db1e61ee637baad5f05b2b03ea6f5a870 +968bcb308c7ad0813dc9b3170f23f419aecd7b42176f27fac698811795bf42659fea6b04dab4ef43595dcc990622041b +a9d0a20e9367ea831dccd37f4d97ea75e9aeec952947a7946d95e0d249c94024183ef79a624bdea782469824df0ee4e4 +8521b9667453c3658703e5db365b13f0e0d2331ce611ff1e708f8124d8a81bb5e82871de4a66d45c1a6b0a3901bd901e +b9c88e76e69b0722c0a2f97e57dbc4a6f7456434cd694e2ff67f4e24740cffa4db03e2b18f07f22954ae7db2286e1fa2 +8400e55aa9ab01d4cc0affd611127b5d8d9a9dbd897f3cb8e2050379983aa54249be17d7b7891977b2515bb44a483f65 +8cbb967b4ed31dc40ea06822a94d54cbfc8845c66fbafa3474c8f5fe1ada97299ed4ca955d9d7a39af8821eabf711854 +b4d266ee3fea264a6c563fd6bed46f958c2d7bd328225f6e47faf41a0916aef3b697574322f8b814dfb2f5c242022bf6 +8f7c72d69a919450215ead660ffa9637642c5306354888d549fd4a42e11c649b389f67cc802a0184d10fdb261351140c +a5f9e494ea9b2393ec32c48aac76c04158ccef436d4e70ad930cba20c55fbf61e8f239f70b9d75462405c4b6317c71a1 +b3befb259b52a44a6f44345859e315c20efa48c0c992b0b1621d903164a77667a93f13859790a5e4acb9f3ec6c5a3c6e +b9e4ca259b4ee490d0824207d4d05baf0910d3fe5561ff8b514d8aa5c646417ca76f36ab7c6a9d0fb04c279742f6167a +98fa8c32a39092edb3c2c65c811d2a553931010ccb18d2124d5b96debd8b637d42b8a80111289f2079d9ebca2131a6dc +a65e5aa4631ab168b0954e404006ce05ac088fd3d8692d48af2de5fd47edbf306c80e1c7529697754dbbba1b54164ba0 +b94b7d37e4d970b4bb67bf324ebf80961a1b5a1fa7d9531286ab81a71d6c5f79886f8ef59d38ae35b518a10ed8176dcc +b5ed2f4b0a9ae9ace2e8f6a7fd6560d17c90ae11a74fa8bef2c6c0e38bfd2b9dd2984480633bca276cb73137467e2ce3 +a18556fe291d87a2358e804ee62ddff2c1d53569858b8ae9b4949d117e3bfb4aefce1950be8b6545277f112bebeeb93d +a0d60b9def5d3c05856dff874b4b66ec6e6f0a55c7b33060cc26206c266017cdcf79b1d6f6be93ed7005a932f9c6a0b9 +801fced58a3537c69c232ce846b7517efd958e57c4d7cd262dbec9038d71246dafad124aa48e47fe84ecc786433747c7 +a5e9a8ea302524323aa64a7c26274f08d497df3d570676ecc86bd753c96a487a650389a85f0bc8f5ea94fe6819dc14e5 +a8a2963dc9238a268045d103db101adc3b2f3ab4651b7703b2fe40ece06f66bf60af91369c712aa176df6ed3d64a82fa +a4a8ff0a9a98442357bcdd9a44665919c5d9da6a7d7d21ccdbbd8f3079b1e01125af054b43b37fc303941d0a2e7baee0 +90ef893350f50d6f61ee13dfab6e3121f4a06a1908a707b5f0036cdc2fe483614de3b1445df663934036784342b0106f +84e74d5bc40aaab2cc1d52946b7e06781fbef9d8de6f8b50cd74955d6bdb724864c0e31d5ac57bf271a521db6a352bd6 +832cdf653bbbd128e2e36e7360354a9e82813737c8ab194303d76667a27aa95252756c1514b9e4257db1875f70f73eb4 +a0af8660ed32e6dbcc4d5d21b0a79a25ff49394224f14e6e47604cf3b00136de8f9ab92e82814a595bf65340271c16c3 +9040b5caf5e4dc4118572a2df6176716b5b79d510877bbb4a1211b046596899ea193be4d889e11e464ffb445ab71907b +b9bf8354c70238ab084b028f59e379b8a65c21604034d1b8c9b975f35a476e3c0ba09dd25bf95c5d8ffb25832537319b +a7b492cc1df2a8f62c935d49770d5078586bd0fefda262eb5622033e867e0b9dc0ffc2ce61cd678136a3878d4cbb2b56 +95a5ef06f38743bba187a7a977023b1d9d5ec9ef95ba4343ad149a7b8b0db0e8e528bfb268dc7e5c708bc614dc3d02c8 +99dcf7f123df6c55aeff0a20885a73e84d861ec95cf9208ba90494f37a2dcaacebc8344f392547d3046616d9753c7217 +b3e14f309281a3685ceb14f8921c1e021b7e93c9e9595596b9fb627e60d09ed9e5534733fcbdf2fbc8c981698f5e62ac +816a5e0463074f8c7fb2998e0f0cf89b55790bdbbb573715f6268afb0492453bd640dd07a9953d0400169d555fdf4ac8 +8356d68f3fe7e02a751f579813bd888c9f4edcc568142307d1c9259caef692800e1581d14225e3a3585dac667928fa94 +8d70ea3314c91bfc3f7c1dcf08328ae96f857d98c6aac12ad9eebc2f77e514afdbaf728dfcb192ed29e7ce9a0623ecbb +b68280e7f62ced834b55bc2fcc38d9ea0b1fbcd67cc1682622231894d707c51478ed5edf657d68e0b1b734d9f814b731 +b712dd539e1d79a6222328615d548612eab564ace9737d0249aa2eefed556bbcf3101eba35a8d429d4a5f9828c2ac1fe +8da42ca096419f267f0680fd3067a5dbb790bc815606800ae87fe0263cae47c29a9a1d8233b19fe89f8cc8df6f64697e +8cb2ffd647e07a6754b606bde29582c0665ac4dde30ebdda0144d3479998948dae9eb0f65f82a6c5630210449fbd59f7 +8064c3ef96c8e04398d49e665d6de714de6ee0fced836695baa2aa31139373fad63a7fc3d40600d69799c9df1374a791 +aec99bea8ab4e6d4b246c364b5edc27631c0acc619687941d83fa5ba087dd41f8eaec024c7e5c97cf83b141b6fb135da +8db6051f48901308b08bb1feb8fd2bceaedde560548e79223bd87e485ea45d28c6dcec58030537406ed2b7a9e94e60cc +a5b812c92d0081833dcf9e54f2e1979a919b01302535d10b03b779330c6d25d2de1f374b77fe357db65d24f9cbcd5572 +967d442485c44cf94971d035040e090c98264e3348f55deabd9b48366ec8fe0d5a52e4b2c9a96780a94fc1340338484e +a4b4110bef27f55d70f2765fc3f83c5ddcdfe7f8c341ea9d7c5bcee2f6341bcfbf7b170b52e51480e9b5509f3b52048f +a0d39e4eb013da967a6ac808625122a1c69bf589e3855482dedb6847bb78adc0c8366612c1886d485b31cda7304ec987 +a92f756b44d44b4e22ad265b688b13c9358114557489b8fb0d9720a35e1773b3f0fa7805ac59b35d119a57fe0f596692 +aa27e4b979af6742b49db8bf73c064afd83a9cfe9016131a10381f35a46169e8cfd1a466f295fcc432c217c7c9fa44a5 +845961319cc10bcfbb1f3cb414a5c6a6d008fb3aac42c7d5d74e892cc998af97bc9a9120c3f794e4078135e16a416e38 +a18dbe3015c26ae3e95034c01d7898e3c884d49cc82e71ddb2cf89d11cec34cc2a3dff0fafb464e8e59b82ce1a0a7a11 +a954aed6d7124fa5bd5074bd65be4d28547a665fb4fe5a31c75a5313b77d1c6fc3c978e24c9591a2774f97f76632bdde +8f983b2da584bdff598fcb83c4caa367b4542f4417cc9fa05265ff11d6e12143c384b4398d3745a2d826235c72186a79 +b2caa17d434982d8dd59a9427307dfe4416b0efc8df627dd5fc20d2c11046c93461d669cab2862c094eec6a9845990c6 +8c2baa5a97ee3154cce9fa24f6b54b23e9d073e222220fdd0e83e210c0058fb45ce844382828b0cb21438cf4cad76ee6 +b93437406e4755ccf1de89f5cbe89e939490a2a5cf1585d4363c21ae35b986cb0b981dec02be2940b4ec429cc7a64d4c +a90ac36c97b7ea2eddb65e98e0d08a61e5253019eeb138b9f68f82bb61cdbadf06245b9dfffe851dfa3aa0667c6ac4b8 +8bcdd7b92f43b721ddbfd7596e104bc30b8b43bdaee098aac11222903c37f860df29d888a44aa19f6041da8400ddd062 +98f62d96bdf4e93ed25b2184598081f77732795b06b3041515aa95ffda18eb2af5da1db0e7cfed3899143e4a5d5e7d6c +ad541e3d7f24e4546b4ae1160c1c359f531099dab4be3c077e446c82cb41b9e20b35fa7569798a9f72c1fae312b140b4 +8844a1471ff3f868c6465459a5e0f2fb4d93c65021641760f1bb84f792b151bc04b5a0421bbc72cf978e038edc046b8f +af895aebe27f8357ae6d991c2841572c2063b8d0b05a2a35e51d9b58944c425c764f45a3f3b13f50b1b1f3d9025e52ad +adf85265bb8ee7fead68d676a8301129a6b4984149f0eb4701eae82ec50120ddad657d8798af533e2295877309366e9c +962e157fe343d7296b45f88d9495d2e5481e05ea44ca7661c1fdf8cc0ac87c403753ca81101c1294f248e09089c090eb +a7c8959548c7ae2338b083172fee07543dc14b25860538b48c76ef98ab8f2f126ecb53f8576b8a2b5813ecb152867f18 +ae71680366e11471e1c9a0bc7ea3095bc4d6ceb6cf15b51f1b6061b043f6d5941c9f869be7cb5513e8450dca16df2547 +831290201f42ebf21f611ca769477b767cf0ee58d549fcd9e993fae39d07745813c5ce66afa61b55bb5b4664f400ece7 +af5879e992f86de4787f1bc6decbc4de7d340367b420a99a6c34ac4650d2a40cbe1cef5c6470fc6c72de8ee1fe6bcce4 +8d3c27e1b2ef88d76ac0b1441d327567c761962779c8b1f746e3c976acb63b21d03e5e76589ce9bb0d9ba6e849ed3d53 +ab23b09c9f4151e22654d43c1523f009623b01fe1953d343107cef38b95bd10afd898964946d3cb8521bcbe893e1c84d +8a6acade9520e7a8c07f33d60a87fd53faa6fbf7f018735bffcbbb757c3bafb26f547ceb68e7b8b6bca74819bfcd521a +94db50080d557440a46b6b45ee8083bc90e9267d40489040cbed6234bebf350c788ec51557b969f95194102fde8e9713 +8be8031f32504e0c44958d893649f76cec17af79efcd22bbedb78378f0a150845467e59f79a3f2a3b6a66bdf0d71d13c +a69a4ac47fd92e1926b5e14adcbebbef049848e8a00d4bb387340892e5a9333cae512f447201728d3b53c6cf980a5fdc +8fc713825277c5a8d9ef0a1f6219d141def6d8b30aff0d901026280a17d1265d563ff5192a0817e0e1a04ff447fb6643 +8bf0a85569c4f0770ff09db30b8b2ea6c687630c7801302c17986c69a57c30f0781d14b3f98a10b50c4ecebc16a5b5ec +896baa4135d5621fd6b6a19c6d20b47415923c6e10f76c03a8879fd8354e853b0b98993aa44e334623d60166ba3e3ca9 +b82cde1c2e75a519ef727b17f1e76f4a858857261be9d866a4429d9facf9ea71d16b8af53c26bde34739fe6ea99edc73 +b1a9e1f2e34895a7c5711b983220580589713306837c14073d952fe2aef0297135de0be4b25cbfaed5e2566727fb32ef +b42ed0e9eaf02312d1dba19a044702038cf72d02944d3018960077effc6da86c5753036a85d93cd7233671f03d78d49a +a402e34849e911dbf0981328b9fe6fff834c1b8683591efd3b85aa7d249811d6b460a534d95e7a96fdd7f821a201c2c4 +a774417470c1532f39923d499566af762fa176c9d533767efd457cc5e4a27f60e9217f4b84a9343ecb133d9a9aab96b7 +83dc340541b9ef2eb8394d957cd07b996d2b52ac6eb5562cbba8f1a3312f941c424c12d1341a6dc19d18d289c681ef40 +b2906c32d5756b5712e45dec53782494a81e80f887c6e1ef76e79c737625eccecb8fd17b20e6f84890d322b6ffde6eab +b89705c30cec4d50691bc9f4d461c902d6a4d147cf75ee2f1c542ad73e5f0dabe3d04cd41c6c04ab1422be4134cf1ad7 +8c3293651f4c4fac688bf5837c208b15e5a19ce51b20dd80ffc7fca12d3e615b2773cfc3ed62a1b39c66808a116bde06 +8fceb8ef481163527d1fc3abc7e1a5b3b6de2f654c3fe116d1367b177dcba2e0d2124a7216803513a3d53fc1e30435b9 +b2a42c827da630aaa3eb20ed07d136aa11ba01b4c8efc0a57ebab7d5b851a15daa6ba118bcffbc20703916e430e30a87 +a86340153abb3fe97414e2fde857e15aac27c9bb9b61258eea6766024f426ed0753f08f07f6b02b5375e1587ea3afcab +b006465e258e646f91ba889765113d3dc9bd657246c533cab6516d55ba054baa9d7276a3b0fa31730c3bd824845bf107 +a08aadc09428719cde0050d064c0f42c5b7c4f6c158227d7636f870957d6cfe821b4c62d39279a7c98f5a75fcb7bbfba +885e7d47ce9b50d21b95116be195be25f15223a6a189387575cc76740174c3e9044f1196986d82856b3fb25cdd562049 +b18c3780362d822cc06910743c4cbcef044823a22d12987fe2e56f3801e417f2e9cd31574ea1c5c6ee7673a14aa56e3e +a625570ef7d31c042d968018865aeeba34ee65a059ab1ec079c7a8ba1be9e24bce6afb7036c07d9d6c96ab014f95d661 +8fc9bd4764adc4c300b5bd49a06dce885d1d8aff9bae68a47976d0cd42110aa6afa2d7b90b64e81c0f14de729f2fb851 +91d88714cb669f5f00241aa5ab80dffb04109492ea9c72b59645eb1f85f3539c61db2ab418af986f42241df8b35445e9 +b98f14e664df2590dd2d00b5b5c817e388e5d9fb074f718637c33b3d4969c89e82fdd12db8997f5ff3bf5bb5ca5dd839 +86cb3d9f148cb2170317a4c22af7092155aa66ecff7ab1299b102fbbaa33ed2a284b97b08f529d2da9faea63fb98972c +92449f6b8a7c737ecef291c947cbd602c47d7fe47dc3426c2b413f3019169aa56e14c2a7216adce713e1c7bd5c08a83f +b08c1b9080bba88b44a65070948142d73c00730715fbdd01e13fc3415c5b4f3248ef514fa3ade4a918c9a820cccae97c +b0a05297da76e37c22be7383e60bba1cbc4f98ba650e12d4afcfcea569842003644a10ad73c9148958f7bf1ffa0a27d0 +839092c1f4e9fb1ec0dde8176f013b0d706ab275079f00f8e774287dd658d1b5638d5fe206f5f2a141911a74bb120f75 +a36bd669bdc055ece4b17ff6eac4c60a2f23324a5eb6d0d6c16a2fce44c39cfd52d1fa2b67f3f5e83504e36426fbfc40 +8aa428323512cf769645e2913a72976d32da4c0062ffe468a6062fd009340f0f23c6b63285848a0e7631a907adb032a0 +944800f7d43f41283eb56115ac39ccc5bf107ae5db6abcaba6936b896260cd09428a6b828c0bccebeb00541073dbf38e +8e700ca7c9e1538cf64e161dd8d16af56fc29d53c79648150d6d8c268b0c95c76acded723e29918690d66252bd75f5b3 +b9c4ce35b5b16b4c39b6e85800c76b26e8d0999500fabc1e5b6234a7f8da18c621266ac0d5ebc085354297ff21ac89a5 +a0c706d32063f1877f7e903048ce885f5d012008d4a8019dd00261a8bbc30834bffeba56cdeddc59167d54cc9e65f8fa +839813b736225087cbbcf24506ea7bf69138605036b764ec0514055ac174bbc67c786a405708eb39a6c14c8d7e0ec6ee +b1a5fef055a7e921c664f1a6d3cb8b21943c89b7e61524a307d8e45aa432e5765a27c32efdb32d88062cd80800a260de +b17f8202d9ed42f0f5cb1b1dbda60711de3b917a77f6069546fa3f86d21f372b8dd5cb86f1994b873ba9982404e08daf +b5211d54bd02d44d4d808ad57067606f3e9fa2cad244a5f2acef0edf82de3c496d2b800f7c05f175d01fa6ace28b44d1 +aa9c6f8f489b35fdb7544116fe5102a34ff542de29262f156df4db4ea6e064f5ea20c4bd877d40377ed5d58114b68f19 +826668b1f32e85844ff85dd7e2a8e7f4e0fd349162428bc9d91626b5ab21bdbacd1c9e30cf16f5809b8bf5da4f4fe364 +b30d14917b49437f9fdbae13d50aee3d8a18da3a7f247b39e5d3e975c60bd269da32da4e4cc8844666fca0d65f4e3640 +8c6918d8d94b36c6b9e772e9a432e66df16724e3b0660bde5ea397e6ef88028bb7d26184fbe266a1e86aef4a0dfe5faa +906d80ffd692c1dd03ab89be52e0a5a9e90a9cdbfc523d2b99c138ae81f45d24c34703f9cb5a666b67416e3bb6272bc4 +8b07e8ba22b436e64f011cacf5e89c55cd3bfb72ae8b32a3a8922c4fccb29de6f73662d6e330da6aa6e732a2187ef3c9 +9547466b4553a49adf59cc65d4c3c9401b2178947ebe3bd33c6e63cfb67d6be8729033158594f6f244b272c4487d6958 +aafcccea41e05cb47223fa8dfec0dd55964268bd4d05e24469614077668655ac8a51d2ac2bfb22862f8f4fa817048c2f +870f8c1173e8fd365b0a2e55c66eea3ab55355990c311f3042377803d37e68d712edcc5a0a2e2f5a46df0c1c8e6310c2 +b4288f792008f342935f18d8d9447fe4ddcfea350566e13dba451f58c68e27241af1367f2603a9dff6748e7fe0c53de4 +91c58c0e537d3afdcf7783601dd9cda2aa9956e11f711b15403760cf15fc6dffb40ed643886854571da8c0f84e17adfe +a43fec8ee92febed32e7cdd4e6314a62d9d3052c7a9504057dfba6c71fdfbeff1cef945d8f087bd106b5bec7478ad51f +99cf5e0e3593a92f2ec12eb71d00eccec3eec8662333471b2cb3a7826b7daca2c4d57ffba18299189cf7364e2af5df6d +af50f9ab890b7517ff1f1194c5b3b6f7f82eabc607687a8380be371a6a67b117aeb9b6f725556551b81f8117971706a2 +aa352430887053602a54403bd0d24d6b5181b44aa976dfa190e21851699a88127dcc904c90a48ec44610056b5dcd36c4 +964c821ea1902354736fa382a929c156bd67b9468d6920d47c27b9d0d304b6144118888d124c1f6785da596435ed2410 +b2284a67af26b5f5aff87b4d8e12c78ab37c5eb6e92718fca8549f86f4f001b660fc4520456aff72c9bcddd686603942 +83c54cbb997ea493dc75df4023071dce6da94268feaa2352373789616f012098270ba4fd60c791796a6f5062fb2cd35e +9143e8fee0b8f0f34c65c7750858093dcf165c6a83c026bfac2d5ffa746361eb4b6a14fdb43e403add901ac3735735a3 +97d7748a5b278ee47b18c9e60689b12a0a05be47e58e78bf8c04b9e8b34e2e2f2d3ac3c25c76ab2e0a75e8a54777b7c8 +b4e68f6f2d978a5411414c164c81ddb2a141b01ebe18c65a8626ca75d6432e5988310b50a888a78c3a0a242353525af5 +8976f4cc3eaf2684718cf584712c4adaf00a4d9c521f395f937e13233b30329658b3deacfe7e29fac84c496047f2d36b +a40bcdf4b6e95f1535c88dddcbf2074ef2e746b7fd232bdfd2b88f2f6d4bbf21c6b263cf5fd3e12a03476f2f5ffe00d2 +88c7b6337ee705acd8358ef6d2242d36b140afff0579a7784b3928a0c49698bd39c1f400e8a2e3eda5fbfb2e8f28fe51 +a98612ba8b450a71d2075d51617ebeb7ca401ad3cbd9b8554850c65ef4f093ba78defb00638428c9f1f6f850d619287f +b7e71d3ffa18b185c1a6bd75668ff65d985efc0a0c19f3812cafde9adbfb59ffd108abeb376e6a8877fdf5061562f82b +8a3e5fd776cc26908a108a22b1b122d60cb8c4f483cbedcd8af78a85217bb5a887df3efed2b8b4ec66e68eb02a56ca93 +b0d92b28b169d9422c75f9d5cb0a701e2e47b051e4eacd2fd1aa46e25581a711c16caf32f40de7c7721f5bf19f48b3f5 +88895739d5152282f23e5909cf4beebda0425116eb45fc5a6a162e19207686d164506c53b745fb2e051bb493f6dbad74 +adbccfed12085cd3930bd97534980888ee564dda49e510c4e3ca0c088894855ef6178d5b060bca8a8a1a427afdbec8a8 +87d00674abd3d2e7047a07ed82d887e1d8b8155635887f232dd50d6a0de3fb8e45b80b5a05bc2ec0dea9497b4aa783ac +806e1d3dfadd91cbf10e0d6a5e61738d0dbff83407b523720dce8f21f8468b8a3fc8102acf6ba3cf632ca1cb2af54675 +95a9dff67cf30e993071edede12623d60031fa684dfbe1654f278a1eb1eb7e1be47886d3f8a46c29b032da3176c0d857 +9721973288384c70a9b191436029e85be57970ad001717edc76d44cbfa0dff74f8af61d5279c5cd5c92c9d0f6c793f63 +95c22d1d9b51ef36ba30ee059dcd61d22be3c65f245d0a5179186874219c08e1a4266f687fc973e71f3e33df2b0f7fd3 +b53ec083dd12cc42ae2bae46883a71f2a35443c9ce4ed43aa341eb5f616a53b64211ed5aac717fe09ef1d50f551ed9f0 +a103dab6695c682400f60be8d5851ce07f12e4bd9f454d83b39c41ddcf1443bb14c719b00b4da477a03f341aa1e920cb +b522236988518e5363b1c4bb3f641ff91d3d4c4d64c5f065415b738160b4ce4b0c22e1e054a876aa6c6a52fa4a21dfa2 +a6a00562f0879702cdba5befd256a09f44bf48e61780e0677ff8c3fda81d8e6dc76ba1b05e3494ca9a4cef057eba6610 +b974a2ae631e0b348421f0cda5bd4ce7d73c22dd0fc30404c28852c33499818cab89fbf5c95436d56a0aab3bf2bbab51 +9148cf2a7b7e773245d4df5a9d34cf6d9d42b1a26a4ca6bc3013feca6f3941d6c44f29ba9328b7fe6ce6d7f6565f8e4a +a34035c4a63e98528a135cc53bbbcfcda75572bc4c765f212507f33ac1a4f55563c1a2991624f7133c77b748bbe1a6da +a0c45923cfb7bd272ee113aecb21ae8c94dda7ad1fe051ddb37ab13d3bb7da5d52d86fff9f807273476c24f606a21521 +81ec2ca57f4e7d47897d0c5b232c59d7b56fe9ce0a204be28256a7472808de93d99b43c824a0cd26391e6cac59171daa +8373852f14a3366d46c7a4fc470199f4eebe8ee40379bd5aae36e9dd3336decaead2a284975ba8c84d08236e6b87c369 +b47e878a93779f71773af471ba372cb998f43baca1ae85ea7ff1b93a4dee9327e2fb79691c468ec6e61ab0eae7ceb9f1 +8fc8f260f74303f26360464cfef5ee7eebcbb06073cef3b1b71dab806d7c22f6b3244ce21d0945b35c41f032f7929683 +87e3c4e1dab00596e051ce780b9a8dba02ecdc358f6ddaeb4ec03c326e4b7da248404745392658eb1defff75b1ba25c8 +aac95d8e3b7fe236a7ca347d12a13ec33073f2b2b5a220ecfd1986ca5c3889f0e6a9d9c377a721949aa8991c1821953a +91a483679437ae126a16f5dc3bba6e9bb199dfbba417f0dc479f22819b018c420edc79b602db6183c6591b1909df4488 +94a4b2c663aa87a2417cad4daf21a88b84983a7b212ffcd18048a297b98e07dd4c059617136976fac1d9e94c8c25b8d2 +83e2a690bfa93c79f878a63c0f69f57aabdd8bede16b5966ffba7903dc6ad76775df1fd5347e6f2825f6cd7640f45a45 +a316af7ac11b7780d15312dc729499a1a63b61c4283e103ecce43c3b0cbb0f4bce6ff04e403f5c7cb670dee80c75ab99 +8d0a911c54ee1f9f7e7794732ad87b434c3f356294d196a5e35eac871727fd32a49c27c2dfa10833f9e6f9c7ccbe0064 +8b8db09028298a1f6362b346c8bfeced7cb5d13165a67c0559a9798a95b7a4a9810c02bb852289d47c59f507bd24ce77 +962d57305c518f175ed5d0847fb52ddc4258ca0e4c9ddfc8c333a2ee9f8b4e48d25a3d7e644b785a5953e2e4063da224 +92e0799491898271769250fe88b0cb9dadec98ac92f79de58c418d23ef8c47fcf21ddc90e0cd68bb8f1deb5da82da183 +99855067125f6a6c3a3e58d3bd2700a73ef558926bd8320d2c805a68e94207b63eda6bdc5a925ec36556045900802d51 +a724ae105ab4364a17ddb43d93da1e3fc6b50213f99b7be60954b24dc375c4f93a0737f4a10b4499b6f52667d5f3a64e +82070fb43a63fb50869b118f8940108f0a3e4cc5e4618948417e5cc3801996f2c869d22f90ca4ca1fdbef83c4778421a +b25c04365d6f24d5d3296c10d85a5de87d52a139ddbcbf9e0142074bc18b63a8bc5f5d135bd1e06c111702a4db4cee28 +851093282dcda93e5c98d687a17a7ee828cf868f6c85d372d9ae87f55d0593d8f9f0c273d31f7afa031cf6aea6a7ef93 +93f04f086fa48578210ed207065d80a40abcc82d8bfc99386a4044561d35748ff6c3da6489933c23644ad4b60726da8a +84b1b50d1e876ca5fc341bbedab5b3cc0f6a3f43ea7dd72605f74d0d9c781297b2f12b7872dd600924f1659a4cdf8089 +81b0ba88c582d3956f6b49ca3e031c6400f2ec7e1cd73684f380f608101e9807f54866be0bb9a09c03953c4c74fbb3c8 +a641af6ac644c41a55dee2ef55d3c37abdb19d52bc1835d88e7adda6b6ccd13987c5fd9cba9d318cabb541aa6a0c652e +a7b75b0624d04ad0901070e691eb2d2645b60f87e9d6b26e77a5fb843f846c32fc26e76ae93fd33fe3b857f87bc25162 +a81ba3e2ed0f94c67cd02ba7360e134f8becf7ed2ed2db09b9f5ef0942f7073bfee74ca446067db6092f7b38f74ccc11 +ab80edcabab5830a24210420f880ebac4e41bf7650c11ba230f4889634dbf8e8e2309f36be892b071c67a3bab8fc7ed6 +94d69b64675076fecad40fae4887fb13a8b991b325fa84e9d2d66e3b57646de71a58ad8fd8700fefb46975b18289250b +b44fc0df480cd753a041620fa655be9df74963ae03d4625847d5bb025ceb37f48d19c8c9c444546fba5fe5abb2868506 +b56e2c51324d6200b3d9781b68b5b5e1617a68afccd28b3a12a4be498d2e3aafcd86514c373a9f3a001db733010c29cf +a359a0c172e5cd7ce25080dd2652d863d7c95a4a502ae277ac47f613be5991300f05978404a0acb3bcda93524dcf36e4 +b01427a3dfdf8888727c0c9b01590b8ae372b7b4080d61e17ccb581bac21e61c4a58c75db7a410d1b2a367304e1e4943 +95cb08be4a96c18fbf9d32a4bbf632242029d039a5fdea811488d3634cd86520d4f9806250a8c01855ee2481210f542a +b8594fe6c0717164058f08aedeed1853523f56cec5edbf0d2be271fa5e8bfd61f2974b0f3988d70f5baa2e7888c7ec1f +8f64ee89f59daf74fa1056803247c9d678783ee3917b12a201f30f7523957763e979ceaddb38bae20de40b9885728049 +b6093ee4bdb837bcc59172e236f4bdbd439c0a5a50e2aa16636cbff81b51e92989eb5f80a3f75c37ae7b5b942e55b3d2 +913b6fbb7b43e3e5c49e96cd8e82ed25c655e51c7b8ca82e8fbf92b01ac83c39d52f6f4efab5d39b0591a0538601a86f +81f42668479ca0bec589678dc0973bf716b632578690efe1a0f13de630f306fb4a189a98c2302572fd85d3877ee030b5 +90ff89c38a9a7189f28d35a088657f52283670e7fec842fa91c265660ea2e73b0ad6c46703d649f406f787490b7a7e4b +9077b8b5f1e083183f3152ceb9c5491b5d4b86525a08879f7fb6d5e27f9f1a6867cf0d81b669a4a2d1f1654b67fa8d9c +a7a0275cf5b894adbf2e54a972310cfe113e811872111d6ee497d03750d9f6ffa5517b6c13a99b111a4a91e8e4dfeeee +a08976bf8125b7538313a584bbe710741d630cab067a204ad4501cc4938874ce7aa6a1a826259c2e82ef10a66f1f36fa +8aa45385b5b97f1f3e45f2bbf7a4f3e8ef068e628608484971c97adeb610ebd5deec31317e03eb6536808921062c04db +945b106b8f3ae85e60dfd34ef3dcc079bc6f0aab6df279ed000856efd51321462038ac0a1ca5db3ebf6379bc341e7c55 +a4199c87a96f98cc9d8776fe6de131d2c706b481eb9e9a3bbc50a93d492d7fd724ea469f723fbcfb94920cb5b32c1d76 +a5347b1b2f6149805de67546c5ed72253311099bf1473dbc63edcf14a0a5e68d401f5341338623fbe2e2715b8257e386 +af5dcd03ddc3769e83351d6b958d47a06d4e5224bd5b0ec40ffe6b319763fab8572002f4da294a9673d47762fd0e6e1d +82ec1031b7430419d83b3eea10a4af4c7027f32b91c3ae723de043233b4a2e0c022c9e0f5a1ac49753800f119159112d +8a744d911b67d03b69811f72e9b40d77084547e4da5c05ff33893468b029a08266fc07303f7005fd6099683ca42b3db4 +93ab566bd62d3439b8fc620f3313ef0d4cb369f0f0c352cdaf8e5c9e50b9950ac3540b72f4bf5adcb9635f9f7ce74219 +b2a211d72e314799bc2ac7030b8bbb8ef4c38ebd0ebb09d6cbd43bd40c6c61d80a3aad02cc73f5775a08b9657da20a48 +98d60f0a98d28718e0c6dcccc35a53521ea7f2d8fe08ea474374a336b44cea4cd1c63b31f2ad10186822bfb54aca53e6 +831f89cb94627cfe554d46ae1aad8c1cde7ebe86c4bd8fac4ef73ac2d5b491f5efa5dc4198cb8ffbec563e0606b91d89 +8f8552583bc6cb3fb176b7202236ee4128faf0c8ec608f9150f8e011d8c80b42aab5242c434d622b6d43510eaef752c0 +897bf27baaee0f9a8445200c3d688ae04789c380d1b795557841606a2031092328eb4c47fef31c27fdd64ba841d9d691 +b57589a4af8184b4a8ceb6d8657a35522672229b91692c1cec3ac632951e707922a00086d55d7550d699c4828bcfaab1 +98c2fe98095e026aa34074bcff1215e5a8595076167b6023311176e1c314b92b5a6d5faa9599d28fca286fadd4e3b26c +a034992e563bd31ede3360efd9987ecddc289bc31046aa8680903bb82345724805e6f6cf30f7889b6b95cf7319c3aea1 +85c33d9f10cc7185f54d53c24095e621966065e0ff2689a9aa6bb3d63706796c37a95021738df990c2c19493c0d44b64 +a8c1247d6de2215f45b50dd2dc24945ff9b93184bcc2159b69703b0bba246adcd1a70a12659f34c4ca4ba27dea6e3df5 +83ebdad2834c97bf92aac8717bab2f5cb1f01026b964d78e2f3b44e99d7908e419165b345d2b2f125b903096584e6683 +b0af6f7f81780ceb6e70adfd98e7702ec930c8ca854b50704c4a0fc8b887b9df60a6fe9038b487f3ed0eb8eb457307ea +933ec7e53882453898617f842ab2efae4756eb6f6ea0161cced5b62a0cdde4c08c7700d52f7546d4dd11a4c9e25d624e +adf6e6d4706025f85eb734f506dde66459c9537a1abf6189199cf219ae583b461e11c6242fce5f0795e4d9025270fabf +89e4316319483098761b0b065df4cfb542963b7a2556ba5425b6442fb0e596eb2a4f03e2dc8c617eebe8f243a12e7d10 +90c5a147555759ebc4d0e15e957a548315f9994ef0c7a3f53f2d18da44fb93bf051d96ba8551597a6f3e701b926fd791 +a151a9a5199c72c697b771cd81e550fc6f9596c752ae686ad988b316a7548360cf9785ab4645164d96cfdf9069a94020 +80cba11a3977729d7948db5bcc186159f4cae7c0a835bb38bb781e287dd6c238508e748f23454405c9d5eed28e77df02 +ae4b92ea03cb8ad12ad3ec76869ad05acb09f9d07a3c9a87dec0e50d9a276fe5d3d515a8c446f3aa35cd7d340a22c369 +8630062709a1f180f952de9f1ca3f41acce5420677f43d9619097e905a6237f1908d66db7a4dfdf1b2b92fb087e9944f +81defc33dd383d984c902c014424bddd5e53b013f67f791a919446daa103b09b972fa5242aba1b1dbe4a93149373f6c3 +963891ecaea97e661bac2594642327a54f5a0beb38fcb1c642c44b0b61faab9c87b0c9f544a3369171b533d3ab22f8f1 +932fadbff5f922ddcd4da942d57fe3e6da45c3d230808d800a3ca55f39b0b62f159be31a5924b395d577a259f48c6400 +992ce13bd037723447f88aeb6c7722fd9510c7474192b174ea914ed57c195c44c298aec9a8cabac103f0a5b50051c70b +b032157b3e4fe69db6ce6bb10bdf706a853fbd0bee08c2ab89da51ad827425df5df498b90e7a30247a7f9e954ca986e5 +b2478d4874578da3d5000893736bb65712e6aafe96e6fa5cf5878ae59ba0ce640dbe5d76ec2b5baca75af57def471719 +a387c17b14dd54910fecf472f760e67cf71a95e9e965cc09484e19581ada65e79938b86136a93e287e615fbd4908e080 +98f02be271d0f8841d8d561163f9e55e99b57aff121a93fba7a4654bcf15a0899811f00f5bcbfbebd98e365a0e332e97 +a3c34f01d54cab52a8890391b8cf152cc9cdc16e7e53794ed11aa7b1a21e9a84d39ddcfbcb36c5df6891c12307efc2e0 +a940331f491ec7ad4a9236ca581b280688d7015eb839ee6a64415827693d82d01710dc4bbd5352396be22781fea7a900 +b10874ed88423731535094031c40c4b82af407160dfade4229ac8f4ef09d57b3db95c4a9d73c1a35704f6bd0d5f6c561 +a9c5a4a7680261c1b0596f8ab631d73d4a7881b01e6559c628b5cdafa6dd2b6db2db64f3f2ab5841413a8a52b966a0da +8fc154564a61d5e799badc98b43a3587f804385a850adce9a115cbd2ad911f3fd4072b8e6b22fc6c025a6b7e7ea5a49f +b9caf7c6dcce3d378aa62c182b50bc9c6f651eb791d20fffa37ef4c9925962335fe0b3bc90190539312aa9ccf596b3b9 +90c5b7acf5cb37596d1f64fc91dee90f625f4219fa05e03e29aebea416c8e13384f2996f8d56791bcf44ae67dc808945 +ab8d311fc78f8a1b98830555a447c230c03981f59089e3d8a73069d402a3c7485abe3db82faf6304aaca488a12dbe921 +8a74fda6100c1f8810a8cacc41b62875dd46d5c4a869e3db46202d45a8d9c733b9299dda17ce2ad3e159122412a29372 +8769dcacba90e6fc8cab8592f996c95a9991a3efecfb8646555f93c8e208af9b57cf15569e1d6e603edac0148a94eb87 +854fd65eea71247df6963499bafc7d0e4e9649f970716d5c02fbd8708346dcde878253febb5797a0690bd45a2779fa04 +83e12dc75ef79fd4cc0c89c99d2dace612956723fb2e888432ec15b858545f94c16fae6230561458ceee658738db55ba +8416ef9ac4e93deff8a571f10ed05588bef96a379a4bdcc1d4b31891a922951fa9580e032610ac1bb694f01cb78e099b +93aea6e5561c9470b69d6a3a1801c7eef59d792d2795a428970185c0d59b883ab12e5e30612d5b6cde60323d8b6a4619 +91d383035aa4ec3d71e84675be54f763f03427d26c83afb229f9a59e748fb1919a81aca9c049f2f2b69c17207b0fb410 +b1c438956f015aef0d89304beb1477a82aed7b01703c89372b0e6f114c1d6e02a1b90d961b4acbb411cd730e8cacc022 +a1ee864a62ca6007681d1f859d868e0bcd9e0d27d1da220a983106dc695cb440980cfdb286e31768b0324b39ae797f18 +b57881eba0712599d588258ceada1f9e59c246cc38959747d86e5a286d5780d72d09e77fd1284614122e73da30d5cf5c +a48f9ae05ba0e3a506ba2e8bbce0d04e10c9238fa3dffa273ef3ffe9ec2ed929198a46507c0c9d9b54653427f12160f9 +8db18da7426c7779756790c62daf32ae40d4b797073cd07d74e5a7a3858c73850a3060f5a3506aae904c3219a149e35d +a2bf815f1a18d7be8ce0c452dfc421da00dcd17e794300cdd536e4c195b8c5b7ccc9729f78936940a527672ac538c470 +a34c6f1f2398c5712acc84e2314f16d656055adcafad765575ae909f80ab706cf526d59e5a43074d671c55b3a4c3c718 +b19357c82069a51a856f74cbb848d99166ce37bd9aca993467d5c480a1b54e6122ebddb6aa86d798188ea9f3087f7534 +b440eac6f24d12c293d21f88e7c57c17be2bdb2a0569a593766ae90d43eccf813a884f09d45a0fb044ee0b74ff54146a +b585d42ef5c7f8d5a1f47aa1329f3b1a566c38bf812af522aa26553010a02bfd6e9cc78fdb940ef413e163c836396a5f +aca213b27f3718348e5496342c89fffc7335f6792283084458c4a1aa5fe0a1e534fcec8e7c002f36141308faae73ef2a +b24c07359769f8ffc33bb60c1f463ea2baad440687ef83d8b7c77931592d534b2c44953c405914ace5b90b65646c1913 +b53dfaf381205a87ca4347328ff14a27541fa6436538f697824071d02d4a737ceb76a38dcc6e8dadef3b5bc6442f5109 +b55972d8ed5197215c0a9144fc76f2cd562ca5f4e28c33a4df913363fd1388978b224c44814adb4c065c588a4ac1fe10 +a3303bc650e120c2e9b8e964ad550eb6ac65ffe6b520768b3e8735565ae37eafdc00e3c15fae766d812f66956a460733 +b11e53912ea0e40c3636d81d7637e10c94cc7ed9330a7e78171a66d02b7603f4cb9b3f6968104b158de254e65b81640f +b076bb9f6d396aa09c2f4706ea553b426fdfd87d7d69e438285b74d334e82f73973cb4dbd6cb1647493433dad65dbc41 +9415828b1632175f0b733541e32c26a9c88fe12c721c23e595f2efceaa7f867f359e32564b7c032185686587ac935cf4 +89579a112c306181c79aabdbf683e7806357febcb73bf5e8883862ae29618ef89498b62634404bb612d618fcd16da415 +8761bcd55d04297c4f24899e8fb9f7c1fcd7449ae86371ee985b6a262e228f561c2584980694d9bf354bdf01543edb6a +9100c88bf5f6f00305de0c9cf73555f16a2016d71c50cb77438e8062bd549fa5407793a8a6a7e06398756777680a2069 +9235dfef45aeff9c174898b0755881b7171ed86362854f0eabc3bc9256176c05a5dc27ca527c91c3fa70c0ec5fd5e160 +ac53b1d677cebab6a99381dd9072b8ac1abae9870ec04a1f8d2a59b6f1de797c1492b59af6948f5cf2b20599170f5bba +946542936b0c59156e8fd5c1623b41369bc2cbcc46ece80360dcb5e7cce718a3dd8a021f0b9c223062a4e43d910b634f +b1e9939b34e1fcc026e820fcfa9ce748b79499f8e81d24a3ef0457b3f507fe5fa37b975a47c143e92eb695623b4e253b +9382d9b5766f6ae960d8a8435e8b5666e57ef8e5f56219e7bfd02857afe5cb16f44d70a9e444cfb1008649ae9b863857 +91770ed1215ed97dca1282b60b960be69c78e1473edb17cd833e712632f4338ff74bf435c3b257439497c72d535ae31f +8eb2cbe8681bb289781bf5250e8fa332141548234c5c428ff648700103a7cd31fdc2f17230992516c674aa0ab211af02 +a823b71c82481bc6ac4f157d5c7f84b893a326bbb498c74222427ded463d231bc6e0240d572ab96266e60eb7c8486aea +a13ce4f482089d867e5babcd11c39fa9a9facd41a2c34ee2577de9ce9c249187e16f2b3a984cc55f9e45b9343462d6d2 +8d80e7bc706059cf5151f9f90e761b033db35d16b80b34dc8b538adc8709d305a0c06933dcd391e96629cf3888c8bf87 +abcd36cdd86c0fb57fb7c0d7a3b9af5fd9aed14e9f4e7e84b0796c5c0ad18c41585e8c46e511cef73dc486fe43f6a014 +a947a5b6916f416fa5a69c31aba94add48584791148b27d0b3ed32c02a05dfc06f7fdc5006e3b2503bdf6e410e30f2fb +b158e621580659f1fa061d976b8591ac03b53ecd23d9eb2b08c1a20353d78438287749664d196020d469ef44b3b8752e +90a5a9540281e481ac4b8d29968f477cb006b56bd145529da855d65d7db0cf610062418c41a1d80c4a5a880c0abe62a0 +b2c91808b6289d08a395204a5c416d4e50a8bb1a8d04a4117c596c4ad8f4dd9e3fb9ce5336d745fc6566086ae2b8e94f +af6767c9b4a444b90aeb69dfddae5ee05d73b5d96e307ce0f3c12bccca7bc16475b237ba3bc401d8dafb413865edf71e +8dcecf624419f6517ef038748ac50797623b771d6111aa29194f7d44cfb30097ced26879e24f1b12a1f6b4591af4639b +954437559d082a718b0d6d7cec090532104ab4e85088e1fc8ee781d42e1a7f4cdb99960429707d72f195ff5d00928793 +80f0b7d190baa6e6ab859dc5baab355e277b00ddcca32e5cebe192877ad1b90ead9e4e846ca0c94c26315465aeb21108 +b8c29f181ed0bb6ac5f6a8d9016980303bb9a6e3bd63ce7a1a03b73829ac306d4fab306ac21c4d285e0d9acb289c8f2a +a7685079fe73ecaeabf2a0ef56bad8b8afb6aeca50f550c97bf27e6b4a8b6866601427fcd741dc9cb4ce67a223d52990 +ada2ebf6f2a05708d3757fbf91365ec4d8747eb4c9d7a8728de3198ceac5694516ab6fd6235568aecd8d6d21fef5ef48 +846bc5da33d969c53ab98765396cab8dcdbb73b9836c9bda176470582a3427cb6de26d9732fab5395d042a66bdba704c +800a3a7ea83ce858b5ebc80820f4117efa5e3927a7350d9771cad9cb38b8299a5ad6d1593682bba281c23a48d8b2aa71 +a002b18595dec90b5b7103a5e3ec55bdd7a5602ee2d3e5bd4d635730483d42745d339521c824128423dfe7571e66cbaf +b6b4e2067ac00a32f74b71007d8ab058c2ef6b7f57249cb02301085e1a1e71d5de8f24f79b463376fd5c848f2ab1c5bc +a3e03036db1b6117efe995bf238b0353ad6f12809630dca51f7daaaf69f7db18702e6b265208944bfb1e8d3897878a51 +add16712f66d48aab0885bd8f0f1fb8230227b8e0ffca751951c97077888e496d6bfab678cb8f9ffba34cee7a8027634 +ad211af2dd0748f85a9701b68c19edd4a7c420e497cb2e20afdc9df0e79663841e03b3c52b66d4474736f50d66c713ce +8c8a899ce0f16d797b342dc03c2212dda9ee02244c73c7511626dba845d11a0feb138441da5459c42f97209bf758cd9b +a17efc75c7d34326564ec2fdc3b7450e08ad5d1de4eb353de9d1cd919d90f4be99f7d8e236908b1f29cf07ae1ffe0f84 +862d4a8b844e1b0dd9f4deff180456ebed5333b54290b84f23c0ddb2725ac20307e21cbb7343feac598756fe36d39053 +9187fbb19e728a95629deda66a59e178f3fcd6e9d7877465aa5a02cea3baba2b684bd247b4afbf4aa466b64cb6460485 +85ae5636688d06eab3be16e44fe148515d9448c6123af2365d2c997f511764f16830610a58d747adab6db5031bea3981 +8aa8a82891f4e041ce6df3d6d5d7e5c9aaaffe08e0a345ac0a34df218272664c1b7be2450abb9bc428bd4077e6e5dcc4 +8c3bcc85ea574dfe1b9ca8748565c88024e94374434612925b4e9a09fa9d49c0a56b8d0e44de7bd49a587ef71c4bff5f +9524f9dd866fe62faf8049a0a3f1572b024120d2e27d1be90ad8b8805b4e2c14a58614516281cc646c19460a6b75587c +84580d9c72cfa6726ff07e8d9628f0382dc84ce586d616c0c1bd1fd193d0a49305893eae97388de45ba79afe88052ee9 +b5573e7b9e5f0e423548f0583423a5db453790ab4869bd83d4d860167e13fd78f49f9a1ffe93ddddf5d7cd6ec1402bc4 +aff658033db3dad70170decb471aee2cf477cf4d7e03267a45f1af5fd18200f5505c7ce75516d70af0b0804ec5868a05 +84a0eab4e732a0484c6c9ed51431e80cea807702fa99c8209f4371e55551088a12e33a11a7ef69012202b0bc2b063159 +a68f8e730f8eb49420fe9d7d39bb986f0584c1775817e35bb3f7dae02fd860cddf44f1788dc9e10d5bf837886b51947f +946002dd6cf7a4fd3be4bf451440e3f3fd7e9b09f609fa4e64767180b43146095dfc4b6994287f8cfa6d1390d144be71 +b7f19777d0da06f2ab53d6382751dc5e415249d2c96fce94ef971401935c1d1f7d3b678501e785cf04b237efe2fe736e +81e5c66dd404fc8ffd3ac5fe5e69ead7b32a5a7bc8605a2c19185efcc65c5073e7817be41e1c49143e191c63f35239c1 +b5f49c523532dfa897034977b9151d753e8a0fc834fa326d0f3d6dacc7c7370a53fc6e80f6d5a90a3fbec9bbb61b4b7c +8fc8e78c07319877adfaa154a339e408a4ae7572c4fb33c8c5950376060667fbfc8ede31e1b067933d47e3fdbf8564d7 +859cfef032a1a044532e2346975679545fbb3993a34497ce81bdcc312e8d51b021f153090724e4b08214f38276ee1e0d +ae476722f456c79a9c9dfdc1c501efa37f2bff19ab33a049908409c7309d8dd2c2912aa138a57a8d5cb3790ca3c0ba2f +89acbbeffb37a19d89cfe8ed9aa8b6acf332767a4c54900428dd9ab3bf223b97315aca399c6971fe3b73a10a5e95a325 +90a4a00418fdf4420a4f48e920622aae6feb5bf41fd21a54e44039378e24f0d93ccc858d2d8a302200c199987d7cb5e4 +a3f316b0bd603143eba4c3d2f8efe51173c48afe3c25b4ca69d862c44922c441bd50d9a5040b7b42ba5685b44071c272 +a22f4dc96fedd62b9a9f51812349e04d42d81d0103465c09295a26544e394a34abdc6ded37902d913d7f99752dbfb627 +a49f51baf32d0b228f76796a0fef0fe48a0c43ec5d6af1aa437603d7332505be8b57b1c5e133bc5d413739f5ae2ce9d0 +a9e4fe133057a0cd991898e119b735b31a79811307625277c97491ff5d864c428cfa42ae843601d7bb05c0313472d086 +b987edfe0add1463a797ff3de10492b2b6b7ef0da67c221ab6f0f2b259445768a73fbe495de238c4abbe4d328e817c49 +b7f0e4532a379a4c306bbef98b45af3b82b17175dfe0f884222ed954c12f27d8a5bdd0cdeb1df27ff5832ba42a6dd521 +9471bc5ad5ec554acfd61b2eb97b752cb754536f95ae54ca2cbd1dc2b32eb618881f6d8a8b2802c1a4e58c927067d6cf +b4c84f09225cf963c7cc9d082efe51afbbbe33469dd90b072807438e6bde71db8352a31bb0efde6cd3529619812ef067 +8f08005a83e716062d6659c7e86c7d3b51e27b22be70371c125046de08f10ea51db12d616fbf43e47a52e546e7acaac7 +a8937e66a23f9d9b353224491f06e98750b04eca14a88021ee72caf41bdce17d128957c78127fba8ef3dc47598d768a7 +80ad991de9bd3ad543cddeaa1d69ca4e749aaefb461644de9fc4bd18c3b4376c6555fc73517a8b1268d0e1e1628d3c1f +b22f98bca8fe5a048ba0e155c03e7df3e3cee2bfe8d50e110159abdb16b316d6948f983c056991a737b646b4d1807866 +b0bb925c19ca875cf8cdbefa8879b950016cc98b1deb59df8b819018e8c0ad71ea7413733286f9a1db457066965ce452 +95a991e66d00dd99a1f4753f6171046a5ab4f4d5d4fe0adfe9842795348a772d5a4a714dba06b4264b30f22dafa1322f +ad91e781fa68527a37c7d43dd242455752da9c3f6065cd954c46ae23ce2db08f9df9fec3917e80912f391c7a7f2f7ffa +a202d3becbf28d899fe28f09a58a0a742617c1b9b03209eca1be7f072a8ada1f7eac2cc47e08788d85e1908eb9d3d8ee +a360ccb27e40d774d5a07b4ebed713e59a0d71b3ee3f02374e7582b59ec4a5ce22cc69c55e89742ba036dd9b4edd8f34 +a10b897a946882b7c9e28abbb512a603ffa18f9274369843eb3491524a321df1f572eea349099ac6e749ea253c901ea0 +b782a672cd344da368732ecd7e0a1476c2af04613d3eb6da0e322f80438af932bd6d49be7a6f69f7c877512731723d89 +aeccee8dfd764e1adcfc4bf669e0fa87a94e7c79324333e958df47888bff5cec358b8b5bbb48db54822b54d11bbb4bc6 +ad4953913662a9ee8753a354864339f43916f2c2390d0a3f847c712b42718ee00ee14158d730709971941e8680d54560 +92ccb31d6c9e8940c7e8a4873e7eb9de9fb2fa2bac344fa367062ea451fd49a6920a45218dca3ee968711397d2a01536 +9448d9b2b3d12dde9b702f53373db8b8595f9d1f9de2ebee76de292f966f375316953aadf6bfc0e4e853e1fa12d8f02c +8919230878a7219da8c80a4b7d00b9169fb503e72d79789dd53863c243b8d0fb0a819d46fa636d805d0b9b1d15d1f2d9 +b6581ab01215aac023f5e6f57419b6aa63c0743c07caf57d4e146b56b02d90ce1423f70489ac3a11e5c968cb924f937c +a793ec1b1fe56a76920296af06073caadfd6f1d7e30950f8ca13de3de45fe275ca4b361f5249d9405264c3a06ebb5502 +86385b4a4e1bfb5efe7bfef8fd0dfeba7f4400852237cab60febb1dfa409e497a649e81284b5a15fe680b78927256756 +85d10600de96103daa7c90657174b6cb4a1286df5379f1eda9f11c97f9df57043c290eb1ae83658530fe0fd264867b86 +ae01b2396d0f598c21659cd854c15edd4904a34d22278aef97c9260a14a8b250b52d972d304ac4b187c24d08795d5355 +b91b3e4b6fc06e88081fe023ef1b773d82c628eb0f73a2731a9aa05b0dc89b7aeef2eea60125d302e696f45c407aeac2 +986d0f478e33af7568eab6bb26a55c13ffd7cae27525b4abe2f3a994bdb11bbc73d59bdb9a2f6b6ba420a26f8f620ba6 +9746f4fdeef35feaff1def0ea5366b64f21ed29749ae6349f9cb75987e7f931952f913f446100f2a6b182561f382e8eb +a34a116cfde1acbce0d7de037f72a7ca30ab126d8f4815b2b8bcb88e0e6c89015a4daaf4d4ce8eae23eb5d059cf9a5cf +80c3ea37f6a44f07cc9c9c881990f2a5deb9f9489a382718b18a287aa3c50ee6ebe8fd1b3afb84a3cf87f06556f4ca15 +97cff3bc88cfc72ce5e561f7eeb95d4ffb32697e290190c7902e9570c56b3854753777fc417fd27536fc398c8fefb63b +b8807232455833e4072df9bffa388ae6e8099758c2a739194719af7d9ed4041974a6cd9605f089de8b43f0e12f181358 +96f79fca72f75dc182c71f2343f0c43b06d98563fd02d2e1fbc031b96601608d8a726c811a74bb51ab8b0a3ce3632dc4 +b5262761680a4235a8c1257de4735cdcadf08d5d12c6e9d4f628464d5c05dfff3884a9ef2af3b7724b5a8c97e6be74eb +b6ce0eada73433d98f8fae7d55e4ea2b9d9d7a0ae850d328dd06991f27b1f03e470868fb102800ff3efe4ee1698531b9 +a37b7d9fe9d3fdfbc72c59cf6cacc7e7a89d534dea3d73121f7483331aec8ab3fbff58ffabb943b75d6f86df0ba43262 +93fce9be8a27fcaa1283d90d3e87265a6221ee302ec708161a42bd00ffe8e726743d9e187e1bf4307c0e3f25afbb1d44 +a4ea919021346ae7ea69d5e8f46d860b24c35c676b62f4e577c90e0c05c5646fe73721b143b7c38835dd4b443e6c3676 +b79983a5948453f70dfa4c396ce1945204498fe79f40c0667291bd0fdd96ed0b9ea424571f7ade342275c854c9f03d9e +866f8e395ed730b614b70bf999cad6e87e9086c1f5aea8d69020b562ee285dd0fb93afaca0dd13a0713f74a3f9340f01 +a3fef158782292c6139f9a0d01711aa4ed6f5cac11d4c499e9e65c60469ae3afbde44fb059845973a4b3bbca627b7eb7 +b4a2c0321b68f056e7d8051beede396fa2f0704d8aa34224f79f7b7a62eb485fc81889cb617019622fd5b5fa604516f5 +8f0e3edddbaead9059df94de4139e3a70693c9ea9bc6baaa5695dddfd67263b33926670159846292801941b9a0c6545b +9804e850f961e091dadd985d43d526ba8054d1bf9c573ed38f24bbd87aeaad4dcba4c321480abc515a16b3b28f27bb2a +95f330da28af29e362da3776f153f391703a0595323585220712dae2b54362cc6222070edd2f0dd970acfbe2e3147d5c +82d03b771231179cc31b29fe1e53379d77b5273b5c0a68d973accd7a757c7584dbb37f0507cdfde8807313ec733a6393 +81b3c39a9f632086e97b7c1f0ec7e2eaf9dc3cb0d84dec18a4441dbdc9fe9878fde4bcfa686bca1a9522632a353a5566 +a2db124ab2b493d5f9a1e4ca6b3144593c2fc8bfac129fd79da11dfbb7ef410a234fda9273a50a5ca05d7b37cc2088a2 +aa8550633c9449228702690cc505c0fc4837ea40862058e8f9713622b34d49fdc3a979b9317993c5da53b5bb5b7f4974 +ae783bcf7a736fdc815d0205b4c2c2b2fee0a854765228f76c39638ba503e2d37f1e28f6bdf263923f96fead76b4187b +b5ec86092c1d250251e93bab2f24e321afd2cd24cf49adfcbed9e8bc5142343ae750206c556320551e50fc972142f0da +b3b5791b590a6e9b3f473d5148624014aa244495249322a5d75cde2c64117ff9d32f4b0698b0e4382e5e7f72933061f8 +876c6a9162c17b16d6b35e6ce1ba32e26aec7dd1368bceab261ab880ad845c91e54b96a52c7d3aafbfbafc0e37139dca +902ddb5774d20b0707a704486457c29048776a5b88c377b14af6616c8ddf6cd34f49807df9c9d8866d6b39685cfb0f19 +8b87f71f94bc96de927d77a5d7123fa9cdda8c76aff64a5e6112cbc2eca43b07f8376db3e330f8af6a1db9b948908a6a +a69a5922e572b13d6778218e3657f1e1eea9a9682f6eb1b731d676d03563e14a37ff69bc5e673c74090ecb0969a593f7 +aff3510d78ba72f3cf5e3101847b7c4a956815aa77148689c07864e8a12dd0ef33d5f6c8cb486e0ea55850161f6afed0 +aa9c459cb2a008d94cbee2c6b561d18b0d7c6ffa8a65cbf86ae2c14eec070ee9d5324f5d38f25a945ddcd70307e964c4 +8310e15b050b1e40ece7530b22964bde0fd04f48dfffdec5a0d1fb8af0799a7fdc1d878139fb7cb8d043d3a52c2d1605 +b8f0856ce2c4034ee4041d0383f25fb0eeefc00b82443311a466fc18608313683af2e70e333eb87e7c687e8498e8a1ce +a8200a75c158fbb78474cab8a543caecd430b5d8b9964fc45d2d494dd938021cd00c7c33413ad53aa437d508f460a42a +a310091472b5b42b02176b72d5f8120bdb173025de24b420e3ca3fb9a386c39092a1d1bb591c6f68ee97a268a7ff9e95 +b23f1bf8bcec9cb5232b407115eead855fd06f5bf86ba322ad61d45460c84f0f36911aba303de788c9a0878207eac288 +ae4c129ad6d08be44690bb84370e48bfd92c5d87940750ee2c98c9a2604456f7f42727ab211989657bb202f6d907df04 +95992057d654f3e189a859346aa9aa009f074cb193b7f5720fa70c2b7c9ce887d886f6cff93fa57c1f7c8eaa187603f6 +ad12d560273963da94151dd6be49c665d7624011c67d54ab41447452a866bc997e92a80bdd9ca56a03528e72c456dc76 +8e4eda72e9cfcaa07265bb6a66d88e9ce3390ae1a6b8831045b36ea4156b53d23724824d0f0bca250ce850c5926fa38f +980fe29c1a267c556532c46130fb54a811944bdfea263f1afcdab248fa85591c22ac26167f4133372b18d9f5cce83707 +a7da9f99ddde16c0eac63d534a6b6776ad89b48a5b9718a2f2331dce903a100a2b7855cf7b257565a326ddc76adc71a5 +8ca854c55e256efd790940cb01125f293e60a390b5bd3e7a60e13ac11a24f350a7eb5ebddfa0a2890905ca0f1980b315 +9440335818859b5e8f180893a8acedceabaaa44e320286506721c639a489b5bfb80b42b28902ee87237b0bd3dd49552a +b9da545a20a5e7d60fd0c376dcaf4b144f5c5a62c8ffa7b250c53ce44be69c4e0d5e4e11422ef90593ae58ae1df0e5d3 +b75852a850687f477849fc51e0479703cd44428671c71bfdd27fe3e7930b97d2fc55f20348ca4e5bc08db2fc16a4f23c +b515081d8d099e4b6253c991ca2d3e42633f5832c64aa8f9cde23cb42c097c2c3717c46c5f178f16c58295f97b2b3fe7 +9506c9902419243e73d3197e407985dd5113f16c6be492651bbbf9576621942710aea74522d6fb56d5b52c6ccdaa4307 +952673ae27462a0f6c9545eede245c2f8e2fd6077b72a71f5672f1a5a02c263bc2a66f24f0e30376feb7a8187b715f08 +a8f1e2085ed666a8f86b474d9589dc309d5c83bd53e745f8e09abe0dfbaf53e5384c68580672990344d4aa739438b4d8 +ad6e04d4a67a5a5529ceaf7de6e19416be5b4c436610aa576ac04aee3b73317da88f891121f966393a37f52b775a2dd8 +a35a884736f08c7f76923ae7adb17fdac04e6c505178bca9502eaa2ed16d4d93fa953fb6dcf99e9e9962a6eb3eeead00 +b8af72273360bab4b3ca302cf0659717cbfb335fbc9ad4ffdd3340113ece9e63b2bdbd611e5f6b740a4689286f9a452d +b1a1f4ba2640800c3ed3892e049f6e10f8a571efa3bbe21fe2d6cee8fded171c675a3bb8aa121e2d1d715de84bad2e2b +8102a6c3598b40da4d6e8eccfdd5dadc8d6262e38b69c5b211b0732f4c6e3045d79fba12770a0b2b66f1e9f4664b1510 +90979587d75bf12819f63832beea7dcbef101f6814bf88db4575bfcd9cf0ea8eceba76d4d6db17630b73b46c1acfe011 +8dd98f14d2beb5b5b79cc30f6825ec11ed76bd5a8864593ffc0c2baffab6872bad182e1c64b93aab8dd5adb465fa5cec +8083334dadc49c84f936c603a2857f174eda5659ab2b7214572f318aba3ebd7b1c50e7cbea57272b9edf106bd016df3b +a634d08d2e8641b852e89d7ccab1bab700c32fb143bcbea132f2a5fb2968d74ded2af4107f69818798f0128cc245a8cb +94fc2dccf746d5b3027f7cf4547edf97097cd11db8d6a304c1c2ca6b3aba28c1af17c08d2bbb66f88c14472e0196a45e +b257a6fb01424b35e414c1c002e60487abb3b889d74c60cbdbf591e222739c6f97b95f6962842401f5e2009e91b28c55 +81955bdbf25741f3b85d5044898dc76ae51b1b805a51f7c72a389d3b4d94b2e3e0aa1ec271685bbcf192ed80db7367ab +86eb229b66c542514e42b113b9de7d4f146861a60f2a253264873e7de7da2ac206e156ff11f2de88491b9897174fe2f4 +8b8db00533afbb56b3d7d7a9a4a6af3cebb523699ffcb974603e54f268b3ef739c41cd11850b9651d9640d72217c3402 +8b7cbb72a6c4408d5f1b61001e65de459790444530245d47d4ee8e2d17716695283f21540bd7ac4f5a793a0d00bdf1d4 +875920b9bab4bc1712e6af89ae2e58e9928c22095026070b07e338421b554d9f96e549ac3706c6c8d73f502913a27553 +9455d192db7b039b3e8f0bc186c25ff07dfbe90dab911e3c62e3bd636db8019ed712cbb0ecd5cbb9a36c11034e102aba +8cb0b28e5d3838d69f6c12274d6b1250f8843938065d0665b347977fa3c1c685caef6930bae9483ed0d0a67005baad76 +94df2e14aae1ae2882ab22a7baf3dc768c4a72b346c2d46bfd93d394458398f91315e85dc68be371f35d5720d6ca8e11 +aacd94b416bfbeb5334032701214dd453ad6be312f303b7bec16a9b7d46ab95432a14c0fbf21a90f26aafb50ec7bb887 +b43d26963665244633cbb9b3c000cacce068c688119e94cc0dac7df0e6ee30188e53befff255977788be888a74c60fc2 +b40d67c9ad0078f61e8744be175e19c659a12065fe4363b0e88482b098b2431612e7c2fa7e519a092965de09ceafe25c +82cd4a4e547c798f89ce8b59687614aa128877e6d38b761646d03dc78f6cdd28054649fb3441bcd95c59b65a6d0dd158 +a058e9700f05cef6e40c88b154d66a818298e71ae9c2cf23e2af99a0a7dc8f57fbe529d566cb4247432e3c1dee839b08 +95c6f84406466346c0b4a2a7331ac266177fb08c493d9febb284c5ca0b141ccc17aa32407f579666b208fb187c0227dd +905d1d47a26b154f44d7531c53efbc3743ff70bd7dba50c9b9d26636767b0ae80de3963c56d4604399126f4ad41a0574 +83dfa11c520b4abaefe1b2bc1ce117806e222f373cd4fb724f3c037c228e3379d27a364e68faa73984ba73a0845f1b9a +a16e54786ba308a9c0241aff8f1bf785dece387d93bd74aa31de0969e3431479e2c0abebff9939a6644d2b0af44f80bb +81ac565212365176f5be1c0217f4e7c9fdbc9fe90f16161367635d52edcf57af79290531d2e8b585e1223d33febd957d +a296f4b09915e5d80ff7274dc3ffc9b04f0427e049ea4ef83dca91095275e8a260ef0335c7b6585953b62682da8c8e99 +a9150626208168a21ae871192ca9f11c1f7f6e41e8e02de00732de2324d0d69fe52f8762155c9913ee408a034552e49a +a42a56008ca340c6e9ff5a68c8778bb899ba5de9e7508c0cac355c157979a7ff6a6bd64f98b182114d3831cfa97ee72b +a4f05adf22c051812279258eea9eb00956b04ef095f2ca175f775ff53c710fb0020266adabd1dacaee814c4f1d965299 +967492e78ac0bceb8ad726ea0d2292b760043d16d64a6b1bb896e32630a7bf405c2b20e4e00842ae519a21697ff8db2d +adbf05e9b5931ae3dd24d105b5c523c221a486a4123c727069b9e295a5bc94f3e647a3c2cde1f9f45dbd89df411453c9 +a1759c0ebebd146ee3be0e5461a642938a8e6d0cdd2253ebd61645b227624c10c711e12615cd1e7ea9de9b83d63d1a25 +a4c5945d635b9efc89ad51f5428862aefe3d868d8fb8661911338a6d9e12b6c4e5c15a25e8cb4a7edc889b9fa2b57592 +aff127675ea6ad99cb51c6e17c055c9f8fd6c40130c195a78afdf4f9f7bc9c21eed56230adb316d681fc5cacc97187da +9071294e8ff05b246ff4526105742c8bf2d97a7e7913f4541080838ecfd2dbc67c7be664a8521af48dbc417c1b466a85 +990880b0dd576b04f4b4ce6f0c5d9ff4606ec9d3f56743ac2f469ac6a78c33d25c3105cf54f675e300ac68073b61b97a +a8d1a62ce47a4648988633ed1f22b6dea50a31d11fdddf490c81de08599f6b665e785d9d2a56be05844bd27e6d2e0933 +8ea5a6c06f2096ded450c9538da7d9e402a27d070f43646533c69de8ea7993545673a469c0e59c31520e973de71db1b4 +99d3a098782520612b98a5b1862ae91bcb338ab97d1a75536e44b36a22885f1450a50af05c76da3dd5ca3c718e69fdd4 +b987451526e0389b5fe94c8be92f4e792405745b0a76acd6f777053d0809868657ba630aa5945f4bd7ce51319f8996f7 +afffccc5ddd41313888a4f9fee189f3d20d8b2918aa5ad0617009ea6d608e7968063c71bd5e6a1d7557880d9a639328d +8ac51a02505d5cadfd158dde44932ab33984c420aeceb032ed1ee3a72770d268f9e60ccf80ce8494dfc7434b440daafd +b6543e50bd9c6f8e0862850c3d89835ddd96231527681d4ab7ae039c4a3a5a0b133a6d40cdb35c8a6c8dbb8d421d3e2b +a2ba901f4fde2b62274d0c5b4dbbea8f89518571d8f95ec0705b303b91832f7027704790a30f7d9d2cdafde92f241b3e +a6974b09280591c86998a6854a7d790f2a6fbe544770e062845cfc8f25eb48c58f5dfb1b325b21f049d81998029ad221 +890baeb336bbf6c16a65c839ffaab7b13dd3e55a3e7189f7732dbcb281b2901b6d8ba896650a55caa71f0c2219d9b70e +b694211e0556aebbe4baf9940326e648c34fda17a34e16aa4cefd0133558c8513ffb3b35e4ee436d9d879e11a44ec193 +97cf9eb2611d467421a3e0bfe5c75382696b15346f781311e4c9192b7bca5eb8eaf24fa16156f91248053d44de8c7c6f +8247f88605bd576e97128d4115a53ab1f33a730dc646c40d76c172ca2aa8641c511dddad60ee3a6fbe1bb15cac94a36c +ae7ecd1c4a5e9e6b46b67366bc85b540915623a63ab67e401d42ca1d34ae210a0d5487f2eef96d0021ebecfd8d4cd9a8 +aec5123fff0e5d395babe3cb7c3813e2888eb8d9056ad4777097e4309fb9d0928f5c224c00260a006f0e881be6a3bf8f +8101724fa0ce7c40ea165e81f3c8d52aa55951cc49b4da0696d98c9fafd933e7b6c28119aa33f12928d9f2339a1075d1 +a8360843bab19590e6f20694cdd8c15717a8539616f2c41a3e1690f904b5575adb0849226502a305baefb2ead2024974 +ade5cad933e6ed26bba796c9997b057c68821e87645c4079e38e3048ea75d8372758f8819cde85a3ab3ab8e44a7d9742 +ab1fe373fb2454174bd2bd1fe15251c6140b4ac07bda1a15e5eabf74b6f9a5b47581ef5f0dbd99fdf4d1c8c56a072af7 +b425e1af8651e2be3891213ff47a4d92df7432b8d8ea045bb6670caf37800a4cd563931a4eb13bff77575cbcae8bc14f +b274799fe9dd410e7aed7436f0c562010b3da9106dc867405822b1e593f56478645492dbc101a871f1d20acf554c3be6 +b01a62a9d529cc3156bc3e07f70e7a5614b8d005646c0d193c4feb68be0b449d02b8f0000da3404e75dbdfa9ca655186 +878b95e692d938573cdb8c3a5841de0b05e5484a61e36ea14042f4eadb8b54a24038d2f09745455715d7562b38a8e0df +a89e998e979dba65c5b1a9000ad0fd9bb1b2e1c168970f2744982781306bbe338857e2fac49c8cafda23f7cc7c22f945 +85880fdf30faed6acce9973225e8fe160e680a55fc77a31daacf9df185453ad0c0552eb3fd874698ad8e33c224f7f615 +ac28d20d4bbb35ba77366272474f90f0ed1519a0e4d5de737adee2de774ccd5f115949e309e85c5883dbc63daaa6e27b +a1758ac86db859e323f5231ad82d78acbe11d53d3ebf7e644e581b646eede079d86f90dc23b54e5de55f5b75f7ea7758 +ae4c0b84903f89353bf9a462370f0bf22c04628c38bb0caae23d6e2d91699a58bd064e3c2b1cbda7f0a675d129f67930 +95f21a099ffc21a0f9064d9b94ce227b3ff0a8c5a2af06ff5ee6b7f3248a17a8ca2f78cd7929ef1d0784f81eddefcd48 +8d06fbc1b468f12b381fd1e6108c63c0d898ddf123ea4e2e1247af115043c4f90b52796076277b722dd2b92708f80c21 +a300f39039d8b2452e63b272c6d1f6d14a808b2cd646e04476545da65b71a6e29060f879409f6941c84bde9abe3c7d01 +adecce1ccc5373072ba73930e47b17298e16d19dbb512eed88ad58d3046bb7eec9d90b3e6c9ba6b51e9119cf27ce53f2 +941a7e03a64a2885d9e7bee604ddc186f93ff792877a04209bbee2361ab4cb2aed3291f51a39be10900a1a11479282ca +acbcb1ab19f3add61d4544c5e3c1f6022e5cc20672b5dc28586e0e653819bdae18cda221bb9017dfaa89c217f9394f63 +b8d92cea7766d3562772b0f287df4d2e486657b7ab743ed31ec48fdc15b271c2b41d6264697282b359f5cb4d91200195 +957360ecb5d242f06d13c1b6d4fcd19897fb50a9a27eb1bd4882b400dc3851d0871c0c52716c05c6c6cf3dee3d389002 +abd2a23abbc903fbb00454c44b9fb4a03554a5ef04101b2f66b259101125058346d44d315b903c6d8d678132f30b1393 +ae9572beff080dd51d3c132006107a99c4271210af8fbe78beb98d24a40b782537c89308c5a2bddfdfe770f01f482550 +82c7e5a5e723938eb698602dc84d629042c1999938ebd0a55411be894bccfb2c0206ac1644e11fddd7f7ab5ee3de9fdc +aba22f23c458757dc71adb1ce7ef158f50fdd1917b24d09cfc2fbbcbe430b2d60785ab141cf35ad9f3d0a2b3e2c7f058 +8eff41278e6c512c7552469b74abedf29efa4632f800f1a1058a0b7a9d23da55d21d07fdbb954acb99de3a3e56f12df6 +8abd591e99b7e0169459861a3c2429d1087b4f5c7b3814e8cee12ecc527a14a3bdda3472409f62f49a1eb4b473f92dbf +82dcbff4c49a9970893afc965f1264fcab9bae65e8fb057f883d4417b09e547924123493501c3d6c23a5160277d22a8e +b5a919fcb448a8203ad3a271c618e7824a33fd523ed638c9af7cfe2c23e3290e904d2cd217a7f1f7170a5545f7e49264 +96d6834b592ddb9cf999ad314c89c09bedc34545eeda4698507676674b62c06cc9b5256483f4f114cd1ed9aaec2fba5e +a4e878cf4976eb5ff3b0c8f19b87de0ef10cd8ec06fe3cd0677bd6be80ba052ff721a4b836841bdffb1df79639d0446c +8e15787a8075fd45ab92503120de67beb6d37c1cc0843c4d3774e1f939ac5ed0a85dad7090d92fa217bd9d831319021b +8506c7fea5a90cd12b68fdbbae4486a630372e6fd97a96eea83a31863905def661c5cdead3cf8819515afe258dbcd4d9 +952ef3bc16a93714d611072a6d54008b5e1bf138fd92e57f40a6efb1290d6a1ffcc0e55ff7e1a6f5d106702bd06807cd +a5f7761fa0be1e160470e3e9e6ab4715992587c0a81b028c9e2cf89d6f9531c2f83c31d42b71fca4cc873d85eba74f33 +b4811f0df11ff05bf4c2c108a48eece601109304f48cde358400d4d2fa5c1fdaaf3627f31cb3a1bdd3c98862b221720d +9207ad280b0832f8687def16ad8686f6ce19beb1ca20c01b40dd49b1313f486f2cb837cfbbf243be64d1c2ab9d497c3f +b18a8c1e6363fadd881efb638013e980e4edb68c1313f3744e781ce38730e7777f0cba70ea97440318d93a77059d4a2b +901faf777867995aac092f23c99c61f97eeadf4ac6bcb7791c67fa3c495947baef494b2aace77077c966c5d427abbf92 +a123281aca1c4f98f56cff7ff2ae36862449f234d1723b2f54ebfccd2740d83bd768f9f4008b4771e56c302d7bfc764f +8cffe1266468cad1075652d0765ff9b89f19b3d385e29b40f5395b5a3ad4b157eed62e94279ac3ec5090a6bad089d8b3 +8d39870719bc4ebbcecba2c54322111b949a6ed22bda28a6cea4b150272e98c9ded48cc58fc5c6e3a6002327856726ec +b3d482c00301f6e7667aaeaf261150b322164a5a19a2fa3d7e7c7bf77dc12fa74f5b5685228ab8bf0daf4b87d9092447 +801acb8e2204afb513187936d30eb7cab61f3fbb87bfd4cd69d7f3b3ddba8e232b93050616c5a2e6daa0e64cef6d106f +ac11e18adda82d2a65e1363eb21bda612414b20202ecc0e2e80cc95679a9efa73029034b38fd8745ce7f85172a9ab639 +b631d6990d0f975a3394f800f3df1174a850b60111567784f1c4d5bba709739d8af934acfa4efc784b8fc151e3e4e423 +aeda6279b136b043415479a18b3bbff83f50e4207b113e30a9ccfd16bd1756065fc3b97553a97998a66013c6ac28f3d8 +8840b305dc893f1cb7ad9dd288f40774ec29ea7545477573a6f1b23eaee11b20304939797fd4bcab8703567929ce93ad +963cc84505a28571b705166592bffa4ea5c4eeafe86be90b3e4ae7b699aaaca968a151fe3d1e89709fe0a3f0edf5d61a +8e1ec0d0e51f89afea325051fc2fa69ab77d6c7363cc762e470a9dfa28d4827de5e50f0b474c407b8c8713bad85c4acd +909f313420403cb36c11d392cf929a4c20514aa2cb2d9c80565f79029121efd5410ef74e51faba4e9ba6d06fcf9f1bd1 +b2992b45da467e9c327ac4d8815467cf4d47518fc2094870d4355eb941534d102354fbda5ab7f53fbf9defa7e767ca13 +9563b50feb99df160946da0b435ac26f9c8b26f4470c88a62755cdf57faebeefffff41c7bdc6711511b1f33e025f6870 +a2a364d9536cd5537a4add24867deec61e38d3f5eb3490b649f61c72b20205a17545e61403d1fb0d3a6f382c75da1eb3 +89b6d7c56251304b57b1d1a4255cb588bd7a851e33bf9070ee0b1d841d5c35870f359bc0fdc0c69afe4e0a99f3b16ec2 +a8ae1ee0484fe46b13a627741ddcdae6a71c863b78aafe3852b49775a0e44732eaf54d81715b1dca06bb0f51a604b7e2 +b814ecbfbc9645c46fc3d81c7917268e86314162d270aed649171db8c8603f2bd01370f181f77dbcbcc5caf263bedc6c +8e5d7cc8aad908f3b4e96af00e108754915fecebdb54f0d78d03153d63267b67682e72cd9b427839dca94902d2f3cda7 +8fc5ff6d61dd5b1de8c94053aef5861009cb6781efcca5050172ef9502e727d648838f43df567f2e777b7d3a47c235dd +8788eea19d09e42b0e3e35eb9bcd14f643751c80c6e69a6ff3a9f1711e8031bbe82ccd854a74a5cfcf25dda663a49a62 +95d441d8cd715596343182ddcecb8566d47eaa2d957d8aea1313bbed9d643a52b954443deb90a8037a7fa51c88eec942 +a15efd36ef72783ccdc6336ef22a68cc46b1ecec0f660cfe8a055952a974342bf30f08cb808214bce69e516ff94c14c5 +acc084d36907a16de09a5299f183391e597beaf9fa27d905f74dc227701a7678a0f5a5d1be83657de45c9270a287ec69 +b3fd385764356346061570beb760ccf3808619618fd7521eb0feadc55b8153ef4986ff0cbfcbd4153ad4ea566989d72a +91ec6b26725532e8edfda109daa7ce578235f33bd858238dfa2eb6f3cd214115b44cce262a0f2f46727a96b7311d32e1 +96b867ccddb73afe1049bda018c96cfe4083fff5bb499e6a4d9fd1a88a325144f9a08cb0aee310e1bb4f6a5793777e80 +ad10c18465910152676f1bc6a40986119607b5c272488e6422cfda2eb31da741af13a50f5de84037348014a869c8e686 +86ade2dbc4cceb52b84afe1c874d1e3644691284c189761febc4804b520adf60b25817e46f3f3c08d2ab227d00b93076 +998b949af82065c709fc8f63113a9fecdd1367fc84fc3b88857d92321ba795e630ce1396a39c2e056b5acd206ee011d8 +8dec440bbd17b47dfd04e566c2d1b46f9133023b982fdc5eaeae51404bc83a593f8d10c30b24e13aec709549137cae47 +89436ff47431b99f037cddaee08bb199be836587a7db6ed740317888638e5f4bebbb86b80549edff89678fc137dfb40a +a8e9960746769b3f76246c82cd722d46d66625e124d99a1f71a790c01cec842bcf6c23c19cc7011ec972cedf54dc8a4c +980979dafedfd75ff235b37e09e17361cfdda14a5ac3db0b90ed491abfd551916016b2254538da7f4b86ece3038b1b1c +8ec340ca7654720bb9d2f209985439ebbc3f9990ef27e7d7ae366e0c45b4ed973316943122119604ea9a87fc41ebd29f +ab24440a40ab238d8cd811edb3ef99948ae0f33bf3d257b22c445204016cce22b6f06a1ca979fa72a36c4ddedc2b3195 +a1bcd2473ac7cfebfa61c10e56cae5422c6b261a4a1be60b763fcbcdf2eae4ccf80695f09b062b6cf5654dfab0ee62a5 +9027a613ce7bd827110a3a0e63e83f652e9bc7f4ce8da26c38b28ee893fd0c38bdb20f63a33470a73cb77f776244ab4a +86911cc8aeb628197a22bf44d95a0b49afb8332c38857fba8e390c27c527b8b45335e22b0f2e0a3395c16ced3c1ed2e8 +8f0529a330a3e9967dce09357d774715fd305bd9e47b53b8b71a2a1303d390942a835aa02fb865a14cfed4f6f2f33fe6 +b71ec81a64c834e7e6ef75b7f321a308943b4bad55b92f4dbaf46658613cebf7e4b5b1bc7f1cdc5d50d1a2a0690e2766 +98d66aaed9fb92f4c7bb1b488ccbca5e570aa14433028867562a561d84f673ac72e971cbe2cb3cbbb0a702797dc45a7e +8380aa94d96c6b3efd178de39f92f12ca4edd49fe3fe098b2b7781e7f3e5f81ee71d196fb8e260d1d52f2e300e72e7bc +8c36296ff907893ac58cecadd957b29f5508ae75c6cc61b15ae147b789e38c0eace67963ae62eff556221b3d64a257a2 +97e17676cbc0f62a93555375e82422ee49bc7cf56ad6c3d69bb1989d1dc043f9f7113d0ed84616dde310441b795db843 +a952229615534c7e9a715409d68e33086cdaddf0aec51f4369c4017a94ec3d7113a045054d695fb9d7fd335527259012 +817b90958246f15cbd73a9679e10192ca7f5325b41af6388b666d8436706dea94eafffbc3b8d53057f67ad726dbcd528 +95776e378c8abd9223c55cd6a2608e42e851c827b6f71ad3d4dc255c400f9eccf4847c43155f2d56af0c881abef4acfa +8476c254f4b82858ecbe128ed7d4d69a6563fd9c5f7d4defc3c67e0bfa44e41cfd78b8e2a63b0773ce3076e01d3f6a7d +a64b0b189063d31bcae1d13931e92d5ab0cfc23bf40566ac34b5b8b711d0e7d941102e6beb140547512e1fe2d9342e6c +9678460acff1f6eae81a14d5c8049cdcd50779a8719b5c5861762a035b07f7fa1b1ada8b6173f9decf051fd5a55bebd8 +88398758ce86ed0388b13413a73062adb8a026d6b044cd1e7f52142758bed397befee46f161f8a99900ae6a2b8f6b89f +a7dfaf40637c81d8b28358b6135bd7ad9cc59177bd9bc8e42ba54d687d974cdf56be0457638c46b6a18ceaa02d3c53f3 +b0e885e5d48aa8d7af498c5e00b7862ed4be1dad52002f2135d98e8f2e89ca0b36cf95b3218aad71d5b4ada403b7045b +803b0e69a89e8de138123f8da76f6c3e433402d80d2baba98cde3b775a8eda4168530a49345962c4b25a57257ba9f0a7 +8ce6ef80dadb4b1790167fbc48be10ef24248536834ff2b74887b1716c75cb5480c30aa8439c20474477f1ac69734e61 +824764396e2b1e8dcc9f83827a665ef493faec007276f118b5a1f32526340b117c0df12bea630030a131bf389ec78fc3 +874edb379ce4cc8247d071ef86e6efbd8890ba6fcb41ea7427942c140347ebf93e8cf369d1c91bd5f486eb69b45bce70 +adadcb6eb4cafa1e2a9aef3efb5b09ffa2a5cf3ce21f886d96a136336be680dabc0a7c96ec327d172072f66d6dcdbb39 +b993591b280e1f3527f083d238a8f7cf516d3cf00c3690d384881911c1495192a419b8e37872a565ce8007eb04ebe1b6 +b125faaeca3f0b9af7cb51bb30a7c446adbb9a993b11600c8b533bff43c1278de5cdda8cb46a4df46f2e42adb995bce8 +a7efe1b57326b57c2c01720d4fdf348d6a84d35f229d32a8f2eb5d2be4e561ef8aea4d4d0bcfcbf17da10a8e49835031 +a6bd4f5a87574b90a37b44f778d5c7117d78eb38f3d7874bad15ae141b60eed4ab0a7281ed747297f92e0b3fe5f9cafa +94b5e3067ca1db3c4e82daf6189d7d00246b0360cb863940840358daa36cb33857fde4c01acd0457a90e15accee7d764 +a5ff3ab12197b8a07dd80222a709271ab3b07beba453aacbaf225cfb055d729e5a17a20f0ff9e08febf307823cba4383 +a76dd8aa2b6a957ed82ecec49b72085394af22843272f19360a5b5f700910c6ec65bf2a832e1d70aa53fd6baa43c24f6 +8dfcbe4143ae63c6515f151e78e6690078a349a69bb1602b79f59dc51dea7d00d808cf3e9a88b3f390f29aaae6e69834 +8c6134b95946a1dd54126952e805aeb682bc634c17fe642d5d3d8deffffd7693c90c4cd7d112890abfd874aa26736a93 +933531875561d327c181a2e89aaaac0b53e7f506d59ef2dfc930c166446565bd3df03bab8f7d0da7c65624949cfbae2f +ac6937c5e2193395e5bb69fd45aa6a9ae76b336ea7b6fd3e6aeac124365edcba7e918ec2c663fb5142df2f3ad03411a6 +a8f0f968f2a61d61d2cf01625e6ac423b447d3e48378ea70d6ff38bc98c42e222fe3cbcb04662b19973a160dc9f868a2 +94100a36f63d5c3a6cfb903c25a228389921684cc84f123390f38f90859f37ec9714942ffe6766f9b615101a3c009e43 +b5321b07f5b1eb2c1c20b0c8ab407f72f9705b55a761ec5176c5bcc6e585a01cae78546c54117ca3428b2b63793f2e65 +9922f61ed6763d1c4d12485c142b8ff02119066b5011c43e78da1ee51f10a1cf514329874061e67b55597ca01a7b92ab +a212eb2d72af0c45c9ef547d7c34ac5c4f81a4f5ec41459c4abd83d06ec6b09fdab52f801a2209b79612ae797fa4507b +8577d2d8f17c7d90a90bab477a432602d6918ca3d2af082fbb9e83644b93e21ca0bced7f90f6e9279eaa590f4e41dc4d +9002d424e3bebd908b95c5e6a47180b7e1d83e507bfb81d6ad7903aa106df4808c55f10aa34d1dccad3fab4d3f7a453e +b9050299bf9163f6ebeff57c748cb86f587aea153c2e06e334b709a7c48c4cbfba427babf6188786a0387b0c4f50b5ce +852ae1195cc657c4d4690d4b9a5dea8e0baaa59c8de363ba5fccd9e39ec50c6aa8d2087c8b7589b19248c84608f5d0a8 +a02ff5781417ca0c476d82cf55b35615f9995dc7a482124bc486e29b0b06a215fbe3e79228c04547c143d32cd3bac645 +8d7bc95e34bc914642e514a401448b23cf58bce767bab1277697327eb47c4a99214a78b04c92d2e3f99a654308b96e34 +adb28445d3b1cc7d4e4dd1f8b992a668f6b6f777810465fdab231fd42f06b5bada290ba9ae0472110366fad033da514e +a0c72b15a609f56ff71da17b5b744d8701af24b99fbc24a88588213864f511bfa592775e9ab4d11959f4c8538dc015b8 +933205a40379d5f5a7fb62cda17873fbbd99a0aaa8773ddf4cd2707966d8f3b93a107ebfe98b2bb222fe0de33ef68d03 +90690c1a4635e2e165773249477fc07bf48b1fd4d27c1b41a8f83a898c8d3763efb289867f8d6b0d354d7f4c3f5c7320 +99858d8c4f1be5a462e17a349b60991cb8ce9990895d6e42ae762ce144abc65b5a6f6e14df6592a4a07a680e0f103b2a +b354a7da06bd93fb5269e44925295b7c5049467b5cacce68cbb3cab60135b15e2010037a889cb927e6065053af9ccb77 +af01fc4ac396d9b15a4bbd8cc4fe7b30c32a9f544d39e88cdcb9b20c1c3056f56d92583a9781ddb039ec2eeda31fb653 +a8d889fb7155f7900982cf2a65eb2121eb1cc8525bbee48fae70e5f6275c5b554e923d29ebbd9772b62109ff48fb7c99 +b80edae6e26364c28749fd17c7c10eb96787053c7744a5cc6c44082ae96c5d3a4008c899a284f2747d25b72ecb9cb3d0 +b495b37503d77e7aafc226fca575e974b7bb6af2b7488372b32055feecc465a9f2909729e6114b52a69d8726e08739cb +a877f18b1144ff22e10a4879539968a01321cecde898894cbe0c34348b5e6faa85e1597105c49653faed631b1e913ec7 +8c235c558a065f64e06b4bb4f876fe549aab73302a25d8c06a60df9fad05843915ac91b507febca6fe78c69b51b597de +b4c31398b854ccc3847065e79329a3fdae960f200c1cce020234778d9c519a244ff1988c1fbc12eb3da2540a5fa33327 +b7bd134b3460cb05abf5aed0bc3f9d0ccbfac4647324bedbdf5011da18d8b85dc4178dd128f6ddbe9d56ea58f59d0b5d +92594c786c810cf3b5d24c433c8a947f9277fe6c669e51ceb359f0ae8a2c4e513a6dad1ae71b7ded3cdca823a51e849b +b178535e043f1efcce10fbec720c05458e459fdda727753e0e412ef0114db957dc9793e58ec2c031008e8fb994145d59 +b31da7189abf3e66042053f0261c248d4da142861bfd76a9aced19559be5284523d3e309ef69843772b05e03741a13fe +b190a8c1a477e4187fecff2a93033e77e02de20aae93dda1e154598814b78fdf8b9ff574c5f63047d97e736e69621462 +98234bd1d079c52f404bf5e7f68b349a948ec1f770c999c3c98888a55d370982bfa976e7e32848a1ebb4c7694acc1740 +99b9eeb33a6fb104bba5571a3822ebe612bf4b07d720d46bde17f0db0b8e8b52165f9b569be9356a302614e43df3e087 +a1e3915b0dd90625b424303860d78e243dda73eecd01cba7c33100b30471d0a1ec378c29da0f5a297008b115be366160 +975118bf6ca718671335a427b6f2946ee7ece2d09ccfb1df08aa1e98ff8863b6c8b174c608b6b2f4b1176fb3cbc1e30d +903cb1e469694b99360a5850e2ca4201cad23cfccce15de9441e9065eb3e6e87f51cba774ab9015852abd51194c25e57 +821f7ff4d0b133e3be4e91d7ff241fa46c649ff61fc25a9fdcf23d685fe74cf6fade5729763f206876764a3d1a8e9b24 +a1ee8db859439c17e737b4b789023d8b3ce15f3294ec39684f019e1ea94b234ec8a5402bc6e910c2ed1cd22ff3add4de +af27383148757bdf6631c0ea8a5c382f65fc6ab09f3d342a808ca7e18401e437cd1df3b4383190fdf437a3b35cbcc069 +8310551d240750cef8232cd935869bad092b81add09e2e638e41aa8a50042ce25742120b25fb54ebece0b9f9bdb3f255 +8b1954e0761a6397e8da47dc07133434ebe2f32c1c80cd1f7f941f9965acdf3d0c0b1eb57f7ff45a55697d8b804e1d03 +8c11612381c6be93df17851d9f516395a14a13c7816c8556d9510472b858184bf3cc5b9d14ded8d72e8fb4729f0b23ba +b413ac49121c7e8731e536b59d5f40d73a200c4e8300f8b9f2b01df95a3dc5fe85404027fc79b0e52946e8679b3a8e43 +8451e5c1c83df9b590ec53d1f1717d44229ed0f0b6e7011d01ea355d8b351f572866b88032030af372bd9104124df55a +8d0a5c848ec43299bc3ea106847ed418876bc3cd09b2280c2a9b798c469661505ed147a8f4ffba33af0e1167fdb17508 +a6aa97a1f10709582471000b54ec046925a6ad72f2b37c4435621c9f48026d3e332b8e205b6518f11b90b476405960a9 +97696635b5a2a6c51de823eea97d529f6c94846abb0bd4c322b108825589eba9af97762484efaac04ee4847fb2fb7439 +92fd142181fe6ca8d648736866fed8bc3a158af2a305084442155ba8ce85fa1dfb31af7610c1c52a1d38686ac1306b70 +ae3da824ecc863b5229a1a683145be51dd5b81c042b3910a5409ca5009ba63330e4983020271aa4a1304b63b2a2df69e +aecc0fe31432c577c3592110c2f4058c7681c1d15cd8ed8ffb137da4de53188a5f34ca3593160936119bdcf3502bff7c +821eac5545e7f345a865a65e54807e66de3b114a31ddeb716f38fe76fdd9d117bee0d870dd37f34b91d4c070a60d81f4 +91a02abb7923f37d9d8aa9e22ded576c558188c5f6093c891c04d98ab9886893f82b25b962e9b87f3bf93d2c37a53cb9 +99a96f5d6c612ee68e840d5f052bf6a90fecfd61891d8a973e64be2e2bdd5de555b1d8bffbd2d3c66621f6e8a5072106 +b1d5ec8f833d8fbb0e320ff03141868d4a8fff09d6a401c22dbefadbb64323e6d65932879291090daf25658844c91f2e +a06afd66ebc68af507c7cf5ab514947ca7d6ccc89fb2e2e8cb6e5ae0f471473e5fba40bb84d05f2c0f97c87f9a50cb73 +83de3ca182bcf1eac0cc1db6ad9b1c2a1ecd5e394e78add7faa36e039a1b13cb0d1d2639892489df080fbf43e5cef8d5 +adf77fc7b342ff67a2eddaa4be2f04b4e6ceaca8ea89a9fc45cc892fcce8ac3cf8646cfa5aab10ac9d9706ce4c48a636 +8509a430ef8dc9a0abc30ef8f8ccdb349d66d40390fb39f0d3281f3f44acb034625361270162822ef0743d458a82b836 +8350fc09e8617826f708e8154a3280d8753e7dbbcf87e852f9b789fdbeb10bf3fed84fb76edd7b8239a920c449e2f4b7 +a2e7a29da8391a5b2d762bf86cb6ae855cdfad49821175f83f4713dd0c342a0784beba98d4948356985a44d9b8b9d0f7 +a99c50a1a88b8efe540e0f246439db73263648546d199ef0d5bc941524a07d7e02b3ef6e5b08dc9e316b0b4c6966823e +b34ba55136c341f4ca2927080a07476915b86aa820066230903f1f503afebd79f2acf52a0bc8589b148d3a9a4a99f536 +af637be5a3e71c172af1f2644d3674e022bc49c393df565ea5b05ce6401a27718c38a9232049dd18cbd5bf4f2ce65b32 +a2972ba7bfa7f40c2e175bb35048a8ef9bc296d5e5a6c4ca7ab3728f4264d64f2d81d29dce518dc86849485ff9703d7d +8c9db203e8726299adeb331d6f4c235dc3873a8022138d35796fb7098887e95e06dcfad5d766ceaa2c4fb0f8857f37fa +a82bfbaa9a6379442109e89aad0c0cfc6a27d4a5db5480741a509d549c229cb847b46a974dde9f1398c6b3010530f612 +b2d8ef6e091a76dfc04ab85a24dbe8b5a611c85f0ed529a752c2e4c04500de5b305c539d807184e05f120be2c4a05fc3 +8c6ffc66a87d38cea485d16ee6c63ce79c56b64ae413b7593f99cc9c6d3cd78ef3fa2ab8a7943d2f0e182176642adadb +acbc92de68b2b04e3dc128109511a1cbe07518042f365d5634e8b651cb1ac435ea48eeeb2b921876239183096ef6edee +979c4e1165e0ecfa17ed59fb33f70797e000ddbb64acf5fc478cccde940451df051e51b6449c5b11a36afa7868af82e3 +a5a017c5a94952aeae473976027124231abe50460cec4db3ebeb8b1290525776be7c15d108b749c2a1e4b018de827915 +8b6922ab1db925eed24b2586e95f5c709b79d2408a8fa2a71057045ead3ebdd0cc72bee23d9064cd824166eda1e29318 +89a991087a0b5805fcc5c6c5f6ac27e100da0d3713645aa9c90114e68ca9f185f21155eb7645a2c6c0616a47291fe129 +ae6ef954c942cbfd37f8f2dc58a649e2584d6777e7eb09ae6992ccde283ac4f4ec39e3a5cda7f7c60f467fb308d37f08 +9335ca5ccac59b39eb2bcef09c54b778ebb690415ba13fe5c8e4b6091d9343a01cc9baa6228cefd8dba98f0710f714da +a0211c9328be2b46f90ff13614eeffb4c1285e55580db3874610653219926af1d83bda5b089fd37a7c7440a0f1d94984 +a82e097dfa782c40808fac5d8ed1c4fccf6b95ef92e22276fd8d285303fcf18c46d8f752595a658ee5294088b9dc6fc0 +ad108fcd0ead65f7f839a1337d520f5bd0cb665ee7100fc3f0563ff1d2959eb01617de8eb7a67c9b98b7b4892082acdb +b89e6aeabcb3ee3cbf12e3c836bab29e59d49676bcf17a922f861d63141076833f4149fe9e9c3beed24edfacdf1e248b +8477501bd91211e3b1f66c3bfd399ef785271511bc9366366ce95ec5ea95d9288ab0928a6b7887aba62de4da754d3eaf +aeec40c04b279096946b743ad8171bf27988405e1321c04894d9a34e2cbd71f444ff0d14da6cda47e93aa6fe9c780d50 +a703bd2d8a5c3521a8aad92afef5162aed64e9e6343d5b0096ca87b5b5d05e28ed31ba235ab1a626943533a57872dd01 +b52d9dfc12c359efb548d7e2b36ddedaefdec0ef78eda8ac49a990b3eb0ed7668690a98d4d3c7bec4748a43df73f0271 +af887c008bad761ee267b9c1600054c9f17f9fc71acfe0d26d3b9b55536bca5c8aebe403a80aa66a1e3748bb150b20ef +ad2f7a545ef2c2a2978f25cf2402813665c156bab52c9e436d962e54913c85d815f0ba1ce57f61e944f84d9835ce05ea +91a0a9b3cfd05baf9b7df8e1fb42577ec873f8a46bb69a777a6ac9f702735d6e75e66c9257822c781c47b9f78993a46b +939fdc380fb527f9a1ddecf9c9460f37e406cd06c59ce988e361404acbfcb6379f2664a078531705dbc0c375d724137b +8bbbe5d5a0d102b8e0c8a62e7542e13c8c8a6acb88859e78d8e1d01ec0ddff71d429fcb98099e09ff0aa673c8b399dc4 +b67a70e4ef138f48258f7d905af753c962c3cc21b7b8ae8b311a2356c4753f8cd42fdee09ac5ed6de31296ead88c351a +8d21539e7dca02a271ce7d16431773bbe30e6a03f5aff517132d34cdd215ad0da2f06aa4a2a595be489234b233e0852e +892ae11513f572cc5dc8b734b716bb38c0876e50e5e942631bb380b754e9114c34b0606740301e29b27d88439fb32071 +a8780dc9faa485f51b6f93a986bc4e15b166986b13d22ec2fefc6b25403b8b81c15cc9ac0025acc09d84932b15afa09b +b01af013360cd9f2bb9789a2b909c5e010fe6ff179f15997dee1a2ba9ef1ccec19545afdecfcb476f92fcdd482bb2b5a +b5202e5d5053d3af21375d50ad1ccd92538ef9916d17c60eb55c164767c3c74681886297b6f52e258c98d0304d195d3d +8f6adbcfbb0734bf3a4609d75cf2e10f74ed855a8b07cf04ac89a73d23b2e3e5cf270a1f2547b3d73e9da033a3c514b0 +8abe529cd31e4cb2bd75fa2a5e45bd92cbe3b281e90ffc7dea01ba0df17c9a3df97a3fde373cce5d25b5814cf1128fed +b8bbf51187bb3bb124da3870e2dfecb326f25a9383e5cc3323813487457010b9055811669c3da87105050825dc98a743 +a5c83875fe61ebbdd3fd478540d7e5a1ad0f8c790bad0b7dd3a44831e2c376c4fffbc6b988667afa1b67bfaa2dbbb256 +a0606b3062e4beba9031ba2a8e6e90aa5a43ba7321003976e721fd4eedb56486f2c5b10ba7a7f5383272f4022092eacb +b485cc5e001de6bd1bbc9cd8d777098e426d88275aaa659232f317352e1ddff3478262d06b46a573c45409bc461883e1 +916449580b64a9d8510e2f8c7aee0b467a0e93b11edc3d50725bcbc3ca53c2b8bb231fdc0fc0ed5270bf2df3f64750d9 +b2e687caa9f148c2b20a27a91bada01a88bff47faaf6ed87815db26bb6cdd93672199661654763a6b8b4b2012f59dcca +b6933f7f9dabc8fb69197571366ac61295160d25881adf2fcc8aaabc9c5ed7cf229a493fd9e2f1c2f84facd1f55fee84 +b01eb8b2cf88c75c3e31807cfc7a4d5cafded88b1974ba0a9d5aaeda95a788030898239e12843eda02873b0cabe30e2b +a3ca290fa6ce064514a3431b44ecdb390ef500629270202041f23bc2f74038147f338189c497949fb3126bae3a6e3524 +93b0f8d02bd08af74918b1c22131865aa82aba9429dc47f6b51354ba72e33a8b56684b335a44661aa87774931eb85974 +81eebeb9bd92546c37c98e0a5deba012c159f69331a89615cf40c5b95c73dcdbf3ceb46b8620d94ff44fcdad88020c1e +b350e497932382c453a27bb33d2a9e0dbadf4cd8a858b6b72d1f3a0921afc571371e22b051b97da3bb08694c4ca3a4e8 +8c7052f63ba16f14fa85d885aa857d52f04b3a899a4108493799c90c0410de7549be85bec1f539f1608924668df48e5a +b397574d1fb43de0faaea67d1d9348d67b712b1adce300d6dc497bca94e0994eef8707c285c5c9ac0a66022655a8420b +a934661d2168ae1bd95b1143c2e5c19261708aeb795abad8ec87f23dc1b352fa436de997ebb4903d97cb875adb40dc2b +acf535fa1b77255210e1b8975e0e195624c9e9ffd150286ccd531a276cadc12047a4ded6362977891e145a2bd765e6b9 +8cc32356015d7fd29738dcc13c8008cdbe487755dd87d449ab569c85d0556a1ec520dbce6c3698fc413d470c93cb0c92 +8787c7b3b890e0d3734ac1c196588cacf0a3bde65e2cf42e961e23dbf784eef14c07337d3300ed430f518b03037bd558 +99da90994030cbc2fb8a057350765acac66129a62514bbd3f4ec29d5aab8acdd5f4d69ca83efe7f62b96b36116181e79 +a306424f71e8b58dfa0a0564b2b249f0d02c795c30eee5b0ad276db60423210bba33380fb45dbe2c7fedd6ee83794819 +b207a35d31ce966282348792d53d354bbd29ac1f496f16f3d916e9adbf321dc8a14112ca44965eb67370a42f64ca1850 +89e62e208147a7f57e72290eefccb9d681baa505d615ca33325dfa7b91919214646ca9bdc7749d89c9a2ce78c1b55936 +ac2d0ec2b26552335c6c30f56925baa7f68886a0917e41cfbc6358a7c82c1cb1b536246f59638fb2de84b9e66d2e57eb +8f1487659ecc3b383cebc23a1dc417e5e1808e5c8ae77c7c9d86d5ab705e8041ce5a906a700d1e06921f899f9f0ee615 +a58f1d414f662f4b78b86cae7b0e85dfddae33c15431af47352b6e7168a96c1d307d8b93f9888871fc859f3ed61c6efc +94f3626a225ac8e38a592b9c894e3b9168f9cf7116d5e43e570368ee6ee4ab76e725a59029006a9b12d5c19ddce8f811 +b5986e2601ad9b3260e691c34f78e1a015c3286fdd55101dcef7921f6cbcc910c79025d5b2b336d2b2f6fd86ee4e041e +b6e6798ddd0255fbe5cb04a551a32d4c5d21bdfd8444ff2c879afe722af8878d0a3a2fe92d63936f1f63fea2d213febf +86bea9bfffef8bc11758f93928c9fdfae916703b110c61fa7d8fe65653f8c62c6fecd4ff66a1f1a7f3c5e349492e334c +9595a4606284569f4b41d88111320840159fd3b446e00ec8afd7ddaa53dd5268db523f011074a092f8e931fc301a8081 +83b540a6bc119bf604a7db5f6c0665c33b41c365c12c72ca4fa7b0724115bbb0ff1ae38532c3356e8bb3ac551285929f +92c6daf961ca4eb25293e1794cf85cda4333cf1c128207af8a434e7e0b45d365f0f5baaefc4ebd5cd9720c245139c6e2 +b71465f3d7dba67990afc321384a8bb17f6d59243098dbed5abd9a6ffc7a3133b301dd0c6ca3843abbaa51d0953abbed +b15d93482d2ee5b1fec7921fcc5e218c1f4a9105a554220a4fb1895c7b1d7a41f90bbf8463d195eecf919fcbe8738c51 +a79c98e70931ffd64f4dcf7157fbae601a358261e280fe607eb70cef7d87f03efa44cf6ba0f17fbb283a9c8a437d2fdb +9019d51a6873331f8fe04cb45e728a0c8724a93d904522a9915c748360ddf5cdbf426a47b24abf2005295ed2a676cbf0 +b34cc339fec9a903a0c92ce265e64626029497762ff4dcaaf9bb3994298400ce80f4fb7dbe9ec55fe0c4a522c495cb69 +8fda9be7abfe3b2033cad31661432300e2905aef45a6f9a884e97729224887a6ec13368075df88bd75c11d05247bef15 +9417d120e70d6d5ca4b9369cba255805b5083c84d62dc8afec1a716ead1f874c71a98ad102dac4224467178fe3228f62 +a0a06b64867eebb70d3ce8aaa62908a767fb55438a0af3edf9a8249cd115879cde9f7425778b66bb6778cb0afeb44512 +a44309d3e1624b62754a3a4de28b4421f1969870f005ac5dc7e15183fa5b3ad182bcd09cca44924e03fbdb22f92f8cf8 +aea80f1c3a8fc36cfb5c9357d59470915370b2bec05f51f1d0e1d4437657e2303ba2d1ac3f64cf88f2df412dff158160 +b3f1557883d91b24485123d2f3ae0fce65caa533c09345ae6b30d2ac49953acee61c880c57975be7b4f5558d3a081305 +b52cb1e56f0d147cfb58528b29c7a40bab7cfc9365f2409df7299bfc92614269ff9de3cb2500bbc4909f6a56cf4b9984 +aa4f8fd0f5f87c177ee7242f7da76d352db161846cd31523a2100c069d9e4464170eec0bffc6d4da4f9e87017b415dbd +b5b61f52242985c718461a34504f82495d73cbb4bc51f9554b7fe9799491f26826d773656225f52a1531cd5bd6103cde +ad12ba9697804ede96001181c048f95b24ba60761c93fb41f4b4a27e0f361e6b1434e9b61391bacaf0705fdaa4a3a90e +9319286cbda236f19192ae9eb8177e5a57a195c261082ba1385b20328fb83ed438f29d263dddae2f5278c09548830c4a +88b01ee88c3a7ae2c9f80317dddbaa2b7b0c3a3c23828f03ff196e244500410c9ac81c2e2d3e1f609d4b36ee1732738c +8e31f30600a9d629488d44a008c821c3c57f13734eaee5a19f0182a2de9e538fff7d982980d7fcc725c969f29f7c2572 +b215740eea98b4bb14197a803a8975700ad2f25a25ef3628eae10166d56c823301f6dd62ce3f9ebf2d42d1f33d535004 +8fb0fdb253d4bcc6693642779be13a5b816189532763dfd7da868cfacfdb87cb5ebe53b18b69dfd721f8d4baf3c1d22d +8cdd050a447f431ff792156d10381aaf83c6634a94b614dd5b428274538a9cc1f830073533b4fd0a734d6dd4f8d9c4ce +81b01ee8c72ac668ad9dd19ead2d69cac28c3525e613e036e87aa455c2da9651cc8fcc97c451a8c8a071a4eb69623cd1 +8d9e02dc9ac83f861b3745bd69216232144c47cb468a7dbc49083ed961f978e34265b3f42c400339120bdc4644fe5711 +89e9410455b34cba9db0a5ea738e150fae54dd000d61e614f3274a6c8102ba7cd05b0936f484a85711ad9da7946f51ea +91f9d4949678f8e6f4b8499899818bdd0f510da552b5d79d8e09bf3b69d706ab36524b5e86d3251318899b9223debf6b +8b3c38eec7e1926a4be5e6863038c2d38ab41057bcfa20f2b494e9a0c13bc74c3a44c653402eb62a98e934928d0ebccb +a5cfe465bfbf6e8bfbd19d5e2da2fc434bd71acd651371087450c041aa55e3c4f822361e113c6c3d58646ed3ba89d6da +918665b8810bcb8d573ca88b02a02c62eaa5a4a689efb5c564b0c9183f78144e75d91fd1603e17d2c77586cbe5932954 +997dace0b739aeb52ba786faae5bdf1d48630a90321f9ceebfa9e86d189a3d79d7b04e459ac8e4adcfe83a5ce964eb1c +a5a1ca9f0ccc88017a616d481d912aab3f0e154b673f1131c5d9c9c3f5f147d25b6392b2c31e49f7bb7eb2697d05dbec +a76e99bec509eff01bf6767a06ac97ebc6671cb58bc3d4acc2803580a874885453dbba2e1bba26e45f8d2bda5f688860 +956c1362c8123c5d9ebff7049e851235d69fa645f211ef98e2b6564f2871114a12224e0ec676738d77d23c709dd28a6c +885efede83b1a3e96417e9f2858ab0c7a576fc420e8f1f26cabf3b1abeec36bcaa63e535da177847f5e0afdb211bf347 +affca2257f292a2db52f8b1bab350093f16f27ef17e724728eeaec324e2513cd576f6d2e003cc1c6e881334cb2e8bf22 +8dac963d34dcc9d479207a586715e938c232612107bb2d0af534d8da57ad678555d7c1887fadca6551c4f736ffa61739 +b55e600a6bbde81f5a0384f17679d3facb93a7c62ca50c81a1d520cf6e8008ac0160e9763cb2ca6f2e65d93ca458783b +9485e6c5ab2ebfb51498017e3823547b6ab297d818521ceac85cd6c3aa2d85ae075a0a264ae748fc76ce96a601462ffa +b4d8abca786c0db304a6634fba9b2a40d055c737ed0f933e1739354befdae138dae3c8620a44138f50ebeaf13b91929f +8bde7ca39c7bda95b1677a206b16c3a752db76869ea23c4b445c2ff320f2ee01f7358d67a514982ee3d1fb92b7bd7229 +8f8cd0acc689b6403ee401383e36cae5db2ff36fc2311bbadf8ebb6c31cbcc2ca4ffac4c049da5ba387761ef5ec93b02 +a06f42d5f69a566ff959139c707355bbf7aa033c08d853dce43f74a9933e6d7b90e72010ef3fcb3d12e25852343d1d31 +b10ece7cf6b69a76dba453b41049db0cdf13d116cf09c625312b150ee7437abd71d921eda872403d7d7ce7af1e6dccb7 +a3d820318e0f3b54fba7a4567912a82d6e6adf22b67cfc39784683a8e75f77538e793d9708aae228fa48a71abb596195 +8758fad55b68a260bea3bd113e078fd58d64a92f7935ff877f9f77d8adc0994b27040cfc850126c7777cfdfb2428a3e5 +b504913ee96c10f00b848cd417c555a24bc549bf5c7306140eff0af2ada8cb5e76bed1adb188e494332b210fbf24e781 +a00e019a40acc7aab84c1cc27c69920ad7205c2a3dc9e908a7ef59383695c9cb7093c4bcbc2945aab2655119552e3810 +b1000b4c4f306672e39d634e5e2026886a99930d81b8670a5d4046db9621e44997c4b78f583374a09c60995f18a6fd4f +a6c5053c4e748540ad2b622c28896c9d4ca3978ca4784ac8f09da5314a245f5cdc5d6203c84e6e0bcb3081829720a56d +8e37e67a70205a5c7da95de94ac4d0ebd287c1c9922d60c18eec1705030dfcbf74ae179e377c008bf5a8bc29c7c07cce +a66bd7c0243319b553d5cb7013f17e3504216e8b51ba4f0947b008c53bcb6b4979286b614a4a828ee40d58b5ef83e527 +97e2110b0fb485508a2d82ecc2ce1fbe9e12e188f06c7ef2ac81caeeb3aca2c00e5e6c031243b5ca870a9692e1c4e69b +8734ce8bbc862e12bea5f18d8a8d941d7b16a56ef714792fed912ca9c087497e69b6481fdf14efe1f9d1af0a77dac9b1 +b441dddac94a6a6ae967e0e8d7ab9a52eb9525fb7039e42665e33d697e9a39c7dcef19c28932fb3736e5651d56944756 +918b8997f2d99a3a6150d738daed2ff9eb1f5ed4a1c432d18eab4a898297f7ffbffd1e4ae9037acf589b1cd9e1185ef6 +a0247b8ac4d708cf6b398dc2d5c127a291d98e8bef5f195f820c4fddb490574ba4f62647c2d725237a3e4856eec73af0 +b45636e7e0a823c2a32e8529bb06fcccfd88e9964f61201ee116279223ed77458811d1b23bcb6b70508d16d4570a7afb +a99c1188fa22b30b04fda180d2733586ea6ef414618f1f766d240c71f66b453900d3645541c019361027aebe0a0f305f +b4c2f758e27fe233f7e590e8e0c6de88441164da3fcd5211a228318d3066dfdafc1d40246dd194f2b597f6fe9600b3d7 +972530819445b11374c3043d7855d5f1d3c4922b3b205d0bf40162c51605375dd0b61f49cd7f3d39a533a86a13005989 +992b533a13e5d790259bfdfdf1074f84a5e5a0a0d7be9cd6568cdc1662524f1a6666a46da36cea3792ba6707850f4d86 +9875d130457e04dc6ea2607309bfbb900ad3cb5f3e0574f808d27b20cbf6f88389d87dca19998680c5bc30d1df30a41b +adea8494a69e83221edf360ab847272b5c47eba5404665fb743d98c0682732c30085ae3ec82bc1e8e4aba8454c9b1849 +887d4c624ce05e224216c5f6fa13c5741012ac33330bc291754782f0bfe668decdc98c0e43a1ce28323effe6b639f477 +ab6b167aeb5e93ab155990b94895e7e7ff6dea91384854a42cc8a3b9983495b4b3c33ab1b60b2b6450ccf0418fada158 +a7588d0b7c6a6bc32fc474aa0f4e51dfb8e6e010346ad32c59d6f99e6f0522424111a03a4f56ba4075da8009ee7a63e9 +94d645cc3936db1563568193639badfc064dd5bda8d0631804ee00b09e141b200619e07506b5a8225130541436327194 +8d695c03cc51530bdc01ee8afcd424e1460d2c009e1d7765c335368e5c563cf01a2373c32a36400c10e2bf23c185ed19 +ad824a0a7ed5528e1f9992cbb2050785e092b1ea73edd7fb92b174849794a5b04059e276f2941e945bc0f3e46172f2af +ad6ed2af077a495d84f8eeed7d340b75c0d1c8b7c5a854dfc63ab40a3d0c2b0d45016d30b3373a13f0caae549f657976 +82454126c666023c5028599a24be76d8776d49951dfe403ebf9a5739b8eb2480c6934a34010d32cd384c91c62a9aa251 +b57070006793eca9fa2f5237453ed853994ad22c21deb9b835e1fb3fbc5ac73aec265a4a08de7afae1610dc8c42b7745 +ad94667c791cf58875eb77eb17b6ad02de44e4ba2ddc2efe4d0ff22a5e1a090c670354437847349fd61edc4ba5606f07 +b2aac0c345ffc00badaab331c12a22019617b004d32c099c78fa406d683744d96d51d1237ad0842f9f54655186f8f95b +8fed51076cc939b354e3b69034a594e6c9c98425ccf546154ab087a195375128444732388d2eb28f82877de971ec2f58 +8e521c0093deb9dff37888893db8ffebc139984e7701e68b94d053c544c1be0d85f0f98d84b2657933647b17e10a474c +a2c6c9a307aff9b1dea85f90fa9e3b8057fd854835055edeb73842a7ef7c5ae63d97c51fec19dd8f15d696a18a0424a6 +a3390b25a9c11344ed1e8a0de44c848313026067a0f289481673c2c0e7883a8fc9f6cab6ccd9129729a6d8d0a2498dc2 +82770c42b1c67bbd8698c7fe84dd38cc5f2ad69a898097a33b5d7c5638928eb1520df2cb29853d1fa86a0f1bcc1187e8 +a6fdf7a4af67bc4708b1d589135df81607332a410741f6e1cc87b92362a4d7a1a791b191e145be915aa2d8531ee7a150 +aecac69574188afc5b6394f48ba39607fe5bb2aa1bd606bc0848128a3630d7d27101eb2cea1fb3e6f9380353a1bb2acc +a23fd0c52c95d0dffb7c17ec45b79bf48ed3f760a3a035626f00b6fe151af2e8b83561d0b9f042eaae99fde4cbd0788d +a5f98068525cdd9b9af60e0353beb3ac5ac61e6d3bac1322e55c94b3d29909d414f7f3a3f897d5ae61f86226219215c6 +b2a4d724faac0adf0637c303ff493a1d269b2cdbec5f514c027d2d81af0d740de04fb40c07344e224908f81f5e303c61 +adeadb3521e1f32ef7def50512854b5d99552e540ec0a58ea8e601008de377538c44e593e99060af76f6126d40477641 +a18b7fc2fcd78404fed664272e0fef08766a3e2bc2a46301451df158bd6c1c8aa8cf674dd4d5b3dedfaceb9dd8a68ae3 +83bcfb49313d6db08b58c6827486224115ceef01ca96c620e105f06954298e301399cdd657a5ff6df0b0c696feec1a08 +8c94391eba496e53428ec76dfe5fa38f773c55c0f34a567823316522a0664a3d92bff38ec21cf62ac061d7d1030650c5 +b1fa196ccfd7d5f1535b2e1c002b5cde01165c444757c606b9848bc5f11b7960973038fb7cc3da24300fc1848e34c9af +b139f6c6449449638de220c9d294e53fc09865a171756d63bbf28ec7916bf554f587c24bddf51dd44372d15260d8fe25 +b716242299d4ee72b5b218781b38ca5e005dcf52333364f85130615d1dbf56216af8ee2c9c652d82f7aab5345356538c +9909f24e4ad561aa31afd3a3b9456b2bd13a1d2e21e809a66af62fec5f95b504507ac50e81d2233da2b223f5443e7585 +ae863530a02cf3a757f72b945c8c0725d9f634d2ff26233478d1883595ff9a1eef69e8babffdbfa161452fc204f5b5a1 +8eb82bde283b6a6e692b30236cbf41433b03eda8dad121282772edd56f144b1ebf5fb489d18c6ce8776135771cbb91e2 +9296141fadf8dadc885fff4999c36efa25ec76c5637a8300a1a7dc9cf55bcedfe159e0ef33f90eee9be8c4f085734e10 +b6c07f2e6fcbd6c42a8b51e52fbcd5df3aa9f7c3f0b3c31021de1aec2111d0a1c36b5ab489ba126af44fd43cf31c2594 +a70ca669c357535b363d16b240fd9cb9c5ba1b648510afc21218ea034e9bf5f22717ae31ff43ef89dded95b7132fa58f +b350721f8f6b4d164fd08aca30cd4dece9b4a81aed0ac12119c9399bab691d5945814306f9a61f0106b76d4d96f7b9d6 +b6886076c9d8c344bf3fb6975173d00fa82866012894f31c17e6fc784fbc0dd2d24d6a1cddd17f7379c74566a23219aa +87636e4a83ceadc170a4b2517b19525c98e2163900401996b7a995b2f3da8d6ba2ab92f909eade65074fac07cf42f6fa +8ff61d87c4699a067a54b8540e8642f4c7be09d3783ec18318bcba903c6714fcd61be69165e07e1ca561fe98e07507de +85485d6b569ac20e6b81a9e97ef724e038f4fee482f0c294c755c7b6dad91293814f143bfcfc157f6cfa50b77b677f37 +a49256cb1970cc1011a7aed489128f9b6981f228c68d53b1214d28fbcfb921386cc7cf5059027e667a18073efa525a74 +87bc710444b0c3e6682d19307bedc99c22952af76e2d851465ee4f60e5e1146a69f9e0f0314f38a18342e04ece8e3ed3 +a671a6cabfd19121a421fdfe7732eccbb5105dfb68e8cbcf2b44ae8465c99e78c31b99730beca5bc47db6fc2f167203a +a2f3270c184629f6dfc5bf4bdd6e1b8a41e8840a1e4b152253c35c3d9e7ab4b8e3516dc999c31f567e246243e4a92141 +b9795a5a44f3f68a2460be69ecacdbb4664991ebbedffed5c95952147ad739e2874c099029412b9653d980a2d4307462 +959053faec9a966dd5a4a767a3154e4b8e4f56ca540ae53e373c565dda99fb626f725e5a5e3721c82918f8c5f2e9e0a3 +b3ef9d6a1b3cd44a3e5112819fa91cb8a7becc3f5b164c6f759f93171d568497b01c8e743f4727b341a1296a0dbadf4f +b852dfdfbe2b8c77d938fad45f00737e14eacf71d5fecbb3e4f60052ec9efb502c38c1fcecaf71da69eabe8b33852a67 +921c7007f26bdd4139e919dfe27d87b489a0bc5bd6fb341e949e4451f14c74add0489b108c9c9666a54c5455ac914a9f +86b63d73ba31c02e5337f4138e1684eccdc45ab5e4f30e952fb37d638b54ecec11010414d7a4b7aa91f7cc658f638845 +853c55e0720b66708a648933407795571fc11ad5c234e97f92faabce9e592983dfb97a1705047ee803648ecf9fbb2e5c +995fe7d1dc09bb0c3c3f9557c4146534778f5ea9c1d731c57440fdcf8094f82debf19090b5d23298da1ed71c283b3ae5 +b9c49c911a0c4d716b7baec130f9e615bfa7d504aa8766ed38878a93c22b1f6353503d4f7f425d4902239fb4689429df +80504d964246789a09dcd5c0298680afb6fe50bca3bb9c43d088f044df2424a1828de10e0dbdc5c0aac114fa6d9cf5d1 +90249351f109f6b23a49a610aaa3b2032189fd50e5e87cdc3b20f23ed4998af3a8b292bf9fbab9bd1cbe0a1371081878 +abb5f0148850f0d80b429c2b9e0038772432340ef0862ccb5dcb7347026ca95bf9a5857f538e295aebd3a6a5027adb4c +b92ac9c0f7e73150798348265e5f01f3c752480c72613c6894a95e9330bba1c642b21b9cbd8988442b5975476634b4fa +af3fbcc825abd92c6d7ea259467f27045e288f27a505e6a3c9ec864aa08fcaca0d4123034513dbd4c82d4814075708ab +a738232a66030e0e9c78e093a92fcc545b10e62fb0ecb832bbbc71471b28eb6ec422a498c2402e2c6d74983df801e947 +ae60194ce2035edd1af253b9eefbb4b1b7609c9678256c89c3cb076c332a9f4442c3441ad2ecc9d73265359bdadc926c +8b2fd55e686f16725fc0addb4065f696275852320b03221fd22889825d66fae5bb986b03c47452e32b3a32c1fdfc8dfd +8e2e1a36673b7729b07e7bc5014584e1c03e9552f7440fbfda0a6a7f41953947fcdf8d666f843bfc03dcca5b06a14318 +95a3df04368c069f3fd32a20b627c5f043e952167c9e80bf5914bbf2086879909c60e089bbd488725ab977c0e6051728 +9856403b2211d0152d4eec10db7ec34c16ac35170714b75af3ebc398a676c171b24b6f370361de0f9057ba444293db14 +a2cb484b758af5fd8e2baca7f0406f849c71255e58ef110d685cd0c1137893a25d85a4d8582e3ced7dd14287faa95476 +b0f697b6a42f37916b90ab91994ae4a92c96dc71e4da527af41b9d510bc2db5a9b4f29183a758074b6437a1e62b2d1d7 +b39c49266aae46f257b7ae57322972fb1483125298f9f04c30910a70fe5629dba0ec86b94cc6ba16df3537a55e06f189 +86cd5595b5b769dfd9ceb68b11b451f6c5b2e7a9f6f6958eac8037db1c616e8a9defb68a0d6c2287494d1f18076072c1 +b462e8fa9a372d4c1888fd20708c3bed1cb00c17f7d91a0481238d6584fbbf2d238e25931154f78a17296a12825d7053 +a5ef28286628ba509bac34c9f13158d0013239fdca96b5165161f90b89d6e46295822ebdf63f22d7739911363a0e0e86 +a629a95a24e2545862b41a97ecba61b1efa792fd5555dc0599c175947e9501bffc82b05a605fd5aabc06969ccf14fff4 +af83467e4b1f23a641630cc00c38d4225ff2b4277612b204d88de12a07d9de52fb4d54a2375a7fd91eb768623c255376 +a630f29fb2e9a9e2096d7f3b2f6814ee046ebc515f6911d4bc54ad8a5a821a41511ff9dcfbe3176f35c444338ecd0288 +950dedc11bd29e01ba9744bec681ad9462127c35e9fcadfacc9405ec86b985a1b1c4f9ac374c0f1fa248212e5e170503 +82e8e7be8011ee0fd9c682d26a0ef992d0191e621d07fd46a3a5640ef93a42e1b98a33cad1f8017341a671d28caebb03 +a075860554e712398dac2fb0375067a48d0e4ca655195cefc5ccb1feb8900d77124aa52a12e4f54f7dab2a8f1c905b5b +81d2183d868f08714046128df0525653a2dc2ff9e2c3b17900139c9e315b9f4f796e0fb9d1d8cbadbaa439931c0e0879 +81fb1456969579515a75fb66560f873302088cde2edc67659b99a29172165482ca1f563758c750f00086b362ae405322 +a13c15ab19203c89208c6af48d2734bb0873b70edb660d1d5953141f44db9012528d48fb05aa91d16638cbda2ca8f0cc +8ba46eef93e4ec8d7818124a0b9fcfe2bcf84a98db3545d2b3d0192cfadc81fc667dcc22ab833c3e71508d0f3c621fe4 +b9bd60d2266a7d01e1665631a6ed6d80ffc0cd7f088f115a5d4ea785c518a8f97d955e2115b13c4960302b9825526c92 +b26fa4e87142150250876083a70c229249099331410f0e09096077fdf97b31b88dc57a3e3568d2a66a39af161cf5dfec +b9d147564124728b813d8660ba15fa030c924f0e381ad51d4e0cf11cc92537c512499d3c2983dd15f2e24ca166070d70 +b6fb44e1a111efb3890306fa911fafda88324335da07f7de729b2239921ef15b481630a89c80e228bec7ab6444a0b719 +a6cd9c7acac052909ef0cf848b6012375486b59b7bac55b42c41f0255b332c1d45a801f6212d735be8341053bd5070b9 +864258d69234786af5de874c02856fc64df51eff16d43bfb351b410402ab28f66895aec4025e370a4864f19ff30fd683 +84370fa1243b64b3669dd62e1e041ff9bd62810752603486aac3cba69978bd5f525c93cbc5f120d6f2af24db31ec3638 +b983c2cdc1a310446de71a7380b916f9866d16837855b7d4a3a6c56c54dab3e373a6fc6563b8309dc3b984d4e09275d6 +914f8587f876470f7812fa11c6f67e2dd38bf3090e8928e91fe2fe5595bee96cbe5f93d26fdced6b4e7b94f75662b35d +8b47bcb111d91aa3d80e4ceef283824aa00d1faeb6fe4111aecd9819869c0e1f6f4b6fb2018aebb07a0f997412cda031 +95b2befa98f9992450ca7ff715ae4da8c36dd8adcfef3f0097de6e3a0b68674b05cbf98734f9665051bb4562692641e0 +8bcd1651a2bfce390873a958e5ff9ca62aac5edd1b2fd0f414d6bcf2f4cf5fa828e9004a9d0629621b5e80fbbd5edb90 +af79bed3c4d63239ac050e4fa1516c8ad990e2f3d5cb0930fc9d3ce36c81c1426e6b9fe26ac6a416d148bf5025d29f8b +881257e86b7ab5af385c567fde5badf67a8e7fff9b7521931b3ce3bac60485c0fe7497339194fb7d40e1fad727c5c558 +a1b40b63482cd5109990dfb5a1f1084b114696cbbf444bf3b4200ab78c51dad62c84731879ea9d5d8d1220e297d6e78a +b472212baa2a31480791828ca5538c3dcc92e23f561b0412f8cc9e58839d1625ddcaf09c8078d31ac93470436843cd74 +8f516d252b1863cd3608d852a2857052bb2a3570066d4332fa61cb684b10ac8d1a31c8d32f2a0d1c77eee2ad7a49643d +8d20b75c51daa56117eda2fd5d7a80a62226074b6a3ff201519f2054eecfeff0aa2b2f34b63bea3f53d7d0ce5c036db9 +8282f433229e7948a286ba7f4a25deb0e0a3c5da8870562c3646757bef90ca1e8d3390b0a25b3f2bf45bf259a4569b77 +8a2dbf4b55cc74f0a085d143a88ebc8c2a75a08eab2703d13a00b747eaddc259a3dd57f7330be938131835a6da9a6a68 +aa0bc51617a938ea6a7b0570e98b8a80862dd9e1cf87e572b51b2a973e027bcd444ef08e0d7b5dee642e0da894435e91 +aa7319ca1ac4fe3cc7835e255419eeb7d5b2d9680769cc0ca11283e6147295db75713b71a9312418a8f5505cd45b783d +ab3f9c465663dc90fae327a2ee9cb7b55361a9b6fbe713540a7edd3cff1c716802fb8ad4dd8fb0c945d96b3b44c5795b +913a2ae88acffab12541fc08920ee13ab949f985a117efe9a5b2c76f69f327f60c5b5ad3fa5afa748034ac14298fc45a +9008f044183d2237b723b235953e4d8b47bec6a7b300d98075555478da173b599ba9c7c547c2f111ce1fae5ac646e7a3 +a26b4cc42b353e1c18222d2e088d7f705c36be12e01179db440f10fcfa9691d31fc4fc7e7ee47876f1624e6d44be1021 +995e75824f322294336bfa2c5d1a319f0d77f6a0709beabaf1b43015d8a78d62447eab907349524734170f0294d1ca7a +8b96f04a19dbe4edc71d1f2c6d3475ae77962e070ec5797752453283c027c6b29b6e58e8b7eb5c3f9770557be7e80b67 +8621459865234734bcfaa492ca1b89899525198a7916ccc6f078fb24c8bf01154815bb5b12e1c3d0a10bd4f1e2ea2338 +ab52174541185b72650212e10a0fe2e18ccfd4b266a81233706e6988c4af751b89af87de0989875f7b5107d8d34c6108 +966819d637bdd36db686be5a85065071cf17e1b2c53b0e59594897afc29354ecba73bf5fc6fa8d332959607f8c0a9c27 +b7411209b5ab50b3292c3a30e16f50d46351b67b716b0efb7853f75dc4e59ec530a48c121b0b5410854cd830f6c4b3ea +a5dc04adbadce0af5dc1d6096bad47081110d4233c1bf59a5c48a8e8422858620f4be89bf1f770681be2f4684ee4cce7 +af77a8f83cffb5f8d17be0ab628dedcad63226c9b13ce4975fb047f44bfef7d85e7179aa485abb581624913eddbb27ec +82bf28dc58c893c93712ce297cc0d64f70acb73a641cb4954ccf9bf17597f6d85eecf5a77c8984ab9afbe588562a0ee9 +988a7cef9a178e8edb91f3ec12f878fd68af2ac0762fa0a48a2423e24f765ed8f7837429fd8bc0e547e82e6894e63008 +a5d5969311056d84b3ee87f49286fac0bd9a7220c196cea4f9dced3b858dcdba74718eab95b38bd5d38d2d1184679c98 +af4d51b3ded0aaad8f12bef66c0616e9398fc42618852ac958e6ab2984a720a6111ac55b249d7e4523051740e12b346f +ac635b4a49f6fbb94a5f663660f28431ba9f7c5c18c36ebc84fd51e16077de7753595f64619b10c16510ecbc94c2052d +ae25eb349735ced1fe8952c023a9b186a1f628a7ddf1a4b6f682354a88f98987ac35b80b33189b016182f3428a276936 +ae3ab269690fdd94134403691ba4f5ed291c837c1f5fdc56b63b44e716526e18abb54f68ca5d880e2fb7bea38e74c287 +a748b03b2bd3fbc862572bc4ddc0579fa268ee7089bcfd0d07d0c5776afcd721302dbb67cb94128e0b1b25c75f28e09a +8f09a2aaa9ba3dfe7271f06648aba9cc1ea149e500a7902d94bb9c941a4b01d1bb80226fd0fd2a59ad72c4f85a2a95d0 +853d55ad8446fd7034e67d79e55d73a0afcb5e473ed290e1c3c7aa5497e7f6e9bbf12d513fc29e394a3dc84158a6d630 +b1610417fb404336354f384d0bf9e0eb085073005d236a0b25c515d28235cea5733d6fbd0ac0483d23d4960064306745 +86de805b3d4f6fbb75233b2cf4d22fcc589faa2ac9688b26730cb5f487a3c6800c09bb041b2c6ab0807bfd61b255d4c9 +893b38c72cf2566282ee558d8928588dca01def9ba665fcb9a8d0164ee00dedafbf9d7c6c13bcc6b823294b2e8a6a32c +8e50de7a70ac9a25b0b5cf4abc188d88141605e60ce16d74a17913a2aff3862dec8fbbf7c242cf956f0caae5bcc4c6bf +b5cf09886a4fb4ce9ea07d1601d648f9f9d1a435b5e1e216826c75197cd6dafd6b2b07d0425a4397a38d859a13fdb6dc +859dc05daf98e7f778a7e96591cc344159c1cbe1a7d017d77111db95b491da0a9272866d2638a731923ca559b2345ebe +8ff1792f77ecdfbd9962f791a89521561c7b82031a4e53725f32fe7d99634a97b43af04cbf3e0b0fdff4afa84c49eb99 +81e2cd8a221b68ae46dd7ce97563bd58767dc4ce1192b50ff385423de92206ff585107865c693c707e9d4ed05f3149fb +8fce7da7574e915def0d1a3780aa47ef79b6d13c474192bd1f510539359494ddc07e5412f9aac4fc6c8725ade4529173 +ac02f5df60242734f5ead3b8a62f712fefdb33f434f019868a0b8ddf286770244e2ddfb35e04e5243ba1e42bcd98a6a5 +a8d69783349a442c4a21ecb3abd478a63e2c24312cb2d2b3e10ea37829eb2226a9b8d05a8c9b56db79ffaa10d1f582d1 +b25b5cca48bf01535aba6d435f0d999282845d07ac168f2ca7d5dba56ee556b37eab9221abdb1809767b2de7c01866c1 +8af7e1d1f4df21857d84e5767c3abe9a04de3256652b882672b056a3ab9528e404a8597b1ad87b6644243f8c4cd3799f +a6718308dfa6992ae84fcb5361e172dbbb24a1258a6bd108fd7fc78f44cc1d91be36e423204a219a259be4ab030f27ff +b99cbe3552c1a5259e354c008b58767c53451932162e92231b1bebfc6a962eb97535966a9bd1dfd39010dfcda622d62a +a8458f6b8b259581f894e4b5ce04d865f80c5a900736ca5b7c303c64eaf11fe9cb75e094eece0424ba871b2aee9f7a46 +914f763e646107b513c88f899335d0c93688ffa6e56c3d76bff6c7d35cb35a09f70dc9f2fe31673a364119c67cd21939 +9210f2d39e04374f39b7650debe4aceeb21508f6110ab6fc0ab105ec7b99b825e65753d4d40f35fad283eeff22a63db0 +98729cf927a4222c643b2aa45b3957b418bce3f20715dd9d07997a3c66daa48dd62355dbd95a73be9f1d1516d1910964 +a602c399f1217264325b82e5467a67afed333651c9f97230baf86aec0dd4edeae1e973cafef2ea2236d6d5b26719954d +ac9632921d45900bf3be122c229ba20b105b84d0f0cba208ccdce867d3e9addfb3ef6ece9955950d41e1b98e9191ef42 +a76ce1f53e1dc82245679077cb3bca622558f2269f2d1a1d76b053896eba1c3fc29d6c94d67523beb38a47998b8c0aa7 +b22b51fcc1b328caa67cc97fb4966cb27d0916488a43248309c745cd6e2225f55ad8736d049250fa0d647e5f8daa713c +b7645c1923a6243fa652494fe9033fa0da2d32a0fb3ab7fcb40a97d784282a1ffad3646c499961d4b16dadbc3cbb6fd6 +acab12b490da690db77c4efdc8b2fe6c97ac4ba5afb5165d6647fdd743b4edbad4e78d939fc512bebcf73019c73bae40 +ad7a0fcd4e4ccb937a20e46232a6938fccf66c48a858cf14c8e3035d63db9d1486e68a6bf113227406087b94a0ece6a0 +a78605beaa50c7db7f81ab5d77a8e64180feea00347c059b15dc44c7274f542dc4c6c3a9c3760240df5f196d40f3e78b +8763315981c8efa9b8ae531b5b21cfc1bbc3da3d6de8628a11dcc79dee8706bd8309f9524ec84915f234e685dd744b69 +b4a6c48531190219bf11be8336ec32593b58ff8c789ee0b1024414179814df20402c94f5bfd3157f40eb50e4ef30c520 +8dac8a3f152f608ce07b44aee9f0ed6030fa993fd902e3d12f5ac70bf19f9cde2168777d2683952a00b4b3027d7b45ea +8baf7dfae8a5840c5d94eabfe8960265f6287bb8bc9d0794a6d142266667a48bec99b11d91120907592950a0dddc97d9 +b8595e6ea6b8734d8ae02118da161d3d8d47298d43128a47e13557976032dad8c2ccbfff7080261c741d84d973f65961 +8b93979c51c8d49f4f3825826a5b9121c4351e0241b60434a3c94f2c84f0b46bbf8245f4d03068676166d0280cf4f90c +aceb0fdaf20bf3be6daebf53719604d3ab865807cc2523285f8fef6f3fc4f86f92a83ad65da39de5bd3d73718a9c4bd2 +814dd41764a7d0f1a14a9c92e585f154a26c8dbf2f9bff7c63ae47f1ac588cec94f601ccc12e8a63a7a7fce75a4287f2 +b47b711848e54fa5c73efc079d0a51a095fa6f176e1e4047e4dac4a1c609e72099df905958421aee0460a645cba14006 +aaf7bd7e1282e9449c0bc3a61a4fca3e8e1f55b1c65b29e9c642bb30a8381ce6451f60c5e0403abc8cee91c121fa001f +b8b0e16e93b47f7828826e550f68e71a578a567055c83e031033c1b7f854e7fc8359662a32cc5f857b6de4aff49e8828 +b3eb70b8c8743a64e1657be22a0d5aeb093070f85a5795f0c4cb35dc555958b857c6c6b7727f45bf5bedf6e6dc079f40 +ae68987acd1666f9d5fa8b51a6d760a7fb9f85bf9413a6c80e5a4837eb8e3651a12e4d1c5105bfb5cfa0d134d0d9cfc2 +acd8fa5742b0bac8bd2e68c037b9a940f62284ff74c717f0db0c033bf8637e4f50774a25eb57f17b2db46e5a05e1d13d +a98dac386e7b00397f623f5f4b6c742c48ab3c75d619f3eaf87b1a0692baf7cb7deac13f61e7035423e339c5f9ae8abf +99169bd4d1b4c72852245ebfbc08f18a68fb5bcce6208dd6d78b512b0bc7461f5caf70472b8babf3e6be2b0276e12296 +937d908967f12bf7f728fe7287988c9b3f06c1006d7cd082e079d9820d67080736910bc7e0e458df5bae77adb9a7cbc1 +8c50e90ce67c6b297fd9406c8f9174058c29e861597a0f4ed2126d854a5632fa408dfa62ad9bb8b6b9b6b67b895d5a4d +8f4840a91b0a198226631a28e7a2e893fc6fed4d5eb3cb87b585aac7f4e780855a353631ad56731803296f931e68a8d0 +96a4b8c64d3d29765e877345383bf0e59f4ac08798ac79dd530acd7f3e693256f85823ad3130fb373d21a546fe3ca883 +b0dce7a6ab5e6e98b362442d6e365f8063ba9fef4b2461809b756b5da6f310839ac19b01d3fd96e6d6b178db4ff90ee1 +8f012cb2be5f7cb842b1ffc5b9137cafef4bd807188c1791936248570138f59f646230a1876f45b38a396cbdd3d02e08 +94a87b5ce36253491739ca5325e84d84aaff9556d83dcb718e93f3ff5d1eecf9ae09d0800a20b9e5c54a95dfebfcecd3 +b993ec5f9e82cc9ceeb7c5755d768bc68af92cc84f109dfaf9cf5feb3aa54881e43c3f598ba74ed98e8d6163377440ca +92f845d4d06a5b27d16aef942f1e3bcbe479b10fef313f9ca995315983090511701b39ccbb86b62d0c7c90a2d1f0c071 +b6ec6da0f9e7881e57fa3385f712e77f798abc523609a5b23e017bb05acc6898825541aed7fe2416c4873de129feceea +86b181183655badfe222161d4adf92a59371624a358d0ec10e72ee9fa439d8418f03d635435ec431161b79fd3fa0d611 +b5e28eeed55fb5318b06a0f63dbf23e00128d3b70358f1c6549fd21c08ef34cb1372bc0d4b0906cc18005a2f4cd349bf +85c4d3fddda61dbfb802214aa0f7fc68e81230fb6a99f312848df76cddc7b6dfd02860e8a4feb085dad1c92d9c6c65e0 +80f7fdec119309b2ac575562854f6c2918f80fc51346de4523ec32154d278f95364fdef6f93c7d3537a298dd88df7be6 +9192c1949d058614c25f99d4db48f97d64e265a15254aa6ed429e1ef61d46aa12355769f1909a5545cd925d455a57dbe +a0b1e7d928efc4dcbd79db45df026ae59c20c1a4538d650c0415ab7cb0657bc1e9daeacc3053ee547e8f9c01bdbd59c4 +893e84c41d3a56bca35652983c53c906143b9ad8d37b7c57f9dacbeb7b8dd34defc6a841f5b9857ffb90062bbd8e9dee +a7f89a448349dbc79854cf888980327f92aedc383c7fadd34fdc0eaa4f63d751315b4f979e14f188854ef4d16c9e8107 +833f2774a96187805f8d6b139c22e7476bce93bc5507344d345008080fb01b36d702b96e4c045617a23a8ca1770b4901 +80e46e86d68bd0a48ac6fa0b376d5bb93a5d6b14f08b3a47efa02bb604c8828c2047695f1f88fc5080e5548e1a37130f +943f42b7b4ad930059a26ad06b62e639f06c1c425d66066c55134e97c49abe412358c7cb994fcc1cf517ea296bca1f68 +8b9d4fe835dc6a2cbf85738937bbfb03f0119ab8df04a7d68860716ce6ee757dbe388a1e8854ddb69fe0c9fa7ed51822 +909030c7fde2591f9ea41ae6b8fa6095e6e1a14180dda478e23f9c1a87b42c082a1ea5489c98702f6ccd2ba5812d1133 +a715ec1beb421b41c5155c7ef065bbb50b691d0fa76d7df7ee47683d9e4eb69b9ea3e62fc65196a405d6e5e29e6c2c60 +8c9e801cb7ef780a535be5c2a59b03e56912acbfdb00447bfa22e8fc4b11dceecc528f848d5fba0eec4237d6f81f4c79 +b96b6af857c3bc0344082bd08ec49a9bed478d4d35b85a2099b1849cd6997521c42225305f414cdd82aef94b9e1007d3 +8764db720b4e44a4d2527f7f9b535a494a46c60e28eac06bf1569d0703c4284aefa6cb81fbba9d967286f9202d4b59ea +a66fd2f9158e1ffcdd576cba1413081f43eed00c7eb8f5919226f7b423f34ac783c1c06247819b238de150eb5a48d977 +82c52e817ac3bb0833ea055dec58c276c86ca5181811cf7a483b3703a06ea1bee90ae3aeaa2cffeaeba0b15fe5bf99be +987d07cb276f7f03a492cfb82bba6d841981518286402d3e69e730a9a0e29689a3619298124030da494e2a91974e0258 +b34f2c5740236bc6d4ae940920c5bc2d89ff62a3dd3a3ec9a0d904d812b16f483073db1e53b07f2b62e23f381d7bdbe5 +a1c0679331ab779501516681b3db9eefb7e3c0affb689e33326306ada6d7115fafd2cc8c1c57b2fa6c2072552f90a86e +94805e30d7852fc746e0c105f36961cc62648e438e8b9182fc0140dbf566ec14a37ad6e7f61cacb82596fc82aed321e5 +a42fb00b29a760141ff0faaeb7aca50b44e7bbc0a3f00e9fb8842da7abfcaae6fae9450abe6ba11e8ecf11d449cbe792 +8fb36ce4cfa6187bfe8080ac86b0fa4994f20575fb853bd8ffa57c696179cc39f58ff3b4bd5a2542ff1c8b09015539df +a1c54e7aa64df7fb85ce26521ecfc319563b687ffecd7ca9b9da594bbef03f2d39f51f6aaff9a3b5872d59388c0511c6 +855e48fdb8f771d4e824dbedff79f372fd2d9b71aa3c3ecf39e25bf935e2d6e0429934817d7356429d26bf5fd9f3dd79 +8ae6157a8026352a564de5ee76b9abb292ae598694d0ea16c60f9379e3bb9838ce7fd21def755f331482dc1c880f2306 +a78de754e826989de56fe4f52047b3ffd683c6ceaf3e569a7926f51f0a4c4203354f7b5cfa10c4880ba2a034d55a9b0d +97609477d0a1af746455bbd8cb2216adacc42f22bfd21f0d6124588cd4fec0c74d5bde2cdba04cdbfbff4ac6041b61b1 +a03dc3173417381eb427a4949c2dbfa0835ef6032e038bf4f99297acf4f0ba34a5fc8ccf7e11f95d701f24ee45b70e27 +aad6283e85cd1b873aeb8b5a3759b43343fdadc9c814a5bf2e8cf3137d686b3270f1ec2fb20d155bbfd38c7091f82c44 +92ab94ed989203a283d9c190f84479c2b683615438d37018e9c8de29c2610bb8fccd97bb935dca000d97d91f11a98d65 +8c0444a0b9feb3acb65a53014742e764fa07105e1c1db016aec84f7a3011d9adc168dbba8034da8d0d5db177a244d655 +95a33d25e682f6c542d4e81716cc1c57ef19938409df38bf8f434bc03193b07cedd4e0563414ce00ab1eebbd3256f3e7 +8716c30e3e4b3778f25c021946c6fb5813db765fde55e7e9083a8985c7c815e1b3d3b74925ba108d9a733ddf93b056af +a186aabc10f1fff820376fa4cc254211c850c23a224f967d602324daec041bbe0996bf359ed26806a8c18e13633a18a8 +a1e8489f3db6487c81be0c93bade31e4d56ec89d1a1b00c7df847f5cd7b878671015f5eaa42ee02165087991936660b9 +8f688c969c1304dfa6c1a370119d1988604026a2ab8e059016c5d33393d149aae6e56f3ee2b5d25edc20d4c6c9666ad9 +91950b651fefd13d2fa383fd0fdc022138ce064ee3b0911157768ad67ed1fb862257c06211cf429fba0865e0b1d06fc8 +86cff4080870d3e94ed5c51226a64d0e30266641272666c2348671a02049ae2e8530f5fb1c866c89b28740a9110e8478 +88732c4d9e165d4bb40fb5f98c6d17744a91ff72ca344bc0623d4b215849a420f23338d571a03dd3e973877228334111 +afcc476ad92f09cf2ac7297c5f2eb24d27896d7648ba3e78e1f538c353ceeb1e569917a2447f03f3d4d7735b92687ba5 +b622aa475e70d9b47b56f8f5026e2304d207684726fb470a0f36da7cb17c30dd952813fab6c7eb9c14579aacca76f391 +802cf5630c0407ae0d3c5cf3bef84e223e9eb81e7c697ea10ec12e029fc4697ce7385b5efab7014976dacc4eb834a841 +a08596493f4cd1b8ac2ec8604496ee66aa77f79454bb8ab6fdf84208dc7607b81406c31845d386f6ac8326a9a90e7fc5 +a54652ca9e6b7515cb16e5e60e9eabbccbc40bb52423d56f0532d0bac068aec659a16103342971f2cc68178f29f695db +a3ab54875cb4914c3a75b35d47855df50694310c49eb567f12bbc5fa56296e11f4930162700e85ba2dbfdd94c7339f91 +94183a040285259c8f56bef0f03975a75d4def33222cc7f615f0463798f01b1c25756502385020750ac20ae247f649a1 +b0004261cc47b0dc0b554b7c6ebf7adf3a5ece004f06e6db3bbac880634cdf100523b952256a796998a5c25359f12665 +a25dfeb0e18ebe0eb47339190f6a16f8e116509ab2eef4920f0d3ff354e3ead5abe7f5050b2f74f00b0885ea75b4b590 +ab10ef2f5dc0ede54e20fa8b0bce4439543db8d8b31e7f8600f926b87ec5b8eea0ac2153685c7585e062ffac9e8633c3 +8386eac1d34d033df85690807251e47d0eaacb5fe219df410ab492e9004e8adabb91de7c3e162de5388f30e03336d922 +b6f44245a7d0cb6b1e1a68f5003a9461c3d950c60b2c802e904bc4bc976d79e051900168b17c5ac70a0aed531e442964 +ad12f06af4aa5030b506e6c6f3244f79f139f48aec9fc9e89bbfbd839674cfd5b74cea5b118fb8434ba035bda20180af +88511306dfe1e480a17dba764de9b11b9126b99f340ceb17598b1c1f1e5acbdd1932301806fe7e7e5e9aa487a35e85de +a17cdf656e1492e73321134a7678296a144c9c88c9a413932d1e4ca0983e63afc9cdc20fd34b5c6a545436b4db50f699 +b555b11598a76de00df0f83f0a6b8c866c5b07f7ac2325f64fb4a0c2db5b84e0e094d747186c3c698ee4d0af259dc4c7 +88014560587365e1138d5b95c2a69bdae5d64eb475838fee387b7eb4c41d8c11925c4402b33d6360f0da257907aa2650 +b220634e6adee56e250e211e0339701b09bf1ea21cd68a6bd6ee79b37750da4efe9402001ba0b5f5cbbfcb6a29b20b0c +ac5970adc08bc9acec46121b168af1b3f4697fb38a2f90a0fbc53416a2030da4c7e5864321225526662d26f162559230 +97667115b459b270e6e0f42475f5bce4f143188efc886e0e0977fb6a31aba831a8e8149f39bc8f61848e19bcd60ceb52 +b6c456b36c40a0914417dd7395da9ed608b1d09e228c4f0880719549367f6398116bf215db67efe2813aa2d8122048f2 +ab7aef0d6cda6b4e5b82d554bd8416a566d38ded953ffd61ef1fcca92df96cdcc75b99a266205ff84180ab1c3de852a4 +81d354c70ce31174888c94e6cf28b426e7d5c4f324dc005cd3b13e22d3080f3881d883ca009800f21b0bb32fa323a0cf +94f3440965f12bee4916fcc46723135b56773adba612f5ce5400f58e4d4c21435e70518bdef4f81e595fa89e76d08fc6 +a6683e7a1147f87cbeeb5601184cc10f81bca4c3c257fd7b796a2786c83381e7698fb5d1898eb5b5457571619e89e7d6 +8ca29539600f8040793b3e25d28808127f7dc20c191827a26b830fff284739fb3fc111453ff7333d63bce334653a0875 +98a69644048b63e92670e3e460f9587cf545a05882eb5cba0bcbd2d080636a0a48147048a26743509ab3729484b3cc12 +84d40302889c03c3578c93aca9d09a1b072aadd51873a19ef4a371ca4427267615050c320165abece7f37c13a73d4857 +87954271e3de3f0b061c6469d038108aac36f148c3c97aefb24bf1d3563f342ea6c1c1c44c703e1587a801708a5e03f8 +86b6f5367e04c5caa3ec95fd5678c0df650371edac68f8719910adf1c3b9df902cc709a2bddc4b6dde334568ca8f98ac +a95fed2895a035811a5fee66ca796fdecce1157481dd422f8427033ed50c559692908d05f39cb6bea5b17f78a924633c +8ba05bdadde08a6592a506ea438dbdc3211b97ea853d1ad995681a1065ececce80f954552b1685ef8def4d2d6a72e279 +90b6b7494687923e9c5eb350e4b4b2e2fa362764d9a9d2ebb60ee2ad15b761e0850c9a293123cf2ef74d087693e41015 +8819ea00c5ea7b960eb96ab56a18c10a41fd77e150ab6c409258bc7f88a8d718d053e8f6cb5879825b86563e8740808d +91e42031d866a6c7b4fd336a2ae25da28f8bde7ace6ff15dc509708b693327884e270d889fff725e6403914546055c28 +85763642052f21cf1d8bd15fd2dc0c2b91bba076751e4c4f7a31fbdb28787b4c6a74d434d6ef58b10f3ad5cde53ef56d +8b61c36c7342a1967a1e7b4c01cddf4dce0e2025bc4a4a827c64994825f53e45277550ceb73c34bb277323fb784aa3c6 +80b9634a45c8b3770e993257bd14df6a17709243d5429969ab8b9a4645bf2a94f9b3cd3d759169887b4aa0eb50f4f78c +b5c44db9439dd8aa4edd151d95e48a25c1154e1525c337f97109f40131db81a4898344c8c3144c270bdc835c269b3477 +863080fcbc227eea32d0dc844f42dc642fbda7efc398ab698be3a3c6f3bf8803dea6ba2b51fed6151f9522b4ab2a8722 +8481e871129e9cb9d2d109c513cbba264053e75192e967f89659dcfcc1499de9ae7a1ac4f88f02289150231c70b4da01 +834d8183698d3d2d1352c22c373222cb78d0f4c8cb15e0ad82073dde273b613515ebcd184aa020f48f8e6fc18f3e223c +a227e300f0c5bc1b8d9138411413d56c274cc014ae8747ec9713f3314d5fae48bb6f8cc896f232fd066182af12c924e4 +ab7242835e91ba273de1c21eb4fca8312bdda5b63b080888b96a67a819b50294a7f17a7dc0cd87fae5e7f34bc24c209a +86eb27c898a5d6c3618c3b8927acee195d45fe3f27b0991903520a26fb8021b279e2a8015fbbba5352223ae906c7c5d6 +a61b1c200b0af25da8ad8e29f78d000a98683d1508ae92ee7f4326a7c88e0edb645b6cb5dde393ac74d322895e77ba24 +887739318c710aae457b9fe709debff63bfbb3ffbbb48a582c758b45d6bf47a7d563f954b1f085c3bc633ffd68c93902 +aacfcb0e2b0a868b1c41680487dc6600577ce00aa2edeee8c6141f4dc407217ddb4d37b79e7c9182258c750d12a91508 +ad8cd2cf5ccd350cd675a17f31b86a0e47499c6c4c11df640a5391bb10989c9c70df0a3ddeba9c89c51e15fedaf67644 +8aba897d32c7ef615c4dfa9498436529c91c488a83efc07ba9600875c90c08b00f66a51469eb901451b6e18e7f38ffd7 +aab8a600609b80e36b4a6772308bac77929a0c5d8d92bbc38e9999186a1c2bfdbef4f7a2b1efba9c17a68dc15a9373ab +b95811d1454307a30c2ac8588c8104804b06c1aec783fed75a6f12c9df626be57865850100f1ad28073e3867aca941cf +8b119d3bd4ee644469457df5d8a0020fd99b8b20bd65ab121cf95a7f55e50dd8945fcf1dff9d269d9d0b74b4edbc7726 +a980b912df832ea09353fd755aa3eec9eb4cfd07ca04387f02a27feab26efa036fca54cc290bb0c04a8a42fdfd94ce2f +91288e84da1d4ee2a4dad2df712544da3a098fdb06a5470c981fb6d6f3dcc1c141b6f426d6196ff3df6f551287179820 +98b0473bcffcbd478fd1b49895c61dd2311dab3cdec84f8e3402f8add126c439ffcb09cae3b7f8523754090d8487b5a9 +abe76988cf3065801f62a1eb3cfe9f8185bd6ab6f126c1b4b4fde497ca9118d02a0db3fadccd4ca98826b30475fa67ef +94a316a0faa177273574e9e31989576a43e9feb4cc0f67aa14d5c1967c4e10fc99db3ef4fdca2e63800a0b75f4b84256 +975ad39adadc7e69e34981be2e5dc379b325dc24dddacc0bb22311ff4a551a0020a8bdecf8ab8ac5830ca651b7b630ce +8b3bc73b640dc80ac828541b723a968fb1b51a70fa05872b5db2c2f9b16242c5fe2e8d1d01a1dbeaac67262e0088b7b0 +aa8d892a6c23dbc028aae82c1534acb430a1e7891b2a9337cedb913ff286da5715209cffb4a11008eae2578f072836cb +8dee9747a3ae8ed43ce47d3b4db24905c651663e0f70e2d6d2ddb84841272848a1106c1aa6ba7800c5a9693c8ac2804e +81e2c651b8b448f7b2319173ecdc35005c2180a1263e685a7e3a8af05e27d57ec96d1b2af2cae4e16f6382b9f6ec917c +98a9a47635de61462943f4a9098747a9cf6a9072a6d71903d2173d17c073eff3fc59b2db4168515be31e6867210ecbcd +912b2398505c45b0bb4a749c3f690b1553b76f580b57007f82f7f6cce4fadd290d6df9048258978c8a95ef9c751a59a2 +8ac8f0893fe642111ef98ae4e7b6378313a12041bbca52141e94d23152f78c2e4747ae50521fc9c5874f5eb06976e5cf +946b4a8eb05b529aaed56ac05e7abeb307b186a7835623fa4e85ed9eb41a4910663c09ea1bd932a2c467d28776b67811 +a4be51abeddd40e1da6fdb395d1c741244988ff30e10705417b508574b32dce14d08b464486114709339549794df9254 +b33b6b7d66cb013e7afeabbd7ed1e0734eb0364afe4f0f4c3093938eec15f808985fb7f3976969bf059fa95f4d8e335b +a808adbcf0049f394914482483ee0f711d9a865615ff39b5313ed997f7a0d202ad9ed6e6de5be8a5c1aaafe61df84bca +8856268be15a78465ad00b495162dc14f28d4ef4dcf2b5cba4f383472363716f66dabc961a6dbdda396e900551411e41 +b16ba931e570e1bf124ea3bd3bdf79aed8aa556697ea333e6a7d3f11d41538f98dcde893d0d9ba7050442f1515fb83b1 +91ecde1864c1a9c950fd28fa4c160958246b6f0aa9dda2a442f7222641433f1592d38763c77d3f036a3dbb535b8c6d8f +92cda991f69fbf8e55c6bf281b07fff5dbbb79d1222b8c55686480669247b60212aac27aa7cccd12fcee94e7a759b8af +b1d9b5b4e996b375d505d7250a54c12d32372c004a9cabf1497899054cb8b5584b1cef1105f87b6e97603ccbf2035260 +86e98bde8b484fb809b100f150199f13a70c80813ad8b673bf38e291595e2e362ad1fa6470d07d6fbe2cf7aeac08effc +aa12f7c39ba0597a8b15405057822e083aca3cee6ed30c4e0861eeb22620823588d96c97bb1c3776b711041c4dc3d85d +b477b34f29334f3bae69c7781d574342b7c27326088f9a622559ab93075c7357953ae84eb40e3421f453e04e9b4d5877 +9625067cb2120ce8220a469900aa1d1bb10db8fe1609988786b07eb2b88e0ddb35a3eccd4b6741e1fa2365c0db6b1134 +997b92af7765f587d70ea9718e78a05498cd523fc675ad7b0e54a4aae75fbeac55d0c8d72471471439dacd5bfcfae78d +88b59eaea802e6a2cf0c0075bf3fd6891515adcb9adf480b793f87f1e38d2188c5ed61ac83d16268182771237047ec8a +a57d078b230b1532c706a81eaabfef190fb3eb2932f4764631e916a0f0d837d6014da84ede100abaf610519b01054976 +94ed5c5b96f6afa9f2d5e57e1c847ae711839126ab6efb4b0cf10c4564ff63c819d206fdc706178eb6a0301df2434c01 +980296511019c86cc32212bad6e4a77bc5668b82a2321a1ecabc759a8bbc516183a4787c7f75f9ee7f1338691dc426cc +b10ef97db257343474601fd95f9016c205e28bd22bf7b8f9e30c3b14aca1cc9a11e6404ff412ef269c55fb101fee5a37 +b670d5d9c77fc6aa14212dd3eae100620f3510031b11a9625aa40bf31835c9fd717753b555bd159b1aa64a2104929340 +862054fabf6d6d529a7584d1a48f72d2eb216caf959c782ec36c69c26aef4595415d19a28b041946811b34a629105241 +ae4bf2ccd7b0f3774653848b5b4d39e5517dcbcff30d8441d78bc387ff42b573f16b7b0a7366e6ca5cef1dd9f0816df9 +8f810527badcb49f1542a0ccd12e3541efa084243f7106eae003458c176f4c1f01daae9d4a073c2cb2aced747e8a4576 +8a32c2067aaf6baf32db67acd4974a22a6da33db5444028a7c8c4135f9c84e102dc3b2c635b15afa6dc907d0270daffb +b15fc057f306a60b20c8487125b6b334ab749cf70eb8a30c962f625bb203ebd0d2a315949ee3b7a99e3d91acec384806 +a37f145d321359b21cba7be8b64dfae7c67a20b7b324f27c9db172d58e77a49fa02ed3d06d09d7644bf1fd81f4aab44b +b338d2e39a485ee4297adcf5e58e16c3cc331c5dffeade0be190907c1c5bdfed38537a6d81dc39a2cdfc1bc45e677886 +b69d84d8511b3aedfdc7c7e66f68b24e12e5a2365dbbe014bddd2e99e54143428cf8b74cf12c0e71316038aa5300e87e +ab210cc38661667450561a1857337879633f5d5bf2c434a3df74ff67f5c3ba69a7880872f19ae4dcbbb426462cd7d0fb +94538ef487a58a5ff93a5e9616494c5f066715d02be5b249d881a00bd0edfe2fe19dd7a5daa27f043d1dbb5ac69cf58d +afb47a899c1b25fe800241635fa05de9687a69722802ad45434f551971df91d8ca9edda0d835d82eb8f36ff9378ed7e8 +827a10d7536230887283a9b1dedccc6b95ef89cb883c4ee7b9821058b0f559704d1636670c0ada2b253bf60b7cb8a820 +97cc07965065d64409f19fb2c833b89ca3a249694b16b58818a6f49d3800926627ce0f87e5c0853ae868b4699cfdee5e +ae0c93d44780ef48ea537cf4cb8713fd49227f4b233bc074e339d754b5953e637a7289c6f965162701e4b64e4eaec26d +80953053397c4c0ba9b8e434707f183f9ced2a4c00d5c83b7dc204e247ad7febc1855daeb906c53abfdf3fe3caca30c4 +80f017e87b471b5216ebe25d807be6c027614572337f59f0b19d2d1f3125537478cb58e148f3f29b94985eac526cd92f +8a8e1c0d49801a8dd97e9e7c6955fc8b2c163a63bd6a4be90bb13e7809bb0dddc7a5025cc7d289a165d24048eac4e496 +8530e5b5c551a2e513d04e046672902c29e3bb3436b54869c6dea21bab872d84c4b90465de25dff58669c87c4c7d2292 +ae3589d389766b94428e9bde35e937ed11aac7ead3ce1b8efe4916c9bfff231d83b7e904fe203884825b41022988897a +ac02e629a900438350dd0df7134dfa33e3624169a5386ea7411177b40aa7a638e8d8aef8a528535efdbe1ca549911c0b +b1ac60b7270e789422c3871db0fa6c52946d709087b3b82e6eba0d54f478520b1dc366bb8b7f00ff4cf76e065c4146eb +a7465e1f8e57de1a087144d3c735fee2b8213fcbf2b9e987bb33c2d4f811de237bf007402e8d7f895563e88b864f7933 +8ab0007ba8984dee8695ec831d3c07524c5d253e04ec074f4d9f8bd36e076b7160eb150d33d15de5dd6e6fb94f709006 +9605bbe98dadd29504ce13078c1891eca955f08f366e681d8b5c691eadb74d6b1f2620220b823f90ef72eb4ab7098e16 +942a083d07c9cb7f415fedef01e86af4019b14ef72d8ab39fe6bd474f61ba444b9aac7776bea7e975724adb737e6337a +b9a49a8c4e210022d013b42363ac3609f90ea94b111af014f2c5754fbc2270f6846fa6a8deb81b1513bb8a5d442ea8dc +99cd62b177d5d7ce922e980cc891b4f0a5a8fa5b96dfc3204673fbef2e7fb2d7553bbacd7b2e6eca4efb5e9a86096e2e +94e30b65b3edd7472111566dde7fab0e39a17e1f462686050f7134c7d3897e977550faf00174748cbeaec6c9c928baa8 +a32fbcb29f3391d62092f2720e92b6ef4d687d8a3eae39395e0464669a64a38fe21a887f60bc9519d831b9efde27f0f4 +8f1492c4890d8f9deecb4adada35656e078754dcf40b81291e7ef9666d11ba3747a478f9420a17409d7d242cecd2808f +8942960b319ef65812d74cb1d08a492334db58d41e8437e83ddf32e387d9f3ad36834f59e6a71d1afb31263773c3ec49 +88d692f4976c99e763b027df9c2d95744d224724041dfbe35afc78b1f12626db60b9d0056b3673af3a1741eaf5f61b43 +9920cd37eab256108249a34d3f1cc487829cc5f16d1bce3a2328fe48b4de735ebde56c8b5cf4e532a4d68792387257c5 +87d34c9f5a913b806504a458c843eda9f00ff02ad982142543aa85551208cab36ebf8b3409f1c566a09a60001891a921 +a2ee8339c96f790b3cf86435860219322428b03ea7909784f750fe222bc99128d1da2670ad0b1f45e71a6856c7744e09 +84bd257f755de6e729cc3798777c8e688da0251a2c66d7ba2e0ce5470414db607f94572f5559f55648373ce70e0b560e +8d0e170714ddf5dde98b670846307ab7346d623f7e504874bfd19fbf2a96c85e91351ba198d09caa63489552b708fbc8 +9484cc95d64f5a913ed15d380c2301a74da3d489b8689f92c03c6109a99f7431feb8a07d9f39905dcef25a8e04bcec9b +b14685f67dd781f8ef3f20b4370e8a77fef558aa212982f1014f14b1bdd8b375c8a782d1b8c79efc31b41eec5aa10731 +b22fb1541aa7d2b792aa25d335d66e364193fdbf51b24a90677191cae443f0ce40a52faf5983d2cb5f91f0b62a5f20e1 +b06fa9489123ab7209d85e8c34d7122eb0c35c88ee6c4c5e8ae03a5f1ae7c497c859b0d62e0e91f5e549952330aa95a4 +b5cd71617ff848178650e6f54836d83947714d2e074d8954cfb361d9a01e578e8537d4a42eb345031e3566c294813f73 +848d39ea2975d5de89125a5cbe421496d32414032c1e2fbc96af33501d3062745b94e27dfe1798acaf9626eabff66c79 +ad35955efd5a7b6d06b15d8738c32067ffa7dd21cf24afc8ea4772e11b79b657af706ce58a7adcc3947e026768d9cdaf +aff6d7c4861ff06da7cb9252e3bd447309ad553b2f529200df304953f76b712ac8b24925cf4d80a80b1adaa2396f259a +b4b88d35e03b7404fc14880b029c188feecb4d712057f7ba9dedb77a25d4023e5a2eb29c408fde2c0329718bdaf1ff63 +88e96720e2f7c63236cca923e017ca665b867ba363bc72e653830caf585d802fad485199055b5dba94a4af2c3130a6f6 +982675dc0299aeedba4b122b9b5f523ca06d54dc35da0f21b24f7c56c07f4280265fb64cec2f130993521272c3470504 +95c77d418490e7e28293169cf7a491a7dcc138362f444c65b75d245c1b986d67c9e979a43c6bd8634dae3052df975124 +8fd6c4dff54fb2edc0bdd44ccd1f18238c145859ccd40fbfbc1cf485264445b9d55ffd4089c31a9c7a0543cc411a0398 +b153eb30af9807b5fe05d99735c97471d369c8a1af06b2e2f0b903b991eb787ab5a88c6e406e86225582acf8186ad5ef +826b55de54496751b0134583b35c0c2049b38de82821177e893feeeeb76ceeb747c7a18312cb79a6fc52f2c18f62f33e +91650d7205b232c495f1386bea0c36e136a22b645ffd4f5207f5870b9ce329c44524781c983adf2769f4c05b28a8f385 +b8d51a39162ebb38625e341caacc030913f7971f178b3eee62dc96f979495a94763ea52152198919c6dd4733bc234f64 +a1fbd3673f2ae18a61e402fe3129b7506d9142f2baca78f461579a99183c596b17d65821f00d797519e9d3c44884d8a6 +b7c5f5407263398cf0ed3f0cf3e6fcebdd05c4b8fd4656a152cedcdbf9204315f265fd8a34a2206131585fad978a0d6c +94fa71804e90f0e530a3f2853164bc90929af242e8703671aa33d2baad57928f5336e67c9efdcbd92c5e32a220b4df07 +b75dcea5ad5e3ed9d49062713c158ebc244c2e4455e7a930239998b16836b737dd632a00664fded275abe4f40a286952 +a02f7b37fc30874898618bfcc5b8ff8d85ef19f455f2120c36f4014549d68a60a0473ddfd294530dfd47f87fbd5e992d +8b48e1626917b8ba70c945fe0d92d65cab0609f0a1371fd6614d262d49fe037f96991c697904d02031ec47aab4b32f48 +b368f02c21d4af59c4d11027e583ca03ef727f2b2b7918ef623f529ceac76753a05a4ce724ce2e018da6ecc5c1c1261b +a95cba06eeae3b846fc19a36d840cbcf8036c6b0dc8c2a090afcf3434aaf5f51ef5d14b1e9189b1d8f6e4961bf39bbf8 +b32ca4dfbeb1d3114163152361754e97d3300e0647d255c34ec3025d867ed99e36d67ebafe8255b8c29be41864c08edc +8e4eddefa27d4fe581f331314d203a6a0417c481085134d8376898f9260f133e2bf48576528d62adf29953ad303e63a7 +92b7d5505833f00d5901ae16c87af028de6921c2d1752a4d08a594eb15446756ea905b0036ae6ffe6b8374e85eb49348 +b50e9018d3c4e05ba9b28b74b6634043f622d06aa8123da7cd0bc482b3131912149214d51bdfd887484422e143c3c1c0 +ab980a2f5317dfcb92baa4e2b3eb64a9ac2a755da6c11094d57e781ae5cf43e351824f1dd3abb4c6df75065b3784210b +aaabb009dfcb0bae65a0aee26ed74872c226965c52a6ed0998209e020a9ee806297dba4b15845cf61e1a514de5d125db +a1fe78f67000ebb6e90fe33e1a9dd5489be6e15fedb93b2a37a961932b77137fe85d46e89a132ecf7bcfb7aa95e16757 +85bc6e7d660180de2803d87b19ed719d3f195ea0a92baf9bfff6113c743f4237f51355b048549913e95be8ddf237864d +87a167968c4973105710e6d24ad550302ee47fe1f5079d0f9f9d49f829b9f5c1cd65d832d10fe63533e9ad1fa0ad20f5 +b2ad1a7b95b8a89d58e0b05c8b04ae6b21b571d035ae56dc935f673d2813418e21a271cccaf9d03f0d6fa311f512d28c +8268e555319992d5ac50cb457516bd80c69888d4afa5795fcc693d48a297034f51e79f877487b6f7219cfdd34f373e14 +b235411f1f6d89de3898642f9f110811e82b04ad7e960d1dd66ec7a9bf21de60e00cfabcd3004f3b5c4f89f5d9c7422a +b6963effcfe883f7ed782a3df3c40edd70f54ceca551859bcccb5d3e28fd2c1fcbdd7acc7af24a104687fd02b53c704d +862645c944e1e2909b941578cc5071afd7353fed1c2c99517e2de7573037704ef5d35accf6ec79b8269da27564209d50 +90f585eeb1a053e2f18c1280c9d6a561c0bc510b5f43cd68370ed6daac4b3749852b66c371397b6a7c1ece05ee5906c9 +876d9a3686feb79ce781e87ac3e3fbeef747b6ab031285e808c8a73f73f55b44507850dcaa745c0791d2cae8ad61d74e +a7ecc3b8c10de41a7bd9527228a0d3b695a651a5b5cb552a3664a887077d39ee60e649aecd68ed630da6288d9c3074ad +83529f1f2b4dc731ea05c1ee602fa2e4c3eebe2f963f3625959ba47657be30716d64e05e8b7e645a98bf71c237d9c189 +834ca6b14428c30a4bc8d5a795596820af6f3606f85bee9f3008f3fb94b3adffa968d21a29e2588d7a473d8b5d3a8b42 +b8d08cd8b73430984fd16e8db0525ae2b76253c92cccd7b3470add4d12d082eafb55a72bde04870924d0bdaf61f76c5d +96ef32df669690c2391f82136fc720231e4a185c90ba79eef7beaadedf7fbeb56ed264825564bdc7da01829b47f4aa88 +93d637b2f04d71891a80a1ee93fd9c9046d671bc4c15c4e597cfcc36f4ae85a7efc111359628965fd10d36c39129b160 +89f28dd3f7bc43749d0e3750c136385d4ffaf2c40354d3be38341416d755de7886d8108d83721b36f99feb3bccd73c88 +ac6392e274659f4c293e5cb19859828f101959c4c0939920a8dfed0e2df24a0cbf89a7aa983e947318c58791c893928e +83b2d4ce42c2fa0f672cd911365d1f1a3e19f1c38f32bedc82820ad665d83ae5fac4068e4eca6907bd116898966fed92 +b5e0144d6e59a9d178d4ee9f8c5dba18d22747fcdf8dc4d96d4596a6e048e384cd1e211065f34109c9ed6b96010d37e5 +b1a65e6b38c9e84b3937404d5b86c803c2dac2b369a97cbf532cfdd9478ee7972cf42677296ad23a094da748d910bc48 +849d7f012df85c4c881b4d5c5859ab3fb12407b3258799cfc2cb0a48ae07305923d7c984ff168b3e7166698368a0653d +84d9b7ee22bf4e779c5b1dd5f2d378ef74878899e9dbb475dfdcd30c2d13460f97f71c2e142c4442160b467a84f1c57d +964e497ef289fac7e67673a6cb0e6f0462cd27fc417479ecb5eb882e83be594977fb0c15a360418886aece1aaf9f4828 +ae1226222098a38ce71f88ab72de6ededb2497e30580e7ae63d4829dcc9c093bdd486102b7a7441cb06253cf0df93772 +a72865b66d79009b759022e53b9eedbd647ff4b1aab5d98b188100d01fc6b5d8c02b80eb6f53dc686f1fdda47d4722b8 +93aa8d7d8400bdfa736521133c8485c973d6d989ec0a81db503074fe46957a3999880fd9e4e7f44de92adf6ac0abe99b +a75e5ab84399962ada1f9ebcfc29f64405a1b17cd0a983950d0595b17f66386393d95a5aa4c6c878408984141625141c +91b1e5e75f4b55ec2e8f922897537082a1414eedc2bc92608376a626d8752d5d94f22f0e78ea1970eb0e7969874ad203 +83bf9c308424ef4711bfa2324d722f550d95f37d7f7b4de0487ccf952b89d7219ca94e7fa25bee60309efefd9a0e4716 +a42060476c425ff7979456d3c5484bc205fb1ef2d7149554a4d483d48e2a19119f708c263e902943bcf20a47e6c7d605 +8170c45ea126e6367aa5f4a44b27f7489a5dd50202cb7c69f27a2bdf86d22cf6b00613b0080d75fca22439eeaaaa9707 +8e5a82da70617697e42c6b829e1889b550c9d481408fe4cf8dc9d01daccabdec01f9e1b8c27dc84902a615d539bf9bc6 +80606c51401d0bf5f2700ebce694c807ab1f7d668920bdcccef2775e0939472419a8f404567bd4f9355095517eb4d628 +a40314565d60d0ddf8995673e8c643b1baa77a143b3d29433263730a6871032260abc1320e95af8287b90aa316133da0 +a87e07e84435f9e8a51ce155cd3096aa4b20d18e493c9dcbc0ac997ac180f3a255bf68ccd8195f2564d35ec60551a628 +84d2ab98416643c457bf7ddd9f1aa82967ecea189db08f3558f56803fe7001693ed67ec6ca8574c81ec1293b84a7c542 +937c3b955889ceae77f28054ce53d75f33cfe3a04f28e049cea8b8ade2a0440d5e2e8c4f377e6c1ae2115d68cc95fc16 +885a911f16845fe587b15ce7cd18cc2a84295bf609732340f74e0f5275b698cffed3e9aa1440e19e6940a7fa8f24c89c +ad90059a50c399996aaa0a10a8f637b7bab0dd5d9100301f0159a2c816596da55c30b2568d1717705fd2826b117a42d6 +828de9ff1e095c189da1f1ee18009afe14613ac696025add6f4e330488e02d5f1a90be69edd9a17bfb3355a0ca77b525 +b7aedb8394064a58dd802be6457555c0cf7b94805ed00cc66f38449773f4b1865feaee3a6f166eb51b2123b89d853a4d +b09c564ff37ccea34e90f2d50a40919a94c2e10d4fa58ffeaed656f88f9f4ae712d51c751b1b8f443dc6c9506d442301 +b24882d66b2ebb0271ebb939c72308d81f653940e70d6f1bcaae352f829134aff7f37522cc42de9e7fe6243db2c4806f +8e6f8dd906e0d4eb8d883f527e926ad1d8156b500c4cfa27214450c8112267c319900de2443c87bed1e4bb4466297dd5 +ae42f4578e8d79b6aa2dca422ada767e63553a5ee913ff09cb18918116905b68f365720a1a8c54c62cce4475ba5cdd47 +ade639bcd5017ea83ec84689874175ed9835c91f4ec858039948010a50c2b62abc46b9aee66a26bf9387ab78f968b73e +8d310a57aeb123cc895ee2fd37edc3e36ce12743f1a794ad0e1a46d0f5e4c9a68b3f128719ed003e010f717ec8949f43 +8606c086fcf3e2f92c1b483f7e2a4d034f08aef1a9d5db9e8a598718e544b82544268a0a54dfed65b4d0e6027a901d47 +8ccd95dd673d8cfdfa5554c61bcdbe6bb5b026403a320856fe51571e7c59504fe1c035f2ad87d67827339d84c0e1a0c6 +955a7cb4afcf70f2eb78756fc3a82e85ab4330eb89a87117294809beb197d1d474001e25306e8ad71daab6928abf6d64 +ae6b44ec6294736ea853ddeb18fc00cce0ac63b38170ff0416a7825cd9a0450e2f2b340d27a7f2e9c5ac479b4cb8a5fe +a88ec3f12b7020dd593c54376597b056e70c772c0ec62c24c5bfd258b02f772161b66e5dcd95c0c0fceb23433df9ff23 +b4a83933b4de552dba45eedf3711f32714e58ae41d4dab8a6114daeb06e90a5a5732c70384150d04124ac6936ca9804b +b8b7c4fa549b0fa1dc9c1f0af0750d6573f1648767751882d41f0dd7e430e3934590757e1c8b436ac35381bdde808117 +ab598b911234a98cfde07234cfc0d2fddfc5cb9ea760212aa3e175a787ce012965c8fcfdf52d30347f5f1b79cf4a0f54 +a9d354f9dfbd1976e5921dd80cbb56b2e15df53ce099ecb4368eff416998130d7830209282aaf1d4354129845f47eb80 +8c889afff546c721969e4d8aae6e6716ad7c2e9c1914dd650e30419ee77d630efb54dfffb4ec4ff487687b1864bf5667 +94ed2fa79116c7c8c554dc306b1617834dd3eab58baf8f0d085132c4688ca4a6bd38420281283678b38970a3f02b9a94 +944fdc8f0516d22f1672193d183833d3e3b043e26807fb2123729a0216c299785b1c4e24b5aa56e9bbe74fa54d43e22a +a48521454a3e0c10a13d8e810fad9d0522c68eea841821a8e0e57811362f7064a8f9c50f79c780a02df7df8c277feaef +8f3d26670ab55e1bd63144e785203373b2b13b76cac305f0363e48a6339fac3364caa3fceb245527161fc2fac9890912 +b4d6fe71001cb4141f6d8174dd7586d617cfccb54471e1fbce30debc2b1dead62cab29565abb140b682811c6231acb03 +91dc8afc4934fcc53ef851462a055cc1c3c87d7d767e128806891738427606d2fbfa832664d2a7f95f8ffe2cf0c44dc6 +b297eb432c74071764272c1b1663547ba753e66bf026643bfc0e42a9c5cdfb05a88083ad67d6ddfe6ab290678c607b29 +b343d1df85be154faeb5b21741a5ac454ca93f70a0b83a98f5901d1be173a1b2969d43e646363c5d4975924e1912599e +b2d74a66e4dfc41128aee6a3f0ff1e5137a953ed7a2a0ab5a08d7ea75642f12bd150b965c8f786ad0caf55ef7c26be4f +a54141faa8dd9a567c3cd507e4fc9057535ffe352fa1e8a311538fe17e4a72df073fbf9371523e5390303db02321650e +8e229a58f1acc641202d2a7c7e120210b9924e048603b9f785a9787ad4688294140ef3f4508c8c332d2dedafff2485be +9523554c11d39b56e6a38b3b0fadb7a9a32a73c55e455efdcfda923aff1e9f457d1b7cbc859b5ecbb03094eae8b87d38 +a199ffdff1812aaea10cd21a02b3e7bf3d8e80e501aa20bb2105b5f4cb3d37265abcda4fd4c298d6c555e43fa34517f8 +97f1285229b07f6f9acd84559afef5daad4320de633c9898b8068c6cb3b19b4468b4445607559ddf719f97d2410e2872 +a1dfff82908c90fc38ec7108c484735f104e6ce7f06097e1e80f6545702b6a0bc2a2706203cd85162edb7e9294fdedba +b12a706311c617d6c19e964e296072afce520c2711086b827cff43a18e26577e103434c0086d9d880c709df53947b48c +88503a6f48cef2f5cd3efa96a5aacc85dc3712a3b9abbb720a2cff582a6ea3c2afc49288b6832c8599f894950843ac11 +83ed63e38dfbe062fe8c7e6bc2eeb5a116f1cc505c6b038990038de6051281f9062e761ea882906ccff69c9c5b8a4a25 +911090d5d0231dde1189408dca939daddcb69a812ac408d1326060f0220781bcc131c9229e6015540f529d9fb33d9b0a +8a8352f1d9e5c7e80276e4448f997d420d5a7e0e2d5be58ae4106f47f867d1caa478b2e714d9c3263e93e5cc4c7be08b +9362f1ea9995f9b3850ebb7c8d5bf95927ab5ea25ee00e85d7456b3bf54459798b1fffde049d445c0d0587b0ab0a1694 +8859502b391273f4a00b6c0e87e5cdae676b7baf6c402f12b3360db6a5dfb4931ece4da0e1e4d98c7a71c3d01a183a9b +a9a5edf474120f9bbec9485d8b1e6f83be68b10de3d765219b0bf3e5d2840e478f1fb2bf806d78a8b8ad22ec50cf7555 +82c75daf983b06e49f0d75a042dfaae8cc92af050293d9059d6e8b01ca3ab2597e7adfc1159ed805513488944e739fa5 +a5cf240f04a9bfa65b811702c923d209e01f9535e217fa55ae3e0d1eb3257d6749e5587e727091e860609d1df29a1305 +95608ab8ade1c9fb814bad78d9cc99a36ad3e9562d5319830e4611ceea508ef76be04639294be9062f938667e33bce6e +8e44181f35c38b02133473de15560ae6588ac744cfdaf5cdfc34f30ca8e5ff6c85eb67dddc1c7d764f96ed7717c89f06 +8007b6ddece0646b7e9b694931a6a59e65a5660c723ebdffb036cf3eb4564177725b1e858ed8bc8561220e9352f23166 +a2d9d10fa3879de69c2a5325f31d36e26a7fb789dc3058ee12e6ccdda3394b8b33f6287ba1699fce7989d81f51390465 +81993d0806f877ca59d7ffa97bd9b90c4ebf16455ea44b9fe894323c8de036c5cc64eacf3f53b51461f18fa701a5860d +a20030f457874d903b2940ec32fa482410efecb8a20e93f7406fc55ab444e6c93fa46561786e40e9bf1e3c7d5d130bc8 +80c72d4985346ac71a231e7bbbb3e4a91bf50142af0927e8eb86069303eb4ce7fca1aa5b919d5efc82f2f09b41949acb +91b857d2f47f1408494940281127ba4b9ac93525788e700889aa43402eedea002e70eded017f5f5263741ed3ee53a36c +97445d007f08e285ea7f4d25e34890e955dac97448f87d8baa408e826763c06cbd58dd26416ba038d6c28f55bcea2d3a +a409c89526c2886f6a6439e2cd477351fc7f886d1a48acc221d628e11895a4eedd426112a368a0dbd02440cd577880a8 +a2c6adc7866535f6ffc29e00be4a20fa301357e1b86dff6df5f8b395ad9fb1cdc981ff3f101a1d66672b9b22bd94ec0f +8887fc53ffc45e4335778325463b3242190f65ae5d086c294a1dd587f62dd0d6dc57ca0c784bf1acaa5bbba996af201c +9731d3261a7a0e8c7d2b11886cd7c0b6bb1f5c57816944cc146caa518565034cea250eeee44ddffaeb6e818c6b519f4d +afe91c706efb9ee9e9c871e46abde63573baa8b2ea2b61e426cd70d25de3cc8b46d94c142749094287a71f4dfadd3507 +ae7bdf6ecc4fc0d8d8a7fa7159aae063d035f96ca5a06b6438b6562a4eee2b48d9024dbe0a54cfd075eac39b7a517f2b +a382e5205bfa21a6259f42e9ebc11406b5da2aad47f7a722212fdd6fef39117dd158a9991ff95e82efa0826625168a1c +862760c80bf44c2d41c2a9a15c887889eaeea32acc894f92167fb6f72593377c228499f445ccb59794415597f038ac9e +b4e96595a91a611c4563d09f29a136a4c04f07be74dd71a6bbabc836617ecb95494e48971a8229f980b2189fd108d2e5 +b5e7200357317c36244c2e902de660d3c86774f7da348aca126e2fc2e2ba765fa0facd29eebcb3db3d306260e91a6739 +a64c7133156afee0613701189c37c1362e2b4414f7e99408e66370680c554de67832c30c211c2c678dab5cfcdcecb3f7 +88f4cb67b1db497a91a0823ee3541378133eb98777842d73e43ab99efe8aa52fa02dfb611c1691be23684618394988d6 +89a9382a147d7387d0ff9516ee0c75cd1f8ee23333f4a2c9693d1a8cbe03680bc5b10c43c238c2190db746cac409bf39 +ad510bcc067373d40b05a830bf96fac5487de1ad5b708a13f62484c09b00fba6c5b00b981004e5ab3f28e55c9a5bce26 +8384156d7117675547279ad40dc6bf81e8f9a57b2d8cfebeea6b9cd1d8534dc0cf704068bc3ba0815010cd8731d93932 +a818fb76e53165b2f86c7f2317d64cf5e45f48405a34560983cd88bfbd48369e258ce2952233a8ce09c464e07afcade6 +ab19a4ed90527e30796064634b66cdc023bc5966e2c282468f5abef7879fc52986d5bb873a796b077d10e7b374b60309 +a17dafe2484d633fe295f8533662631b0bb93cdb4e7cd6115271f20336f602f7f8b073983cd23115093c7f9891c4eef5 +804acbc149d0334c0b505a8b04f99c455a01592a12f64d1ec3b82b2f053ccc4107e47f418f813d6f400940c7c8700a4a +965e097a825d8511d095b247554ec736bcb3701ead3ba785bd425cbabd56f4b989764e0965a437fa63e7e16efd991fc0 +b6701675ca27d7a4084f06f89bd61a250b4a292ee0521b2a857c88c32b75f2a70b97f98abce563a25d57555b631844e0 +abbdf65fcbdf7d6551ccd8d6e5edc556f1ecd275ccd87ee2bda8ea577c74615f725aa66e0911e76661a77f5278e0c2b9 +ab715ae372c900239a0758a3524e42063afc605b8fb72f884dc82ab9b0ff16715f3fb2fd06f20f15f9e454f73a34e668 +b45f41ea1d25a90af80a8a67c45dea881775fed000538a15edc72e64c7aa435a5e4375dcdedc5c652397c02b0bc61b16 +86f7be9252f8ed9078e642c31a70a09639899f7ffcd7faaf1a039fec8f37e1fa318fba0ed1097f54fc55d79900265478 +a30e5ed4277dd94007d58d5a3dc2f8d3e729d14d33a83d23c44ddfc31c6eac3c6fe5eb13b5b4be81b6230cfd13517163 +87e723d916f5fcda13fab337af80354e8efe6b1c09ae5a8ceeb52df45bfca618eb4bec95fefef3404671fb21e80bf9db +a521b8a04dc3abd3e9e0454b9a395b3638e5394dc2d60e97fda61b0a1880d1d73a64a4633f3d7acbd379bde113240d03 +851686c79c5403d5f05fbaac4959fcbfdfb51151bec55e10481b3c16e3be019e449907ae782ca154f76a805543d5755d +8ec1929e746b6c62b0c3fdd8f4e255e5c707e6e0d8d57ff9e409ae2dd6e76fdb50af923749992cf92d1b5f2f770bafbc +9175f7b6820d47205c9e44f8c684833e1e81da46c1fdf918a4dcafbc3231173f68370d442a20e45f8902bcab76a4e259 +b4f66c698115333b5ac00c9fe09aa9e1e9c943fbb4cce09c7d8a6ed4f030e5d97b48e944fd6d3e69ac70f1ae49d35332 +b958878b875eead61a4416a4597b1c567ddbb1eaaa971033f4a656f01a277822c1f4ea3972045156c2a5a28d159f5ddf +8188de8ad5258024d0280137a40909d24748137ac7c045dddd2bc794eac8edd5850b9d38f568fa8174b2c0593bb57e96 +91152c7bafce7a0358152221081bc065796fa4736bfc7d78076a0a6845287cde2ee2a2c9b96f500297c0a00410634888 +a5328ab939a2d3bd4c21e5f3894c02986b6590ad551c7734be3f4e70380eb7bc19629e9031b886ce3b4074ee4edee63a +97c4d49db40e266bcedaacb55edca4e1ebf50294679b271f3a2332c841705089b5ba96ef2064040fa56c36bb1375a8d9 +85cf0514f340f9d865b32415710d7451b9d50342dbf2c99a91a502a9691c24cd3403cb20d84809101cd534408ddf74e8 +950c3d167f59f03f803dcba3f34fe841d40adc31e5be7eefff2103d84e77a7cbe4f14bd9c3dfa51cde71feb3468a9c00 +96a69624e29c0fde3b92caf75a63ac0f3921e483f52e398652f27a1ec4e3cc3202f17af1f66224731bc736a25638d3e4 +aeac4170cf4b967227f66212f25edc76157eb4fb44c84190b520ecc2946470c37da505790e225fd1b0682bef7fc12657 +a94146a04e3662c50c2580ae1dba969cbb3fb0f43a038729c9e8be6ed45860b2c7de74f248dfa50ccdbe2ecaf3f2b201 +917b8e2880e85b8db723631c539992ec42536146e7091d4a3f87d37f051b5da934d84393523814f19962c78e6cb12ef8 +931f140ff8f7de79e399f5cd8503558d566b5c2ab41671724dd38aed08dd378210f01ac8fa9911f3047993dbc10cf8c4 +859eb9b560bc36273694f8ae1a70d25e7f206013597c4855a11328162ba1254bb736f1ae41240c8ec8dea8db035e08f2 +b4ad2cb2c3a3e6ab1e174f2dbfb1787a8544f3c9109215aa6d33265ef269455e3cde9858738b4fe04711a9cf9050e7d4 +8a3b342b87b19c0cdb866afff60317e722013c02dee458ba71e7123edc8b5a9f308c533b9074c7dd0d684948467502d1 +89185ac5cc5ea8f10a1f2a3eb968bb5867376d3cff98ef7560b9a0060206c4046ff7001be10b9e4d7ad0836178eba7e4 +845f48301f25868f6d0f55b678eab1f8458e3321137dba02b4cfbb782cbc09f736a7585bf62f485e06a4e205b54a10b7 +931a6c523d4a66b51efadb7eefadba15bf639d52d1df5026d81fd1734e7f8d5b51b3f815f4370b618747e3e8eb19699c +8eb3a64fa83dcd8dd2258942aea3f11e9cf8207f2fdd7617507c6dae5ea603f9c89f19d1a75d56eaa74305a1284ce047 +912a5050ed6058221d780235fb0233207c546236316176a104a9761bc332323cf03786dbac196d80a9084790506e0a88 +945fe10ec8dc5e51aa6f8ba7dace6f489449810f664484e572bfe30c2fe6b64229f3c8801e2eb1a9cb92ff3c4428cdf7 +b62383bf99c7822efd659e3ef667efee67956c5150aea57e412cbd6cd470807dfaad65c857fada374c82fcfca2516ad1 +a727a31c45b2970d08a37e169ea578c21484dde15cb11f9c94eaaf3736652619ce9d3a44e7431d50b0e75b658ebbc1da +97bf54ea9b84b82e4616027bd903ef6152439f1c6a8e1bae6db1d10fdf016af2cac10ff539845833dfd1ddad1403aa8c +a08cf36437e010e59b2057aedb7192e04b16f1cc66382cdef3490b7ad1544ae51f03e87cba0fe43a275841c247a2a0cf +acafab9fa28c1a607df2246490b630ddda1ecf0885ad24c2ecb2c2c1b7b9c7de8066714bf5b9b25f61981d08576789ec +851f0375128d2782586223467d0a595f4c5baa79616622a32f7d6ce1f08af06f8a109bd6527f88d93367dba17be661e8 +a2f1187c2a7cbf776653ff834ed703dd32e68eaf36f0700709be929f4c0ce5fa1d9930d1e3ea2aa01c7a16239e66cb33 +b3721f4a5d24ca112f020cb3f849543bf0e7f84b470fb00126ae80aaaa6f2c208d8359cd82ad9fbafd3ef2ac70656fb2 +98773ac3ce9528c73cfd8e7b95976ce597f67e146357642ac4fb6cb35046f3f39cf6c4a7b5af5c7740dda358aa0d2d08 +92c883a5d820541692af75be1b25dd4a50a4b91f39f367a551a7d5ad6065a26b60d68221a01e4950559717b559c2626a +b82e46dd25fd1234dad26fbcd8bb5177d7b87d79d362ffb9c2f6a5c16eb2ff324d135996fcd6274d919634597869d772 +82a53ed356ced5e94d77ee2a7f6e63f2ad8240aff2d17c5012cf5d1f18512c88c24793339b565dfbb659bd7c48dcbcd2 +84d20c7859b35a1cae1ff2b486d50822f9e6858b6a1f089ce4c598970e63e7c0f7dfbcb3337845e897a9dedf9d449dd3 +974892e5cf5ee809e9353d00e9cd5253d04826a8989d30cf488528c5dcdcad7650e23b4d228c3eb81f6647d2035a9e02 +b2327854910dbf3d97fe668da5fc507e179c4bc941f39bdd62e8b6035f004449c467240f656417e501f32dee109f0365 +88888f73475613d45d0b441276b1dd55835b69adfb27e26c4186936dae047b85478cca56be8dc06107b89a28f3bbb707 +836ba22e40511feff81a5dace3df54e2c822b55e66874dd1a73929994ec29909ffc2a8e39bfc2d16e316b621eb4a5ec6 +a754cedcccf4165a8d998f326f3f37d2989f92ca36d9da066a153c4aab5a62bb0011896bcbf90f14c18e00488d4123bd +86c26fa9584314292c4b7d6fe315f65dadd0f811c699e6e45c95a7a4ea4886c57dc5417b67edd78e597d037c7689568e +b205589648aa49ef56637712490e6867aa3b85b2b31e91437a249fb51bdb31401bff57b865c9e27293b30014b4604246 +afab0843ede582e5a1898ee266235066b94ea378884eaf34919ceaacc0e2738e1074b6ed41e0a1dd9711563e24f0215d +996ed65fbcab7611eada5bd0fd592d3e44705098b8b1dfba6dcdbdcfa1382fe893fa55270a0df0be0e1938bd71ab997c +881bc448a5ef8c3756b67ecb1a378a5792525d0a5adb26cc22a36c5df69e14925f67c9cb747a2f7e5f86ba1435509d7c +b219303c02c9015c6a9a737b35fb38578ab6b85194950a0695f7d521206e1e12956cd010d4d6c3bc3fafd6415845d5d1 +91748829bbd005d2ec37fc36fee97adaccb015208b74d2f89faa2e4295679f7685298f6a94b42d93c75ca9d256487427 +a41d6fd33b9864ebc404d10a07b82ba9d733e904875f75526d9a1f1c1c08b27160dcdb9023c5d99b8ff8a3461d57281f +b68978d39c97d34f2b2fea61174e05e05e6e49cde587e818b584201cf59b7096cf1807b68f315119c6db8d6110b28a9f +b64e66cec798022d64ce52477475d27ea7340817fe7f570617f58c3a9c74071d7ea6b54743d4f520b62aecad9a3a6620 +87b2b9e1c1786b7824f239a857024780a1457e51c64599b858118885833fb87a17d408bc09dcc0607d15ec1e53683a74 +9814799bac07dab4f0c934cc3c051676ca13abd49cf8d4739864e5bb9f2a8474897695113f49239f28832a8658332846 +806931a1526a843a9c2045943d616a8102b02b1f219535a1f1fbda659a1244f1bfead52ca7f1851ff8a97169b91c9ec0 +b8678249595a9641c6404c35f89745b93d8e7b34d9d44da933a1b2f1606972624c5108f1c04eb42e454d0509f441ed9e +81426714851741045a4332eb32b6dfe6422a4a2e75b094fb7c3f37da85648c47ee8af1e54ba26f4e1b57ebe32d0e8392 +b7a1875ea3f119fe0429fd9068548f65cf2869f8519dbbce0b143e66127cb618c81d7578e8391d676b2f3963e9d87f43 +872220a803ea0c6294cdc55aceea42cfacfd7a482982bcb90c0361c351a900c46736a890609cd78f02fb5c8cc21fa04b +974f0380197b68205ff4bb2c9efe5626add52c0ad9441d7b83e6e59ddb2ed93ad4e9bbdbf33b3e0a206ed97e114ea0f2 +a840f2d9a74fca343aedb32ac970a30cbb38991f010d015dc76eb38c5bb0bfe97dd8951de925a692057262e28f2b4e9d +b0913c3ce61f12f9fdc4be3366ed514c3efc438f82fc58c4de60fe76098fbc033a580ec6e4531b9799611c89a8063a66 +a0180d533eee93b070dac618be1496f653a9a0e4e3455b58752bf1703ec68d0be33ec0b786f9431ef4208574b0ad316e +a4a6b871bc95d3aa57bed90e14a0a1dda6e7b92b7ae50e364593ce6773fbf736672b1f4c44e383af4c3cc33e017a545a +a3f44cf19fe52bacc4f911cab435a9accbe137bdbe05d34bdd8951531eb20b41d17e3540e8d81e6b3eea92c744562ee5 +ae6b6d0ff3b30ff0b7f9984ef741cba27ffb70d558de78b897199d586cf60622ec2d8a9d841712fe719cf0f97628842c +87abf72f98c81d6d3a57ab1e224fe4b502ab0d8090d8abc71791271550b721c220d4e2e7da3be94a20c0e63d98e39a50 +b2f73ebdfe7133af57353052f4599776e16862905e64d97e1020c4bb84132e476d1ab79a9fb71611410f3f9d56c95433 +ae1a928253af2b210d31e1b64c765fcbd20a96b8d53823a6b9b6e7fc62249abf4a66c6a6aedb0b687e7384af9a845e0d +99c54398627833ca1435718154de171a47c709e4d5c58589fdabe62e72f2a7a11ae561bc31d7cbe92df4aff23e08cd0e +8a1310bbf1a31fae18189479f470977d324dec6518a5d374ab2ffcc8f64412fb765df57d2ddf69b9a6efaeb2b4c723b8 +898312c6c0d3d3438229b19a8a233eca8f62f680c2897f4dd9bbcacde32c5996d56ac0e63e3e9360158761185491ce93 +81b3f965815b97bc6988d945496a51e4a4d8582679c22d138f3d3bd467ed1f59545da2d66e7b4c2e0373628ae2682686 +b9aca91c6e6f4199beb6976b28e0e35e36e8752618468d436b1cf00d8d23538d0747920e5b2c31f71e34dfe4d5c86a0d +b908f4aa18293295b8cacfda8f3ea731bc791074902c554764c603ab9a1de1bbc72654fd826bffc632d95ce9f79c27d9 +a7316ae1baf4b1196961d53be7fe36535499287aba9bc5f3bed4323039b4121b65bb0bd15a14c1b9cd8b65ede3566da2 +815e39208f205c5fac25ac9988c14a62ab01657c7737a24472d17b0e765644bc2cbb7ff1e8ea169b8b0b17b6996c4704 +89a451d2b740cdaa83ccaa9efb4d0ff5822140783979a4fee89eda68329a08c018a75d58bd9325bdc648b0d08340b944 +8cd08f768438c76bae6bee1809dd7be38ec42e49eb6a4d6862db7698f338bf6b4b409088e4f3d1c5bee430295b12a71f +a4bd8c312103a4bfeb25b0cfffec7a1c15e6e6513b35af685286333c1dce818ffeb52826f2f5bada6b67d109c4ab709e +93afbef5382d89fa539ca527f3e9b4a8e27ab69fd5d5023962cc6d8932b33cb4dfc5f14343e1a3749bfd5e100c9924e5 +8d8e69d046992ec9ff14f21840809166cae8e0e9e7c8f14fb29daf163b05abe6611daa4010960e1141c5ab24373fb58e +96f8e72e96ba673c9265e9cc312f6b9c3b931745fc62d2444d59404bb08e5fb02ddb60715181feb9971cbd954526a616 +8d444c2b8e4d0baadb79e3147a2ee20f1bfe30d72eb9a02f15d632185fb8f4e8c3116066f7de1ebfe38577aaccacb927 +971410c0b10e3698f4f64148b3d2148fc6a4a22217fcf4253583530a9d6fbec77e2cf6f7bb5e819120a29c44653de3fc +99e7e1857bd5ee57007b7b99494b1f1c6bf1b0abd70c054770427d59a3c48eda71b7de7a0d7fcf6084a454469a439b41 +8c8a4cd864894f7a870f35b242b01d17133cb5dfdf2e8007cd5f1753decc0d1fd41be04e1e724df89f1d727e760fdb15 +890a24328bdeaaadf901b120497d1efa17d798f6f4406661e46ecdc64951f9d123d724ab1b2b49e0e9a10d532dd6f06c +a7cbe1f42981c9518608569a133b0b449e9d67c742d62f0d3358112c97e65ee3f08ec0ff4894ce538b64e134d168e5c8 +87c976dea77b3b750c3a50847f25b851af95afbaad635f9bb9f7a6ba8f0c4faeb099dd777cf7eac41072a526474cb594 +9882aa5e9bcc4ea2dd3de4bb5a0878a672bea924b50c58ae077563b6df0268910a60e969d3da1694ae7394ad0d9acd3d +90d35ce677327c461fb5dcb032202e851af1d205e9d21a34ed2b95635f13f8fb8dfa470ea202ccfa4b08140d0cf1d636 +b3b4cbb521cce2b681e45e30a4d22078267e97ccdbdc611b2c9719705650dd87e0ca6e80cf2e174f8f8160be94232c36 +95892b00478e6b27ed09efe23a2092c08e691b4120336109d51e24efbf8aba31d59abf3cf55c0cdab1c210670b9743ba +8643018957fb8ef752673ad73102d0b928796c6496e22f47b6454c9ed5df784306f4908641ae23695db46ebfcfb0b62b +b166ce57669bf0543019ecf832d85164c551c3a3a66c05b17874bccd5d0ae87245925d6f8edc62ac13dbd5db265823a2 +89fb4800ce4b6c5900d58f1a216ad77a170ea186f3aa0e355840aeedcf374e92a15ae442800c9d60334544be020b17a4 +8c65e586215a97bf11ffc591bce5147b4e20750e82486cc868070c7736c3de697debc1f335674aef24b7afdd41922d93 +90f68ce0c97d2661d3df1040ce9c4fa106661a719e97c7b2d7c96f0a958930c57d6b78d823a2d41910261ae1f10e7b0e +adda85e1287371ccbe752aa2a3c1d5285595027ba4a47b67baf7b105a22fb8548fa2b5b3eb93ca6850ecc3995f76d3dd +b26535d218f48d6c846828f028c5b733594ce01186e22e412dd4f4a45b3d87d2ac1bfe5d54c987e4e8aaddeb86366d7d +a081bd86962ea3d4fd13df6481f3aeaabdd7ceae66f7bbb913e601131f95d016cf147d045253d28457a28b56f15643c8 +b3d852cef4c8b4c7a694edbf6f0e103f3ae7f046a45945c77a1a85ec8dad3423636a89058fafc6628aabff4dbb95c2ba +b424ffc94e06e6addc90a6324e0482814229b5902e2a266d0c2d716e40651b952bc9f00d7dad9b6050377a70a72c7f24 +b2cafd908cae0ca22eaa2d9a96175744897a20eb7b0a6d43b0098cb1c69e3cb55373888201e4ed32816655eb7d8a3dd7 +b61177ecf1ae9d7e7852d98cbf6080d9f1e33c90f2436720b4ea4690437e8c7850c3754768fc1312cb4e838d855c5ccc +81b486644e1ae22cf0ba3a37e1df34dc186c82a99ab35ad6f475c37babdea574ddfbe5811d4aa020581292a793d66bd2 +97ae848a823ea7a99f91834e537fb47208f616c08fe32c8f8fe06bd35c9b638698c513265d0b4de9e572a2f9692b98e2 +81b8fef4ea5d399c65e78f40e47c559ada86d890777c549ce362e7ab81b3bfb00d5ff4ae4ee30fd7bda7ee90d28f85d8 +aada6912cc748923ea40bf01922c06c84bc81b2ab0bb3664a0579b646f03d47ce88de733ac7f2cb9be4a8200584cdb71 +89b48b9c79332f8f58eac9100ada5bb7decdc4b1555c5d383e2c1ce447efb0ebdff9c50bb52bc3042107f33a61ab2520 +a32ecca8b870b2b6e9d10b5c1d8f925b3d629d271febad65abed316262bb283c60cade0e91047fbd0fac53ac6db372b9 +b829cd1f13409e3573a8e109c9541b0a9546e98b6c879a11152b5564477ada4d8cb4b3079040e05a5cb63d75ef11eaab +91f3b100baa19e960b170fe9e03b799faac5b9c6f305c56115940bf81f6e64dcb9cda77e8de70ed73a21c0e8a74acc58 +b25b5e872c84065aee04822bbcb4f3bdff57fbd7cea314c383765cc387786c17de3d5bb3de3ae3314bdede14542bfac6 +a89bea9eca1f5a17a3efccfa4987d8e5366b0dba70ef1fef43aaea83c528428d1498c8b056ac27f16e8946ee93f7028e +818a1f7b0b8b06ea0514d6b4a0296da4f69cb18ac8e48c5579e6ba2880b06215fcbe81672566b8b94fcc3c0cadecb191 +98dd6e6b4b4d63d9aa7464a2be08ae8babac4da7716a3f109340bc9187d59c6ca0c88e6877a67c65096f64a3ced22a4b +a2069c5bac4f6590042aefb37570cc20908b0df9d0130180f565ed8a53b4ea476a274de993561fb4d009f529fe7aa1cd +860b7ec2410f033a7b0c5ca08f88a0ad29f951a5ebd5383408a84367e92f1bd33bee3b87adef2466b7e33b47daabf30e +a408855a8414102c3cb49f47dda104edf0887e414723da59b6b6537ada7433529f6a4d1a4ad4fe311c279213cdd59356 +8ca0d81dcb43b89a4c6742747d29598ede83a185a8301d78c6e7f1c02c938441360a1ab62a5e571e3eb16fe17131cbc0 +af7875a495cb4201cdb26e23b7c76492f47f8dd4c81251de2397d73d4c8d5f419cdbad69ba88ef0dc3552e460dbcd22e +80e901e433dca34f3d386f39b975e97f7fc16c7f692808221fb2ee60c1aaa8db079cc48c7d72fd548aaf8dde8d0b8f05 +b6062319e13926416e57a0ffc65668bfa667e708a4e3f5cb26d8a6a32072f5b790d628052d5946c5068dd17cf4a81df8 +90094b569e8975f8799863798912dbf89b12d2c2d62b3e5fac7efc245436fcd33af23b8c509ae28c6591d3f020966e06 +a504f72d3d06a0c9b188a1035c7c6d80047451c378b6c5b2ffa1f8cecdb64871cb6440afb296974c0a528e5e563061a1 +959061c4924e133a419e76e000e7c62204093576ff733ce0b8ae656ec6045ef94c5a1f3c934fb76fa9188c5eb397a548 +a8b9d0b58de38cb86cb88fb039a7c4c0c79e9f07f03954af29013baa18fc2633883f8f9ca847209c61a8da378f9075d3 +b16d8341da4ff003ed6d1bbdb3be4e35654a77277341fe604b4c4e4a1cb95e61362094fb3d20ab8482ea14661c8b9852 +8ea4ca202e3aed58081a208a74b912d1a17f7b99a9aa836cfaa689a4a6aa9d9fbfe48425cad53b972000f23940db4c5c +96a372f55e9a25652db144ec077f17acc1be6aa8b4891e408f1909100cd62644a1c0296a3ddc38cd63ef46bef4e08462 +87df40018ab3a47c3782e053dbd020f199fda791f3109253334a71be4159f893a197a494de8f94d6f09efa5811a99977 +aff82d2ea6b3ad28d0ca1999a4b390641d727689dc2df6829a53e57d4f6418196f63a18495caf19d31fc23fdff26d5e2 +9091053c4a18a22d13ad309313b6d2133a96df10fe167f96ec367f9b8c789ecca7667f47d486fc5ba8531323b9f035ac +a4842090515a1faccc3d8cadbb234b7024254eba5fdfcef0d15265c7cec9dc8727c496ad4e46565d1f08504c77e511d2 +b1d8a37b1a97883d5804d0d2adaa8dbf0c2d334ef4b5095170b19613fb05e9c648484093d0c70d545cf9b043b449c707 +b1ea40f3dd1c3d437072f8adf02c32024f32488dd59389d1c3dfe78aca3df0bab7767f6ded5943cc10f50555da6092f5 +ad219c6a8149f10391452892b65a3268743baa7402736f810a35d56cdfed83d2172b03f15c205f0dc5446baf855907a5 +afe44c3e1373df9fc53a440807fa6af8ebc53f705e8ee44a162891684970b04fb55d60bc2595626b020532cb455ee868 +859ae154b017eae9be9da5c02d151de747cc23094d8f96d5db7d397e529b12fb55666f55e846e2bbe5e6f5b59c9d8b05 +8aa01354697de23e890fe54869cd3ec371f1be32064616ca3a556d3019541ba8e00d683f1396ca08e48988f7f7df5de4 +b8f682487460b9d825302c40a7d6dd0353ff43bf24cd8807cdfa46c043e3f5a7db182b27a8350b28e91888802a015af4 +b6d4d6c3ac40f8976b50be271cf64539eb66dc5d5b7cec06804dfe486d1e386037b01271cf81ef96dba5ea98a35a4b43 +9385a2fd1cd3549b0056af53f9e4a6c2dfcd229801ffda266610118ade9a568b33e75b6964e52fcc49c8e3b900e1e380 +98f4aa0e4ef039786cbd569536204e02b0b1338568d1d22bb5bc47b5e0633fb7ffe1da93eb9d825b40b9b7f291f84d51 +b7b3460cf706dc270a773c66d50b949dabad07075021d373c41fbb56228355324d120703e523ea3f345ef7249bfff99d +81b826255f95201987513d7987cdc0ca0529524d0e043b315a47583136dbada23a114d50d885bb3f855fa8313eff801a +afdc6c35161645a14b54f7b7a799910e2e07c8a5efe1827031a2eecd5d9263b3baa367fdd867360fabc41e85ab687e74 +817b361ce582153f2952f3042e235ee2d229e5a6b51c3d3da7bbe840b5c6ec2f01446125045848d15fd77dc46c8a8fe2 +aeb599265398af6e5613297d97d2b70222534590fcbd534d68b24a0289b6366ac8188b753f6fd1000ee73ef44f8fb7af +a5a9e528b606557be64460c1ad302a43e741357827b92ddc50766a7e6287740fc23bd528d9faf23345ce8bff527d5bc7 +a8d3b3b438d5f75efaae6ce7b67c2212899ece5b5bdc9bac655e271fd1846ea8560e646fdbded3d9363eefe29473d80d +984c7976d557e2f591e779c2885f5033da6f90d63a898d515b5da3adbffa526764cd8eb679b771573fdf7eed82c594ec +8ac748689cc3280e064807e68e27e234609e3cc87cb011f172204e1865ad7fdc78bec1672bd6e6fddcf4e7902b0f38bf +877bb392059540b1c8f45917254b8cc34fb7e423952bdc927e0a1622efec4113fa88988686b48134eb67ddebcb7c3ef4 +ac04b154ccd307ca20428091585e00121b61bae37b22d5d2a1565bc1134be3c81ccf3715fffebe90744164e5091b3d9a +90745c04278c3a47ceea491d9dc70a21a99d52648149b1ab623b5396b7d968fd3c4d1a2d08fc5638e8790463e0cf934e +80bf26ca7301e370f101cc69e7921e187cf5315b484fc80a872dec28bb65886569611a939958f4a3d2d3da4350011298 +87cbf4d6f0c06cc5f24e0f173a5f2f9bf2083a619dcce69a8347c1a6cd1d03325544610f2984eb87a13241e6ab9a22b7 +8909368817a515789ff4d19ed26afafa5729a24b303a368ea945a9287bc9facec9e1c8af19cbec8dab4acbb6a6ddf6c7 +ad8d2f82b08e0990dfd6b09fd54db3a30fd70aad218275550f173fd862347e1258a4716ca2bf4c40e4963850b2277eab +a9467ceacf9337cae4f2c7eeb3e03752ac7d77692b07d5e5d75c438fbe7dc2029ff84f7759372a0ddfa953b4ec7e9e38 +a5feb7669e84b977cb1a50ff3a39c28f7ad1ecc33a893fdf1ddae7a0d8a4c5f6fbaff25cc56631b708af038a961f3b55 +8f2e1fa07963ba18db890b44c3b9ae7f8992b702a5148679df69e4d9d4b1c082b2bd2ae53f96a4fe24b54f3dc1588f17 +896778f35cbecb43f001277c306e38a9c637275101f1a09546f87378b10ccc025644bc650b3b6c36e4fd0c09fbb3df35 +91dc702778176a4d089dc65502d703752dd9a766f125ffef26bdc38fe4abcae07cdea14102c3448d10f8dd6c852ee720 +a5df3004cec6b68b937cadded0dd2f48bd3203a903a3e1c22498c1193f4567659ecaaf3deb7ed7cf43796da9188f5dc6 +b18b4c8ffcb8599c24d9851abf8ee43047cbd4c9074c9cfbf88376a170da4554978988f550afde8a45306ca32713c204 +8370bc38c84da04d236e3c5a6c063e1db6613dcc4b47239d23efdcb0cf86846955b60da3e50f17b17cd3f7e0c29302d9 +ab7d6bb6be10aa52ef43abbe90945e78e488561afb959dc2fe768f8fd660d267c7203a2b7bdfa1b44cd07898f4849e06 +965c96047d82d76ec2cfe5035fd58d483cd2cb7f65c728ab3049562c5d1943096d6a5014c05babc697d79c07907cf284 +9614f7006aef6f0478ebd37fbf17276fe48db877394590e348c724059f07c3d1da80d357120d3063cd2b2bc56c58d9d6 +819c7b2a1a4bb4915b434b40a4e86dd7863ea85177b47a759bc8ecd8017f78d643982e8a091ee9a9e582f2b0208725a5 +8e159a185b5790a3ed444b6daab45f430f72f4ac4026750cbd5c7cd7947b5e00f2b10eaaf5aadf8d23054c5b29245546 +b48cb6f6c0aaea04833e10d735b67607846158b6663da380ef01c5bca3c9d537611716867dc2259883e5bc9daed57473 +8b48ce8b5ab76b7d662c29d0f874f5eec178baf3f14221bffd5d20e952f54f3ed053182a486da1d1f400e0acef58f673 +b6fd3cba177bfbcb5e7ebb1e3c1967cad5848c09c615ba2a6c277908f8b1f4f1ac5f184c33f2a401e8bdafcaed48bb88 +abd8f44c4a447de8fde1c119f4fd43c75b4cc99de9c817a019d219d4b2ad2a73b60606c27e36e9856a86bf03e7fc861f +af9f7e8b3e9e8599c7e355433c503a05171900a5754200520fd2afed072305be0e4aebb9764525d2c37a5a7eede72025 +a0960a58bd2681804edd7684793e3cbb0e20d1d4bd8721b192baf9aee97266be14c4ee8b3a3715845dca157ba2fb2c1d +949a37213209adfbfa4e67c7bad591c128352efd9b881c1202cf526bf4f657140ef213acf0efeb827a0c51a1f18809c4 +9192fae84a2a256f69a5e4a968d673bebf14ea9a2c3953f69fe0416f7b0fafa5166f3e4588d281f00d6deac1b6ec08bc +b1a249662f34a88d2798eae20c096268d19f1769d94879b8f1aa40a37b3764349b8e6ab970558436a88a5aa5c37e150d +aea87086dcd6de0b92886b3da0813ff271a7107ab1a3cb7021b85172c1e816a84dbb1a8fdb47e8a8eb5e6fcddd5b919a +a586b5078b3f113eec9f074430bcf9aabe4e82752e5b421c6e31d1c2a911512e34154bf8143b5197e820c5af42aa8ac7 +a6eda122e400a6600f025daa383685a10f72f62317a621698bd0106b331077b05ac1afc68ece7a2e285c54a366921a3c +8875e9ba654ad7b1d57ede84e2b702600416d40f7475fe2df25dd1b95c0178a227ee187547898e5b9d1ce8ce9ebd15c9 +af2cb289f8c75f4ddae9e3ef9c1977fe4d4d513e411777b03b996f5baa372eb995b5ca96255fad9ace776168806ecc42 +8d24c465d26bd93290f45ef035bb6dde4530d9d7d051baf583b1f8b98e9886de262c88b5709084710cffa7c767b4c27d +8cf35b1b28a7726645971805170392d522f5e7e6cb94157fe9c122a987051c1c90abe3c5bdb957ef97b1c45dd9bba05c +93e2bbd82a3cb872cea663f9248b21d4541d981f3f8d5af80a43920db5194857f69e2884753f6ed03b6d748dbfb33620 +8b774b97657db654ebdafce3654d645f849203452e876e49dad7af562491cb6531bd056f51cb5b2e8f0a99e69bd8566b +b5333c49d3e1c4c52f70f3a52f0ad77165bed6ad9dcbfaf1364e7a8a0f24570e85a218e4c2193f63d58a7dd975ceb7a5 +b4a34c443e4fdaab8e69fcda1fce5e72eaa50cf968f5d3d19084d049c5e005d63ab6e1d63dee038317da36f50ffb6b74 +824a224009c6848b92d6e1c96e77cb913fee098aaac810e2c39a0e64d5adb058e626d6a99be58593d921198edd48b19c +a86f1fdd2e1ba11ebda82411b75536fc0c7d2cdb99424e0896d7db6cae0743ee9349ffa5bff8a8995e011337fa735a9d +b406b5b89b8bed7221628b0b24eb23b91f548e9079a3abd18be2ed49baf38536a2c1ec61ab1ddc17928f14b006623e7b +8a7ea88d1f7420e2aaf06ee90efa4af798e2ec7cd297aacd44141471ed500107fdd93bd43b6de540314ef576646a7535 +a7a8c071e68bbae9aca110394cf56daad89404dff3e91ea3440670cd3d0423b67905e32b1ba7218fd4f24d2f8bd86ce7 +b959830f152e4d31c357be1ded5782aed5d6970e823cf8809434cf4fddd364963bc7cfda15c8f6b53eda16ab20ca3451 +b59232c8396c418238807ce07e0d248ad2045289e032678b811cc52730f99b480eb76f6adf985e6d5e38331d4bb2b9d5 +a14092fddecc1df18847ab659f6cf7c8603769a4e96fbe386d8303b225cebbbe8f61d6ab3dca08e3ed027e7e39f2641f +941cb0632acd395439f615c6b4b7da9ed5abf39700a8f6e6f3d3b87a58a1a7dbb2478a6c9ff1990637ada7f7d883f103 +951b8805ecb46c68101078847737e579206f2029e24b071bae6013e9dde8efa22bce28aa72c71708caf4e37f9789a803 +b2cbf22e53f6535fa950dd8de4aa6a85e72784dd1b800c7f31ec5030709d93595768748785ff2dd196fbedf3b53cd9d7 +8d84ea3a7eafb014b6bd6d57b02cab5ac3533aa7be4b86d2c5d53ce2d281304409071100d508ed276f09df81db9080ea +a2204b60836cba8bf29acd33709e6424226ae4d789ef6b280df8a62e30d940bc9f958ff44b5590d12fa99fcde2a4a7a9 +86692c58214f326c70eb2aaf2d8b26eae66fb624f143a3c144fd00f0249e30e0c832733a7822fac05c8fe74293768ace +b1cb3d64eb5b9ca0e01211128f990506fba602cd1417da02237205aa42879ae2a6457386da5f06434bcb757f745f701d +b3eb4290a53d5ff9b4596e4854516f05283f2c9f616ec928a0934b81c61afc351835f7eca66704a18a8b6695571adb30 +b0bfb1d44b039d067d7e0e2621e7c4444a648bce4231a6245179a58cd99758ec8c9e3f261d0adb22f9f1551fceb13e4a +a29320f71a9e23115672ea2b611764fe60df0374e0d3ff83237d78032e69c591a4bdec514e8b34f4b3aeb98181153081 +8a6abe9c8a048002b2ff34154a02c2f13fc6dbae928da47c77f3e5b553ea93d8f763821a6ead3c6069677870fdff7ff3 +b73ab66a62f427e1a5e315239a2e823e2a43550d245cff243c2799eb2e4701fabb7d5f9ce74a601b5ee65f6555dacf64 +b64858e98b9c10de8c9264b841b87e7396ba1da52f0f25029339ca1d13f7f9d97f4de008cfe12a1e27b0a6b0f2c9e1ab +807d2440d1f79a03f7163f5669021f3518094881f190cb02922eb4e9b17312da5e729316fe7ba9bfffc21ed247b033cb +a7f06458d47ebe932c2af053823433a8a06061c48f44314fad8c34846261c8c3f7f63d585a7930937327ad7d7ca31a6f +82ac2215eba9352b37eb8980f03374f5e0a2f439c0508daa7a32cdce398dde2a600e65a36795a4f5cc95bbcf49b01936 +a1882c83a2f946d54d74a008eac4aed70664db969e6799b142e0d0465e5662ba0d224a1cc33be339438d69bdad446ff6 +8009776f7a34a3c8779e21511fa409b0c5a38e172d1331acc29a16114e002f5f2f001381adb5fb3427a100752d775114 +b24441019af4a0df2dc68e3a736f358da0fd930c288398a18bb5a8d9a1e98ea376395f19d8e03a5f020b83fcb709f1af +ac72b4de3920c4f3c9b8ea90035cd7ed74d34b79e79aab392f057c3e992ebe79050cc1c6ccf87120e4162b29419147de +973e75577cd2a131a0bd568fd44e43554ac5a9ea3bf10f02d1ad3ac6ce9dc7a8a7ea93aacf3325f7d252d094a0de1376 +98a114de2a86f62c86862de37c328bf6a7fccff4d45a124addbe0eb64debe365409fcb72ce763f2a75030e1ff4060c64 +aff753e1dd4707f1a359eaec06ebef1903242889a2cb705d59dd78a79eb5b894731f5a91547479506145ca5768877dec +b856e4234858b5aa515de843e8bd4141c15a4cc02c51640e98a8aaa1e40344f1ff8ef7c3b913ea2ae7411713daa558d2 +863525eb2f8147a6d1d0d4304881795bfed348913cd7f38d815d929a426788b69e41f022dba5fdcaf56c85720e37fefe +a14ad76b145a6de2e0f8d4f615288c1512701a7b3010eb8a95941a2171bc23561e9c643764a08c4599040a3b4f5e936a +a18bfc66f6139dcb0485a193104fec2e7d52043837a4c0cadb95743e229712a05cf9ce4ccb482f36ff1ce021e04b574a +991c8e6678077d6e5f5733267c1819d8f7594e3b2c468b86a5c6346495a50701b1b05967e9590c15cef2f72bc10a38f9 +a034e7f9b547b047c99b99a0dd45509b0ac520d09130519174611de5bcdb9998259e1543470b74dcd112d0305c058bad +95ffe0d02317b5c6d5bfddbcec7f3fdfb257b26ad1783bb5634d983012e2ea1c6b9778009e1b6d10564198562f849ac0 +b3db442aa4adb33577583b2a4ad743f41efe0e1f87bfc66091d1d975333ffc00b4afc43057bcb88a7d68b0c9695d38dd +ad2e97d10d7c53d231619e3f2e8155a27ea4f2fb3c0cecf5c7f14f4cfcdd21f62ea46d843b21df748b2892131633fed2 +905d7aad6d3b56bad48694b6b20b27e370ebca8b91d0821e48e2f9cad39910c26cc11c77c266894db3d470485a63ed11 +99bfadefca796ce6af04ede65ba5ef5bf683ff7e2852bb9c406fda77b95ef382289853dfe4d933525071e4cab8ce3936 +94d9905ed4ef92107d0adb9ea38f085a2a24b8f792108bec702d747c215b1f14aafd486ea0c07ed42602b12d8f602b93 +a78dce23ca09dda2d5e7fe923290062546825286d624de35ac5756b6c8ae030e211f4f9c9c8d18a924f5880e3b383d1f +abce9e2128ff51fa17e73d93e63d7134859b2f328eedbcefb337c39e752d6750d9cffe6abfcd359c135dc5a12018827b +a9ea7d91e8a3524acb3182bedd7e1614d37b48f8eb2d8f677eb682d38408b8d512786d8bb65811f4d96788b9378e59b3 +912c9f804fb57dd1928f8274be58b42618f589fc72a7e5b6cb4d4b5d78c547f80737cdd77ebe5d2b71eaf60b8fd2b663 +b7227ec9a62d5538974547f717fdd554ab522d8782667fc3e9962e9c79a21134ef168371bf3b67e28d0964e92cf44028 +89440a781c812a19c758172bf722139598023ed0425374fbb0d91f33be7b7f62a36d7aa34696c4fb0da533bd5dd41532 +b31e4a9792d6e9c625c95aa3c0cd3519410dec07940afab820ef9f63017415d237a47f957d0b591b6de399ffc2a8a893 +a66ec47393df2693be161daaa88be0cf07b430c709ca97246d10a6080ae79db55c9e206b69a61f52512b868ba543e96b +90ca425dee74cc6a7e8eb1755cf9b7b76ba2a36ab851333b0fb7b35e8e6e189702456f2781ad87b4215993d62230ff4f +88b64741f93a2ae5d7b90b22a5e83c9d56bcee5c6bfcedb86f212acc776cc3ebd0b62cc025f596cd8db4f4b6a7aeebab +a1b6c7d2358bb201b42264f8fbebaa242ef105450bab21b4a2f16f368048c16ad1f3695841787eb33a0192f1f6b595eb +8a932f1cd227ceb18389791ed9ea1ff26571715ed1ab56601a994795713a8f7f031d1e8472ec3eb665b7bfbbca8ca623 +8bb2e34a2bf77f9f657dfc51ff296a6279a4d7d15860924f72b184fb7d5680320c7769954b9dac73c4bfe9c698e65e58 +af54e7367891c09f2cea44cc7d908d37d058162ec40059d32ded3983a4cabfe5057953878cf23bfad5292dbd0e03c0e1 +8a202532b9205385cf79f0299ddcb3156fd9fab09f9197bce762b5623f75c72ab1d74334ee6f0d289007befe222bf588 +83bd0f5896eaad58cfa7c88fc5ed505cd223f815dcfe93881b7b696cdd08b8b5ede03ea5b98e195c1a99c74ac5394c1b +b4a84d9940e58e3b4f804e4dd506f8c242579cfa19323c6e59047e5a1e35150699a2fab2f4862dba2f0ee4ed1d8970f8 +8c9ec477d057abebc2e2f6df5c4356a4f565bde09f499a131967d803d4bf36940ca2ed9d4a72adbe0a4a8b83fc686176 +8598f43c32623fd5b563d1ec8048ffc36db3d7f9b3a784299811687976f64b60585b2a2707050a3c36523b75d1e26716 +b55eb07014fe5ad3e5c9359259733945799e7429435d9bf5c72b2e0418776e329379433e17206f9f0a892d702a342917 +a5ed942eda7b36a3b0f516fafd43d9133986e4c623b14c0f6405db04e29c2d0f22f1c588150f670dbb501edda6e6dd4b +92b6abb28cefab2e332c41c98bfa53d065b7d262638389603a43f4431e6caf837b986254c71f7cdacf4d6cc4064b0195 +b01806178a28cc00d1561db03721eef6f6539676d93dd1fa76a13b42a31d38797e99b1848de92fd11821a342b04f3f72 +a2f10303437acfbb5912e186bbff1c15b27ed194c02cbc1c5b482b0b732c41fa809136e8e314e26b5bfe57690fe3b250 +9990207fcc711102e7e941b3ac105547a3e7301390e84f03086c99c6d3e14efff3a2e2b06e26227f496d88d5cdaa3af1 +b903cdb0c2fd578612398c30fe76d435cd1c2bab755478761244abb1e18ba8506fd9c95b326422affbcaf237309959d7 +99e0c12cae23f244f551d649302aac29bfdeb2c7b95578c591f512ad7ac562bd47e7c7317ac9bac52c9ea246617bdb48 +b996d267ab5149c1c06168ee41e403be83f99c385be118928d6e2c042a782de0659d4d837f0c58b26df0ce22049a5836 +989001b8414743765282f7e9517e4b8983a929341b8971d7dd8a87d246f6c8ba5e550c983566ddd932c22948f4fa5402 +a0b006a2c9124375364b8fc5ddb543a7468fa6d321ea046d0fd2bfdaef79e5e3600b3d56190733491ca499add1298c7f +80881d6f3ee507089b7dfb847fc53dd443d4384ef6fce878d07d9b4a1171eefea98242580e8a6a69664699f31e675cfb +adc48ef53d88b9d70409ed89cc3be592c4bd5eb65d9b1b28f2167dc4b12406889c00f2465c554f3aff673debc2997ccf +a62f5d9f167b9f4a4aab40d9cd8c8a48c519f64a1985823e20e233191b037c02e511b0280487112a9f8b1f1503b02db7 +b89aa2d4fb345a1d21133b0bd87f2326eb3285bd4da78b62174bf43d30a36340e4217dbe233afb925ab59e74c90fccf0 +932ba22acdd2f9d9494da90958bf39d8793af22417647d2082d2c3e6a5e17a2d14b0c096139fa8fa3f03967ca2f84963 +b67b107e71d96de1488b4154da83919d990502601c719e89feabe779049ddf7e4fb7e146eb05e754b70bbead4449efb1 +84509de1b8dc35aa2966d8a48501f725d59b4c65f3abf314b2009b9a573365ae3163c1f276708c66af17de180aae0868 +849153fe837a33fcb32c5fa6722c2db9753e984867c112a364eb880d87467782142d1c53a74b41df1dec7e900c877e1f +903d05c73ae043b69b18e980a058ce2254d008647a8d951175b9c47984164b34fc857108dcc29ad9df0806d7e90405f4 +a6b05917ac32c0b0eeea18f1ef3af5343778c543592078fdf6a1b47165013e2676bfe6a592a24efab9d49c4bd92b8fc0 +8648482f6947a5a8d892a39f098160aae1a648cb93e7724ea9e91b0d1a4f4150b91481f6e67d3bf29ff9d65ba4fa61a8 +a6ecaabc38895013297ae020686f04ea739c4512d2e3d6f2d9caf3f54000fb031f202e804ee615eb3357714a18657bcf +912f5935acc2dd20d5ef42b2ad5b307c925324a84a3c78ff66bc5885751934bd92f244e9636b60a744d750a2a7621198 +a0d6f261a776c5b114298f5de08d6e3372649b562051ea2470d3edfc376048793e18fc57ec84809b463dc72496d94329 +940744cd3118d1598c248b38503f6f1fbdbe7a147e683e5b3635140aa91679f8d6c1472600f8e9c36117a60203be6b4e +ab81737c839fe340f6f1fb7275811cb0c0d5fe8bbc265f6a56c6c68d0291bc7234eaa581ff26f8929d9a5bed4aac7002 +8df47341160f1c728c3e31be17a32e42b54faaa1286ef2c7946882ca4dd46443b8428f3654616c6e4053f1cda2e11994 +a721067e75c3c791f4d9f58d4810ac9621606e29c6badb593d6bb78c39968b45be1777ddb9bf03696d4d4be95b2dc1bf +a4e399213d3c4350c2d0cbe30757ba7e1f9680f58e214ff65433b36232323744c866a87d717851ba1dbd6769599f69a6 +b0be851d1e43dee27abe68f85e2330d94521b5f1c1a356ad83fcd09162c0ca9c2e88bccbcc5bacfa59661764361867a3 +86111bdd3dbfca232aa5802a6db41d639502e43a2e24cb06bb5d05c7f9b5ccac334d16b61d1c5eaac4fa0cab91113b46 +a4f805b11c174c34250748b9beebfb7c8c243198fb13463911906ee4effe7d331258a077e374b639a0c5cdcdff166b7f +87e4cf2c6f46d2dbac726a121127502921decf0195d7165e7bbeec6f976adb2d1c375eaa57f419895a2c70193215dc4c +8ff06de2c1c4d0744483bb4f7c5c80bf9c97b4df23e86c0bb17f1498ea70e0ee3af20827da5e8cb9d7f279dc50d7bd85 +ab112c0116471b4dc3fd1e6d918f99158eb7a08153e891ddbba2fe5bf0eeb188209e3019176e758231c3df937438136c +a67f89194e99e028a5da57747268e5ef66fefb881144043429920d222d37aaf268ebf73ca1da659fcdac3b4e7a65092a +b4da1dcc791566140d6abeaa2923cb6b21a6e6aaa30bb4cc70011e931eefa71f96b7e05358c0654bad7ce45191ab9fa8 +8283933231bca359db588c80e043ad6ea765fb0cba5ef233c5d514ba01ddd1b409efbadb368f26763402e4576dc4655f +97f568ce3edacd06f3e31a15462f5f9818a8c3fdbcf92b1ac5840b0b6e73166a154013dd52e85a18e8ead3fc9e54aca0 +a9cd1601c41e5ab2018f986443914fb703ddb6b06a36c06fb58065f2fee8e1751071ef924ea3ad76f0c19baccb1b5f8b +92aad71bb7e929cc35a48020d16a5822f4f106a7f59985005a5ae5ba8e8016ec33727610393498f56b4f353b3d5161b8 +89427780aa4e7ac894c681fbe2889153b94db883f17f109bc9caa93f0c259dda42aab502bbefaf572c56f70abbc42db8 +aa8cf76ff847dfe59534432ed8520bb48bf412c28497747dce04d2b2a54ba843c3be1564630cb49ec0217167847ba590 +a1570a6748a2303e74a31c2131d05ab372ec006ee92ef74c42f2e9a250663bebdfb3777e7ad91f50c954889a59c2d434 +a4c2b1bbc48199c31ea8d8196729eab00ce0200350d4aa9f23347a3289355e5828cb2f93036a14d2d9ec575fb3835239 +84819d0bedbaab5bf8afdf23f59a7ec5f50da3063cfdd1ef5fc4ca4c1fe68980b5c80e30a49f38e5816765e81dfc5a57 +a57cfb5e877b88202f589be777605deafbfc85ed1357af03a18709cfb4b668a271199899243cd3750f1cb77ebc40bba7 +8d95934bbb0efaf3339f27cb96de46e4486aa58a2c40dbc77c1c3ac7c27a228062824b9045c046631b2e286e8549603a +b99a8356abeee69f40cb3bd8c87e8039a1e076897dde430bfbf989dc495c48609a7122bc6c1d1c32ccac687b47d5558a +aac2edcf2fe5d3f1a84e8f1f27ece920eabe7793bf0ed5290cda380752e55d57a55a362c5253bebb71e4a55f2c437ff6 +af7c76876072c3b0091e22b9c5b27ce99bf1f0079ea1a7816ad9c06e9e5fc407595c7f4f9953e67d86fb2da656443dc3 +9175b64d104f78d3310c9c02f82e04c8e9878d2044ea5ee9c799846a3d23afa5fa2aa4af7350956136c69a0eed03cb2e +b3328e953317494a3d976e7f7c3d264258a5d4b2c88e12d06786a9e7b2affd41086762ef6124c6a6e5b6b028db933c14 +a49d166065e19d39299ee870229e4a04be81acd6af3a2201f3a291a025dd5f8bc3e676ee123cd4b9d8455f6a330b395b +85fa15bc8947ba03681d87b50bd2f8238b1c07849a7ed4e065053fad46aac9dd428186a6dd69dc61b5eba6ffec470831 +b6fcb2f694a47d3879b374b8b2967dcd59bd82a5d67ae6289a7326c18791b1b374e12571e8c8ea16a4bfc5525ced3ec4 +b6115f52566aa90ccac2aab6d2dbf46eca296d047db1eb29a1b8a2bc2eef7a24e90407f8dae528806aceb2a1e684d49e +9707e66220233f6a48a93e8dec7b253d19075eaa79238e519b82ce1ac5562cca184f8a1c14f708a96c34ad234673d646 +a0822903fb3825eae07ee9d3482277c0b8fc811856dfe4a51cf24b373f603924166fc5485185f99c4547cd6476b62270 +88dac6366c439daaeee2532b2ddbe206132cf6e12befbb8e99870ac684e04e62de150cba0e22e395a0b858948f40808b +a72dfba9caad3179f43fead0f75e33ba5342470d8c9cb7c86d30d2c7ce7244a8aafd1d558b0ec8e2a9436de2c2e95ccc +8d696046defcc32cc19954c559213100f0ba273ea12abb55ca7c42818071d853846bd4213af2c41ecd4442f6b4b511b1 +89d6f2d52cf65414da15a2fb1911c53afbfb50bb5f2638844abfc325ff2651cd9130be4beff05dc4046adfc44394a182 +afb91abd7c2a9cfe62855ede3c6960ad037fe8778364a2746ff7c214c55f84e19a474a9a0062b52a380d3170456ee9c6 +87f724a16ec8fdae8c05788fa3f823ecc3613df46581a63fc79b58f7c0dc2519b6b23e3dd441a0ca6946dfe4bc6cd0ce +86760f90f6bedfba404b234e90fbf981d26c29b87f2fa272c09540afa0f22e6682d08c21627b8a153c0feb27150458e2 +ad4d0342f255a232252450ce4209507ba619abfd1ffcb9c5707cfa45f89be41d88f1837acea993a1c47211b110250b4d +ace54b5889bccdf1d46c4ca21ed97cca57f7d12648381411d1b64afdfc64532a12d49655776ea24cf5eabe34145705ad +936dac693d0c1b1e5de1701f0bc46aef6e439e84bc368a23c0abe942eb539a2950e8929265786fcdb18d40a44bda14b9 +94fafbc544decec1d489b9ad6b23410b9de4779f9f44aabd093d7fab08340a4646a8cba31633e49c04d2690b8369a1d7 +98157e757f1a677c5d9d65c47759727a4dbc49fec2da4d9889c4ea90573fb42e2a8d72eaef92b782ac6f320970f09363 +8eaa0498c191c810c7e1ca7398f7c80dd0a7e7d7829ed07039490f60e7c2ae108843c06fe38fa36d45d63da46cba887c +a0ae116e5b0d2dccf83f056ad876037225687904e0290fe513fdc6b2dbe4cbf5fac1d828352e64734895895840b3c57c +b592b318dbbd7ec4872aae5e64bdf2305db2e5e8cfe0ad77b691f542ba5e066dd20b09b0b08ff0d798bd79ad946ddf7f +879e50c8c3e7f414ad2b38632bc482b71759cd561aeb2215550186ebb4559e4cf744cdf980512d8321954b3458d21e11 +aed5c6c7ce0407d7b2c04785fcb9deadb9b9413e37cef5b1d918f474cccc7de012fe1fa6f5fa93cb7ef9ac974d9fbc20 +892274a9f0afc68fa74be276c2a16de5cec674193f96b27a80bbb9f3add163f85716b531f3c920b98577a0225f84e8ca +938fb7a53266b997a7669596577af82f5289b160b7fcf06d76eee2a094696f6f12b28c2c65b833a52529a116c42e6c7e +892083929b6067f5045b1208f3dc8f0ee25bd0533a8831f5c23bb4ff46a82d48f0a34523359df5061d84a86b718d5060 +99159ae9574df6c16273eda66b6d8b79a327940e335b28c75d647f4744a009f4b5f0f385e2017bd3e7fbf59e629cd215 +a03e5757ef7738eba32d396923ff7ef82db2c15bb6adc8770fcb37260b7bda3be62473bc352a9a2ef7ec8ebe0d7688bc +ae3c24a85c9b1fa55158b2acd56d2016f70dca45a23f3ef7e0c6b096f4a7c54c14020d61bec7c7f87be4a595bf254209 +a920a6f9cc803fe31352fca39c13f8ac1e8d494fcf11b206092227c2af38469b1fbc068b8fe014800b70f137107aafc4 +b893853be57519ffa6410da605e7d3a746ebadec4788c7907f6e0dde9f20f5a6a01181148b874b3decf9b4814846a11a +b46f43918c5195729f6532439f815d1eb519e91005bc641a4a30ae88700982bf4ed07a342e77945780317c297c903755 +8e431bf4497d0ef6538c93c4bdda520179301a0104eebcfd104efa1edea876818d7d31079656f01a5ff76c4f5fcd71df +92e3dbcb580dfb9cc998f878052b0c3be1c5119e5249ae9bad3538ebb0f0c4ab5a959b04033b96d61836ef07784e6b64 +b712d9d63aa888156f4ec83e939c6bad53de18045f115f54fbf4261fb02f10a8a46a8d716ab43d4acbad3b02283c32fc +b2334e776988b4f772446a47c87416b4f19f9b44164a5f828424d3f35ef10baa56afe810d49b0b86b786b9c0227681a6 +a3f25ad18e435ef585fa90e6cef65a8ba327e5e33701979e27e64ef7d8e09e2591e52bff9c5749d35643456d18625685 +adcfa48ae43cac6fa9866b4cce10a243969965942c891d5e6c0e5b03bd4763f9b63779fbf40d26ac674534fe7cc478d7 +a0eb3448e045038740e2ee666e88aa0f8b8e24b1b55d7d4964f01bfc0c581f7e9d4c0e79f8cfbfecfa8b024b216c8ea6 +8110aa1d82f11965af4f4eedb4de09ee9c353481b2d7ee7a2bc2f302d2a5ae6c31ebc6451309ba7c305da41070b0f666 +b074fdad419d42783ebda17f19863aa499eec71fda5aab6cdcc389276b7bf08053795d15890175ca3dc89f6d8d17758c +a14665846d95d7d5f0b5381502080c822776ec0994ccb1ae1ffbb3f19205ce9c7c9bf9c2d2ca098807ce99f29e4f07a0 +b4884842670a333cb5548a842fa2971881e26b442dfab0b91d6bf3b4cbdf99adbbc9d14fe2bb46872cfcabedae85db30 +94549b01cb47ba16c0cf6f7522c833545397de0b3388c25d03e60132eddada6401682f9ffd8c50d1a61b4d2dde37461f +a790c9b4cec96e4c54777f3e03cea5769b20382cdcaf1de494bac2b9425eaf453eff643c62ab284cc1af33bbd36013be +b1b45fd298ed11609aa1ae6c5ac655e365bb451de1b9fc92aad40422ba85c6a454f33b8142acabe55171328c13d92edf +a74cea9e7096e38327064f058a3cdaa34e6eafaa9c7d58f753c40be67998152380fbd612b9dc0751bda7befcdffcc749 +b18978dfc5efb07b7ef992c7b0cf5d1b4ca551578b1dd13057b7aced8b1deb9f2036e1e3116248a803e922659d206545 +8153c07603cdff6622835a9853b795274390abf7197d7a192193bec44acb43e8cd50b56c11a03f4a2a27124c36974f3d +86b987f30bb9a37cc91d22dffffcd346ec5773e846a6c2b8f9e03b25ffcae859c470c901c4e29695d325dfe4eee927bd +af5e980b9507d10d5269c1a5d02bc16f4f009b663e413ea6a7c655250f3a21c608c12f4002269a05d3779907e7be7d69 +a6f737fab2af9f27bfb8ca87f5fdab6ad51e73ccf074e90576db57b309dfa0a95f9624526dfa4feaef39c388802f2ae9 +b7ed51f699f615f58a7ff4f99d52c4ce7a8d662843c1f4d91f1620fa119b80a0f6848f9fb6c4b9822dc019830e7dfd11 +b71f27f291aa6ef0723ed79c13a1c7a1c40198ffb780a129d9d20e250406bc91f459705b2b6674c9bb412a7b5dd9ff07 +9698cf8f638c3d2916fefa5f28c6050784479f84c2ee76a8aeda7e562630a6ae135b445ec4e29af8588ca5ad94a67f49 +9270aa5030966a9990d8bc71b00b9a7a1d7c1ad8f4c7f78a31b3d7f86467332f21407c74a89ba4f574d723acaf0d2042 +b1b82faceed8e2297cd49cc355471d15ff8dc2ccc78f6944c8f7a75d3ad1629a2e2f1d0a2ff7fa2b3c38cd19839aa5e9 +8a8c4ed49dc9bd961773edf8d41d04385b11bbd3577024639a39319cc7068380236bf73fce0b83e6535bd3f95cef0e65 +8d04ec1e7d148b7e66910ab45a0e6bf409612a3b560bfa784e26f2963152821c646a655cf17a0ce3d4ba4c4ebeeb4a1e +8e9d707f6186d93accb60813715ed1f6b3001ff6d2f87daf8b906bd0b988c1833b2ccd80dee9bdefb45901e81bb82971 +9762317ca6a5e6fe0b2991e0fa54b5fbf419dd0550d70074957d65cd7ebf79ceba607dd40d709ed635c822b3b4da2cac +82b53cd9a1eca2f5d3256723dc4b6531ca422bd87bab36243c727d1952db58d7288ab11467305d875d172ce165b1e4a5 +b4dbeafa05c87029ae257bee1ed7603645fab41f6ba7ac8b57ced5b4774a72ba3e671c2433a93acc3c498795b5cccc42 +a916d3ab7f0e7cef294e11c97c910a19c338ad8e615406e6d1c8995b4a19c3b2527100cc6b97a950ec5a4f3f6db7d01a +b9a785c7123609bdc96f8dd74500c6c77831d9d246f73244de964910b4045ce3242c881271bb1a4bc207d67de7b62e97 +b5f94084f695d0821c472e59c0b761e625b537c8ae3a09f11d9a57259e148cfadba1e43bf22c681b6b32390121cec208 +8f91b36d8570f19a90cf3ed6d5bb25f49a3315ddb566280c091fe2795c4e25ed2c6a1ef8d2669b83f2d7bb78fc8c40f5 +80f27359a73ed8fdd52762f0c7b9f676be2398b1f33c67877261480bf375f975f626c2ca3e7a9f59634db176ed672c98 +b96b91e3d5148ca793edefe4ca776b949c9305acb6f3a3cf87767a684014d2c8f2937c2c672eef8510f17d2da5d51385 +99c4e1ca2cabd4388ea2437dbdf809013d19be9bd09ff6088c8c0cfdb9ecf8fd514391a07b4288dd362434638b8834d9 +b6fdfb812e145f74853892c14f77c29b0c877d8b00055fd084b81360425b3660cd42236ecc853eadb25253e1cd8445c4 +a714af044ef500104576898b9409a9a326ef4286a45c3dae440bd9003fdf689c5f498f24a6f6d18502ce705c60a1cf14 +a9444e201be4a4d8c72119b3d3b13098afee6e5d13c5448fa2e9845cc9188239778f29b208749c960571dfa02b484f05 +91c826a6b8425f93ff395d9fdfa60dbfa655534c36c40a295906578540b9a0e6b94fd8d025b8b8611433022fbbc4fb0b +a355d76bc3cc48ba07026197130f25a593ec730d2ef0d5d2642bfcad745ecbe5c391324bc2485944060ff3100c952557 +b5f9b5a289a6f9a7252cc1f381c892bdb6836a5998f323ee21ae387936148ad1ad7cc6eca37ecece36404b958ae01e8e +a3c7ae04a6208851f6cc40ff270047283b95218905396c5dedc490e405061cbefd1251ecf77837d08c5ec1c77d2776ce +aa02ee387dd2cc7a23cf5cd582da0bc84bb33a7158d76545cbd6e06b26a6f30565dc712d7a8594c29f0529a892138802 +8aff025c841f167fadaf77a68284c355ace41d6df3a9f1e41a6e91454b336f0b69ea34cce495839b642a7c43997a8fd9 +82eccf0b6b4b6460f676d677266451d50f775446df313fc89bdf4c96e082340f6811939d215a54ba0fe30c69b3e43e25 +af324d871b038ff45a04366817c31d2c1e810359776fb57ac44907c6157004e3705476574e676b405d48a48bfb596f59 +9411dcca93ef5620ce375f379fea5c1017a2dd299e288e77b1ab126273631a299d7436f3bf3c860bf795e5faaaefa804 +934fca809e66f582c690c3778ea49de2e7940c0aeb8d7edad68f2edccdfda853d2c4844abd366fbc2215348935e4b2e2 +a1b1fa4c088418f2609d4dea0656b02a8ee664db25f40d53d8f4b1be89a55e5abecbf2c44c0499874abeb3d3a80acf71 +ae6ed7a0ba6280c679b0bf86111afad76fc5d930e9fb199df08134ba807f781d7e0b8b9b2c8c03b02d8cc20dbe949a28 +937d200a72fe4ab8d52f6cb849e322bc5959632b85a93c89744b33e832e8dcf1dddd6ffac0c049b03c105afb8930f7f5 +b4b4a46ebe0c5db16004933c08ad039d365db600a13d68be5346b1c840cce154f56c858874e866de8c3711e755c6e5dd +afcbcb7170c8caa2b77d2b3388dc2f640aeb9eff55798aeceb6eb6494438be05a2ae82f7034b2d439a45ad31d8c64b07 +a2c676273081b8761f58e0b11306ddb6a4cde3d90e7c47b434468700c5b749932819b01efd7637ca820e10fc28dfb427 +b445715162d834c9ee75ac2ff8932ace91c8242d67926b2a650217e4765e0531c2393c9438a52852d63dbbe2cceaafc5 +a0c0ebdc1480fb238a25fbfc77fae0db6e5e74b91809f0ff20a819e56b8c3141549615d1bd7b99829898f6028e8c86be +b3d11933e9d1db8ca617934261ed26c6f5ca06ba16369e7541482bf99c4f86520d43fbb10f4effb2fdf3cc70a189fdb5 +888ac610f8fd87a36b5646e1016eaf6dbca04aa0cc43f53a1046d74a658c4d2794606e79fb07fae57cf9d71ed339f4b6 +979818dab00c58435dc0d0d21185943f95819d2a13531abd2d798e1773c4bbd90047f4eebe117868743db75604a50227 +a6fbcd2656e475065fe44e995e8e2b5309b286b787a7597117e7acc3bb159e591a3e7304ef26f567b5720799d8ae1836 +a03f0ac08d2101ec4d99ca1443eea0efa767a65448a8ecd73a7818a99e863a04392bec8c5b8e5192834e8f98d4683f13 +b3c4ea8c6c3ee8aab2873d446ad702000b0e927e0991c9e30d83c6fe62a604efdc3ac92453313ff0d5e0ac6952922366 +ab25c857f26830631113d50145e961441b5e35d47b9e57f92466654dffebde43e4f78b0867d20929f97c2888c2f06509 +98950aa5a70ef41f274775f021a284d4d801a2efe2dea38460db8a3a8c08c243836d176e69127c2cd17497b0ca393e9e +a9698113febfb6d87fcb84bad82ce52d85a279d3a2933bdd179d53cfe8d6c6c68770e549a1e2947e7528a0e82c95d582 +832b504513266259db78478bd1b5a3b0f3bf2c6d25f1013e64bf0cfae9dc23da8ecd25f7f1047d2efb90e5f1d9b4b3cc +b588bba7bcc0d268ab260d5c1db2122cee7fd01583c7cc27a8ae6b48b29f34c6ea8a6acbb71b9b09c6156ec0a0766142 +a73d2223c7afadc381951a2e9e7bcb7b5c232369f27108c9f3c2ced2dc173e0f49531d0ca527eb142fbb70285307433f +9152cd6b97bd3278465348dde2095892f46342aed0e3d48675848c05b9aee6ef5ad7fe26e0dcd4ab176532289d40eedd +a7812a95a43b020721f688dd726356dda8ebe4de79b4f0fdef78615795e29681bff7c6ff710ff5b2d6ae3fd81bdb8507 +83724c16049e9eaae3269ea8e65caa212f0592e0190b47159bb3346208ccb9af3cfe8f6c3176fa566377da1046044ab8 +877634ec37c7dcd3b83705b103c31013697012795f11e8abf88d54bc84f2c060f665f0c3b14ef8087d3c6a8a7982d64f +b3e53aaacef7a20327bdbba8cd84513534d2e12fd5e1dcf2849f43146e098143b539ebd555623d0ecc46f5ebb4051fca +952d58ecafca9b7ffc25768ee4f05ce138f0289d72978eb5e5d3b23a0daedcb17478890afdce42e30d924d680e13c561 +a10dcc725f9a261de53dd3133858c126f6aa684cf26d92bce63a70e0ff5fff9610ad00d2b87e598b0a7548cfd1ffe713 +b7bc5d0c6b665d5e6f4d0af1c539d8a636550a327e50a0915c898ac494c42b3100e5fae0074c282d1c5073bf4a5456fb +8adc330d3b49ddf3ed210166afc944491aaedb28cb4e67472aeb496f66ce59184c842aa583bfb1a26d67d03b85065134 +b2df992a1310936394a1ebca94a7885b4c0a785638f92a7b567cfb4e68504ac5966a9e2b14891d0aa67d035a99e6583a +96f5da525d140739d19cebb706e2e1e0211edea1f518e040d361d5aca4c80f15be797f58cb4cd3908e4c360c18821243 +b2c0d9173a3d4867c8842e9b58feb1fb47f139f25d1e2332d6b70a85a58811ef99324bf8e52e144e839a4fe2d484e37b +ad95a7631ddb4846d9343d16533493524dfd22e8cbfc280a202343fccee86ab14446f6e7dad9bad9b4185c43fd5f862e +97f38ab82a51a7a792d459a90e7ea71c5a2f02d58e7d542eb3776d82413932737d9431bd6b74ec2a6a8b980d22d55887 +ad4e4c57ec3def5350c37659e8c15bd76d4c13d6de5453493123198dda2c2f40df349f20190e84d740a6b05e0b8f3deb +a691bc10810d11172a6662e46b6bbc48c351df32f325b319553377f525af44a50aaa02790c915b3a49824aa43f17fff0 +a80ccac79bb4014ee366dbf6e380beb61552bd30ef649d4ec39ab307e4139b7775e776fab30831517674ff3d673566f6 +b11e010b855d80e171705ab9e94364c45998e69d9120e4ca4127049b7a620c2eec1377356e7b877874e767f7c44afef4 +96bfab7777769a1e00ce16ada6667a0d21d709e71bd0371c03002427d138d9172640cdd5c529c710fea74bb9d19270c7 +a5bffd2c30e29633b4ecf637c1e792c0378252e2a99b385a093675940b48de2f262c275332ed4765f4a02467f98e3ddd +8d11929d67a6bd8a835b80660a89496250c766e713bddb2cd7052d67b92c39a38ce49005d38b4877856c4bef30fb9af4 +8e704597a0dba1dbd1ff8c9755ddac3f334eeeb513fd1c6b78366603ebc1778231deb8e18f2889421f0091e2c24d3668 +904fbb3f78a49e391a0544cf1faa96ba9402cba818359582258d00aff5319e3c214156cff8c603fbc53a45ede22443e9 +af12ac61eaa9c636481a46fd91903c8a16e7647534fc6fd9baa58ae2998c38ffbd9f03182062311c8adfef0a338aa075 +87f2e544b2993349ab305ab8c3bf050e7764f47d3f3031e26e084e907523d49e1d46c63d0c97b790394f25868e12b932 +a279a7bef6de9d4e183e2bedaf8c553fadfc623a9af8785fe7577cadced02b86e3dab1e97b492d4680c060ea0126abeb +8ece08667ed826f0a239cea72e11359f7e85d891826292b61d4edbdc672f8342e32c66bec3e6498016b8194168ba0e0d +90a15162586e991b302427bc0307790a957b53ab0e83c8b2216f6e6302bc496cb256f0f054ff2cccdfe042763de00976 +9966c0413b086a983f031a39080efde41a9fedcaf8e92897ce92e0c573b37981f5ea266b39dc4f4fb926a1bce5e95ad7 +9515be2f65a57e6960d71bfb1917d33f3f6d8b06f8f31df30fc76622949770fea90ff20be525ae3294c56bc91efb7654 +86e71c9b4059dc4fd1ce7e28883e4f579a51449cab5899e371118cdb6afe2758b1485961ca637c299896dea7c732151b +8695b4ff746d573f8d150f564e69fe51c0726c5d14aa1d72d944f4195e96165eca7eba8cac583fd19d26718b0ce3eb61 +813eecf402151c99c1a55b4c931716e95810fc4e6d117dfc44abbf5ef8dcdf3f971d90d7fa5e5def393681b9584637e0 +a9caf7219eed1db14b7b8f626f20294a3305ed1f6c22f6a26962772c2fa3e50b5234f6d9ba7fa5c3448824c2a15271b3 +b2b2ee20de9b334f2d82cbe0d2e426ca1f35f76218737d0069af9b727a1bfc12d40cf8b88d4afcbeaadf317b7f7ad418 +b853960749521a17ff45f16ac46813d249c4e26e3c08fd33d31ef1ed2b2e157c9cb18bd2454fb5c62690bdd090a48f60 +88772297d2972471b3db71f3ddbf5945a90154768ca49fa6729a5e2299f1795445fb3d4d969d1620e87dca618fbc8a6c +a2bb783fd13aee993e3efd3a963ebc8a8eacfc8450042f018f2040353de88c71ac784b0898bdff27f606c60a3d5ef2c6 +9210903ac619edca0cb8c288ed6dcc93c472f45182cd6614a8e2390801ddea41d48a4ac04a40e2f0adfd48f91aabe2ea +a621d00f83260c22db9fa28757ea81dabcc78b10eeaaf58b06b401db6cc7a7d9a6831a16f171ead4e8506d0c46a752ca +b25c525bf6761a18bbd156ac141df2595940c7b011ed849dbb8ac3a2cd2da6b63ba4755324d70dc14c959deb29fb9ad3 +a35111d0db3e862e1b06249d289e0fc6b110877d254f2ae1604fb21292c227a8b6d87dd17a7b31166038d6860b1bd249 +90bf057309867d95f27637bd10ef15ceb788f07d38aca7ad7920042293d7c4a1a13d4ca1d6db202864d86d20a93e16cf +a88510e110b268d15dcd163ba1e403e44b656771399ac3a049dcb672a1201e88bf60bdd1d303158888a3d30d616cc0bd +b33b7e1f765e9cbd5eeb925e69c39b0a9ea3348ab17f1dbb84b66f4a4b3233e28cbdeb0903d6cfe49ec4fc2f27378ff9 +b777da64fa64d9bc3d2d81b088933fce0e5fcc29c15536159c82af3622a2604c2b968991edea7b6882c9e6f76b544203 +8ea598e402a056fd8031fbf3b9e392347999adc1bd5b68c5797a791a787d006e96918c799467af9ac7f5f57eb30b4f94 +b6901a389bf3b3045e679d015c714d24f8bbe6183349b7f6b42f43409a09f0d5bd4b794012257d735c5fdf6d1812554b +b5866426336d1805447e6efc3f3deb629b945b2781f618df9a2cc48c96020846e9108f9d8507a42ba58d7617cb796c31 +a18ccc6ad1caa8462fa9bec79510689dd2a68d2e8b8e0ddbeb50be4d77728e1d6a18748a11e27edd8d3336c212689a4d +abbd48c48a271b6b7c95518a9352d01a84fb165f7963b87cdc95d5891119a219571a920f0d9ceedc8f9f0de4ab9deb65 +94a4e5f4d7e49229e435530b12a1ff0e9259a44a4f183fb1fe5b7b59970436e19cf932625f83f7b75702fd2456c3b801 +af0a6f2a0d0af7fc72e8cb690f0c4b4b57b82e1034cca3d627e8ef85415adec8eb5df359932c570b1ee077c1d7a5a335 +9728025e03114b9e37ed43e9dcba54a2d67f1c99c34c6139e03d4f9c57c9e28b6b27941d9fca4051d32f9b89bec6537b +941601742d1e1ec8426591733a4f1c13785b0a9b0a6b2275909301a6a3c6c1e2fb1ffa5fdcc08d7fb69f836ae641ced5 +b84b90480defd22f309e294379d1ca324a76b8f0ba13b8496b75a6657494e97d48b0ea5cfdb8e8ac7f2065360e4b1048 +95cc438ee8e370fc857fd36c3679c5660cf6a6c870f56ef8adf671e6bf4b25d1dbad78872cc3989fdfe39b29fc30486d +8aafba32e4a30cad79c5800c8709241b4041b0c13185ea1aa9bc510858709870b931d70b5d9a629f47579b161f1d8af7 +865b0155d9013e80cba57f204c21910edbd4d15e53ae4fee79992cb854dc8b8a73f0a9be92f74893e30eb70f270511bc +b9a49ce58d40b429ac7192cdbf76da31300efc88c827b1e441dd5bdb2f1c180d57808c48992492a2dc5231008629159f +8d1438b10f6cd996494d4c7b5a0841617ec7cf237c9e0956eac04fda3f9ded5110ec99776b816e3c78abd24eb4a9c635 +af2dd18211bb8a3e77c0a49d5773da6e29e4e6fa6632a6eeb56c4be233f6afe81655d977932548de2be16567c54ffbd7 +92b92443f44464f2b48002a966664a4267eae559fa24051983bcf09d81bed5bcc15cb6ff95139d991707697a5d0cc1ab +a1864a2bac0c0dd5b2fb1a79913dd675fe0a5ae08603a9f69d8ca33268239ac7f2fed4f6bf6182a4775683cb9ccd92a8 +948e8f1cf5bd594c5372845b940db4cb2cb5694f62f687952c73eb77532993de2e2d7d974a2ced58730d12c8255c30a2 +aa825c08284fa74a99fcfc473576e8a9788277f72f8c87f29be1dd41229c286c2753ff7444c753767bd8180226763dfc +8384d8d51415e1a4d6fe4324504e958c1b86374cc0513ddf5bcbffabb3edcf4b7d401421e5d1aa9da9010f07ef502677 +8b8223a42585409041d8a6e3326342df02b2fe0bcc1758ff950288e8e4677e3dc17b0641286eaf759a68e005791c249c +a98a98cc2fb14e71928da7f8ce53ab1fb339851c9f1f4bceb5f1d896c46906bd027ef5950ca53b3c8850407439efedd4 +866f44d2e35a4dbffe6cd539b6ef5901924061e37f9a0e7007696fb23526379c9b8d095b417effe1eecda698de744dcb +91774f44bf15edafdf43957fdf254682a97e493eb49d0779c745cb5dbe5d313bf30b372edd343f6d2220475084430a2e +ab52fc3766c499a5f5c838210aada2c3bcc1a2ec1a82f5227d4243df60809ee7be10026642010869cfbf53b335834608 +a0e613af98f92467339c1f3dc4450b7af396d30cefd35713388ccd600a3d7436620e433bf294285876a92f2e845b90d0 +8a1b5ca60a9ae7adc6999c2143c07a855042013d93b733595d7a78b2dc94a9daa8787e2e41b89197a0043343dbd7610f +ae7e4557bc47b1a9af81667583d30d0da0d4a9bb0c922450c04ec2a4ae796c3f6b0ede7596a7a3d4e8a64c1f9ee8ff36 +8d4e7368b542f9f028309c296b4f84d4bde4837350cf71cfe2fa9d4a71bce7b860f48e556db5e72bc21cf994ffdf8e13 +af6ed1fbff52dd7d67d6a0edfa193aa0aab1536979d27dba36e348759d3649779f74b559194b56e9378b41e896c4886f +a069ba90a349ac462cac0b44d02c52a4adf06f40428aef5a2ddff713de31f991f2247fc63426193a3ea1b1e50aa69ded +8750f5f4baf49a5987470f5022921108abe0ead3829ddef00e61aedd71f11b1cdd4be8c958e169440b6a8f8140f4fbf9 +a0c53cefc08a8d125abd6e9731bd351d3d05f078117ff9c47ae6b71c8b8d8257f0d830481f941f0c349fc469f01c9368 +94eea18c5ed056900c8285b05ba47c940dff0a4593b627fdd8f952c7d0122b2c26200861ef3e5c9688511857535be823 +8e1b7bd80d13460787e5060064c65fbcdac000c989886d43c7244ccb5f62dcc771defc6eb9e00bae91b47e23aeb9a21f +b4b23f9dd17d12e145e7c9d3c6c0b0665d1b180a7cfdf7f8d1ab40b501c4b103566570dca2d2f837431b4bf698984cad +847a47c6b225a8eb5325af43026fb9ef737eede996257e63601f80302092516013fde27b93b40ff8a631887e654f7a54 +9582d7afb77429461bd8ebb5781e6390a4dde12a9e710e183581031ccfacd9067686cfaf47584efaafeb1936eae495cc +8e4fd5dbd9002720202151608f49ef260b2af647bd618eb48ebeceeb903b5d855aa3e3f233632587a88dc4d12a482df9 +87b99fe6a9c1d8413a06a60d110d9e56bb06d9f0268dc12e4ab0f17dd6ca088a16ade8f4fb7f15d3322cbe7bfd319ae1 +b562d23002ed00386db1187f519018edd963a72fca7d2b9fcaab9a2213ac862803101b879d1d8ac28d1ccae3b4868a05 +b4cc8b2acacf2ce7219a17af5d42ce50530300029bc7e8e6e2a3c14ff02a5b33f0a7fecb0bb4a7900ea63befa854a840 +9789f0fe18d832ff72df45befa7cabf0a326b42ada3657d164c821c35ac7ed7b2e0eba3d67856e8c387626770059b0c3 +986c6fe6771418549fa3263fa8203e48552d5ecb4e619d35483cb4e348d849851f09692821c9233ae9f16f36979c30c2 +a9160182a9550c5756f35cea1fe752c647d1b64a12426a0b5b8d48af06a12896833ec5f5d9b90185764db0160905ca01 +82614dbd89d54c1e0af4f6ffe8710e6e871f57ef833cbcb3d3d7c617a75ec31e2a459a89ebb716b18fc77867ff8d5d47 +8fc298ffba280d903a7873d1b5232ce0d302201957226cddff120ffe8df9fee34e08420302c6b301d90e3d58f10beeb9 +898da9ac8494e31705bdf684545eee1c99b564b9601877d226d0def9ec67a20e06f8c8ba2a5202cc57a643487b94af19 +88218478d51c3ed2de35b310beedf2715e30208c18f046ee65e824f5e6fd9def921f6d5f75fd6dde47fa670c9520f91a +89703ae7dff9b3bc2a93b44cdbab12c3d8496063a3c658e21a7c2078e4c00be0eecae6379ee8c400c67c879748f1d909 +a44d463477dece0d45abb0ebb5f130bfb9c0a3bbcd3be62adf84a47bbd6938568a89bc92a53ca638ff1a2118c1744738 +95df2b4d392143ee4c39ad72f636d0ed72922de492769c6264015776a652f394a688f1d2b5cf46077d01fda8319ba265 +aa989867375710ed07ad6789bfb32f85bdc71d207f6f838bd3bde9da5a169325481ac326076b72358808bd5c763ba5bb +b859d97d0173920d16bc01eb7d3ddd47273daac72f86c4c30392f8de05fee643e8d6aa8bebdbc5c2d89037bc68a8a105 +b0249ec97411fa39aa06b3d9a6e04bbbcd5e99a7bc527273b6aa95e7ae5f437b495385adaefa4327231562d232c9f822 +8209e156fe525d67e1c83ec2340d50d45eba5363f617f2e5738117cdcc4a829c4cc37639afd7745cbe929c66754fd486 +99fd2728ceb4c62e5f0763337e6d28bf11fbe5df114217f002bc5cd3543c9f62a05a8a41b2e02295360d007eaab796a6 +902ebc68b8372feeaf2e0b40bd6998a0e17981db9cc9d23f932c34fbcc680292a0d8adcea2ad3fb2c9ed89e7019445c2 +8b5653f4770df67f87cb68970555b9131c3d01e597f514e0a399eec8056e4c5a7deed0371a27b3b2be426d8e860bf9f2 +8f5af27fdc98a29c647de60d01b9e9fd0039013003b44ba7aa75a4b9c42c91feb41c8ae06f39e22d3aed0932a137affa +81babb9c1f5bcc0fd3b97d11dd871b1bbd9a56947794ff70ab4758ae9850122c2e78d53cb30db69ece23538dc4ee033e +b8b65d972734f8ecae10dd4e072fa73c9a1bf37484abcfa87e0d2fcecac57294695765f63be87e1ba4ec0eb95688403a +b0fe17d0e53060aef1947d776b06ab5b461a8ef41235b619ca477e3182fadaf9574f12ffc76420f074f82ac4a9aa7071 +ae265c0b90bf064d7a938e224cb1cd3b7eca3e348fbc4f50a29ac0930a803b96e0640992354aa14b303ea313cb523697 +8bc10ffde3224e8668700a3450463ab460ec6f198e1deb016e2c9d1643cc2fe1b377319223f41ffeb0b85afd35400d40 +8d5113b43aea2e0cc6f8ec740d6254698aff7881d72a6d77affd6e6b182909b4de8eb5f524714b5971b418627f15d218 +ae2ef0a401278b7b5d333f0588773ec62ead58807cdee679f72b1af343c1689c5f314989d9e6c9369f8da9ce76979db6 +b9c1cb996a78d4f7793956daaa8d8825dd43c4c37877bc04026db4866144b1bf37aa804d2fe0a63c374cf89e55e9069f +a35f73851081f6540e536a24a28808d478a2bb1fd15ee7ff61b1562e44fbafc0004b9c92c9f96328d546b1287e523e48 +82007f34e3383c628c8f490654369744592aa95a63a72be6e90848ad54f8bc2d0434b62f92a7c802c93017214ecf326e +9127db515b1ed3644c64eaf17a6656e6663838fed4c6612a444a6761636eaaeb6a27b72d0e6d438c863f67b0d3ec25c5 +984c9fcc3deccf83df3bbbb9844204c68f6331f0f8742119ba30634c8c5d786cd708aa99555196cf6563c953816aec44 +a0f9daf900112029474c56ddd9eb3b84af3ed2f52cd83b4eb34531cf5218e7c58b3cab4027b9fc17831e1b6078f3bf4a +90adbcc921369023866a23f5cea7b0e587d129ad71cab0449e2e2137838cea759dec27b0b922c59ac4870ef6146ea283 +8c5650b6b9293c168af98cf60ad35c945a30f5545992a5a8c05d42e09f43b04d370c4d800f474b2323b4269281ca50f8 +868d95be8b34a337b5da5d886651e843c073f324f9f1b4fbd1db14f74aba6559449f94c599f387856c5f8a7bc83b52a1 +812df0401d299c9e95a8296f9c520ef12d9a3dd88749b51eab8c1b7cc97961608ab9fc241a7e2888a693141962c8fd6d +abda319119d8a4d089393846830eee19d5d6e65059bf78713b307d0b4aad245673608b0880aa31c27e96c8d02eff39c0 +887f11ae9e488b99cb647506dcaa5e2518b169ee70a55cd49e45882fe5bfb35ffaf11feb2bf460c17d5e0490b7c1c14d +b36b6e9f95ffff917ca472a38fa7028c38dc650e1e906e384c10fe38a6f55e9b84b56ffa3a429d3b0c3e2cf8169e66a9 +a0450514d20622b7c534f54be3260bab8309632ca21c6093aa0ccc975b8eed33a922cbcc30a730ccc506edf9b188a879 +87cfaf7bcd5d26875ca665ac45f9decd3854701b0443332da0f9b213e69d6f5521ae0217ec375489cd4fad7b4babf724 +842ad67c1baf7a9d4504c10c5c979ce0a4d1b86a263899e2b5757407c2adcdcf7ed58173ad9d156d84075ef8798cb1c4 +ac1a05755fe4d3fb2ab5b951bafe65cca7c7842022ca567b32cddf7741782cbf8c4990c1dd4ea05dc087a4712844aebb +a000c8cecc4fddeb926dc8dd619952bc51d00d7c662e025f973387a3fc8b1ef5c7c10b6a62e963eb785e0ec04cb1ffbe +8a573c9986dbeb469547dfd09f60078eab252d8ec17351fe373a38068af046b0037967f2b3722fa73ed73512afd038d2 +b8dff15dff931f58ba05b6010716c613631d7dd9562ae5138dbec966630bcdb0e72552e4eefc0351a6a6b7912d785094 +990e81fd459433522e8b475e67e847cb342c4742f0dbf71acc5754244ccd1d9ff75919168588d8f18b8aea17092dd2a4 +b012f8644da2113bef7dd6cdc622a55cfa0734bd267b847d11bba2e257a97a2a465c2bb616c240e197ff7b23e2ce8d8e +a659bd590fde467766e2091c34a0b070772f79380be069eef1afecc470368a95afd9eed6520d542c09c0d1a9dca23bd0 +b9239f318b849079477d1cf0a60a3d530391adacd95c449373da1c9f83f03c496c42097c3f9aca10c1b9b3dbe5d98923 +851e9a6add6e4a0ee9994962178d06f6d4fbc0def97feef1ba4c86d3bcf027a59bafa0cf25876ca33e515a1e1696e5cc +803b9c5276eed78092de2f340b2f0d0165349a24d546e495bd275fe16f89a291e4c74c22fdee5185f8fce0c7fbced201 +95915654ca4656d07575168fb7290f50dc5dcbbcdf55a44df9ec25a9754a6571ab8ca8a159bc27d9fa47c35ffd8f7ffd +88f865919764e8e765948780c4fdd76f79af556cd95e56105d603c257d3bfb28f11efca1dfb2ce77162f9a5b1700bac8 +b1233131f666579b4cc8b37cfa160fc10551b1ec33b784b82685251464d3c095cdde53d0407c73f862520aa8667b1981 +a91115a15cf4a83bda1b46f9b9719cfba14ffb8b6e77add8d5a0b61bea2e4ea8ce208e3d4ed8ca1aab50802b800e763a +93553b6c92b14546ae6011a34600a46021ce7d5b6fbfcda2a70335c232612205dbe6bfb1cc42db6d49bd4042c8919525 +8c2a498e5d102e80c93786f13ccf3c9cab7f4c538ccf0aee8d8191da0dbca5d07dff4448383e0cf5146f6d7e629d64f8 +a66ab92c0d2c07ea0c36787a86b63ee200499527c93b9048b4180fc77e0bb0aa919f4222c4bec46eeb3f93845ab2f657 +917e4fc34081a400fc413335fdf5a076495ae19705f8542c09db2f55fa913d6958fa6d711f49ad191aec107befc2f967 +940631a5118587291c48ac8576cdc7e4a904dd9272acb79407a7d3549c3742d9b3669338adbc1386724cc17ee0cc1ca3 +ae23ae3a531900550671fd10447a35d3653c5f03f65b0fdffe092844c1c95d0e67cab814d36e6388db5f8bd0667cd232 +ae545727fca94fd02f43e848f0fbbb1381fd0e568a1a082bf3929434cc73065bfbc9f2c840b270dda8cc2e08cd4d44b0 +8a9bc9b90e98f55007c3a830233c7e5dc3c4760e4e09091ff30ee484b54c5c269e1292ce4e05c303f6462a2a1bd5de33 +a5a2e7515ce5e5c1a05e5f4c42f99835f6fde14d47ecb4a4877b924246038f5bc1b91622e2ff97ed58737ed58319acfa +8fa9f5edf9153618b72b413586e10aaa6c4b6e5d2d9c3e8693ca6b87804c58dc4bf23a480c0f80cb821ebc3cf20ea4fc +925134501859a181913aadac9f07f73d82555058d55a7d5aaa305067fbd0c43017178702facc404e952ea5cfd39db59b +8b5ab1d9b5127cb590d6bddbf698ffe08770b6fc6527023d6c381f39754aecc43f985c47a46be23fe29f6ca170249b44 +aa39c6b9626354c967d93943f4ef09d637e13c505e36352c385b66e996c19c5603b9f0488ad4014bb5fc2e051b2876cc +8e77399c6e9cb8345002195feb7408eb571e6a81c0418590d2d775af7414fc17e61fe0cd37af8e737b59b89c849d3a28 +a0150aeca2ddc9627c7ea0af0dd4426726583389169bc8174fc1597cc8048299cc594b22d234a4e013dff7232b2d946c +98659422ef91f193e6104b09ff607d1ed856bb6baed2a6386c9457efbc748bd1bf436573d80465ebc54f8c340b697ea5 +8d6fb015898d3672eb580e1ffdf623fc4b23076664623b66bfb18f450d29522e8cb9c90f00d28ccf00af34f730bff7ac +996a8538efa9e2937c1caad58dc6564e5c185ada6cdcef07d5ec0056eb1259b0e4cef410252a1b5dbaee0da0b98dac91 +aa0ae2548149d462362a33f96c3ce9b5010ebf202602e81e0ef77e22cfc57ecf03946a3076b6171bea3d3dc9681187d7 +a5ce876b29f6b89050700df46d679bed85690daf7bad5c0df65e6f3bde5673e6055e6c29a4f4dcb82b93ccecf3bad9cc +81d824bb283c2f55554340c3514e15f7f1db8e9e95dd60a912826b1cccb1096f993a6440834dad3f2a5de70071b4b4b5 +914e7291da286a89dfc923749da8f0bf61a04faa3803d6d10633261a717184065dcc4980114ad852e359f79794877dd9 +ae49dc760db497c8e834510fe89419cc81f33fd2a2d33de3e5e680d9a95a0e6a3ccbdf7c0953beeb3d1caf0a08b3e131 +b24f527d83e624d71700a4b238016835a2d06f905f3740f0005105f4b2e49fc62f7e800e33cdc900d805429267e42fc0 +b03471ecaa7a3bf54503347f470a6c611e44a3cee8218ad3fcad61d286cfb7bb6a1113dad18475ec3354a71fcc4ec1e2 +881289b82b30aff4c8f467c2a25fced6064e1eece97c0de083e224b21735da61c51592a60f2913e8c8ba4437801f1a83 +b4ce59c0fc1e0ecad88e79b056c2fd09542d53c40f41dea0f094b7f354ad88db92c560b9aeb3c0ef48137b1a0b1c3f95 +a1ffb30eb8ef0e3ea749b5f300241ebe748ed7cf480e283dfcda7380aa1c15347491be97e65bc96bdf3fe62d8b74b3ae +b8954a826c59d18c6bfab24719f8730cc901868a95438838cd61dac468a2d79b1d42f77284e86e3382bf4f2a22044927 +818e7e7c59b6b5e22b3c2c19c163f2e787f2ff3758d395a4da02766948935eb44413c3ddd2bf45804a3c19744aa332f3 +a29556e49866e4e6f01d4f042eed803beeda781462884a603927791bd3750331a11bc013138f3270c216ab3aa5d39221 +b40885fa0287dc92859b8b030c7cca4497e96c387dcfe6ed13eb7f596b1eb18fb813e4ae139475d692f196431acb58fe +89cd634682fd99ee74843ae619832780cf7cd717f230ea30f0b1821caf2f312b41c91f459bdba723f780c7e3eed15676 +b48c550db835750d45a7f3f06c58f8f3bf8766a441265ca80089ead0346f2e17cbb1a5e843557216f5611978235e0f83 +90936ee810039783c09392857164ab732334be3a3b9c6776b8b19f5685379c623b1997fb0cdd43af5061d042247bc72f +a6258a6bae36525794432f058d4b3b7772ba6a37f74ef1c1106c80a380fc894cbeac4f340674b4e2f7a0f9213b001afd +8f26943a32cf239c4e2976314e97f2309a1c775777710393c672a4aab042a8c6ee8aa9ac168aed7c408a436965a47aeb +820f793573ca5cc3084fe5cef86894c5351b6078df9807d4e1b9341f9d5422dd29d19a73b0843a14ad63e8827a75d2da +a3c4fca786603cd28f2282ba02afe7cf9287529e0e924ca90d6cdfd1a3912478ebb3076b370ee72e00df5517134fe17f +8f3cdabd0b64a35b9ee9c6384d3a8426cc49ae6063632fb1a56a0ae94affa833955f458976ff309dafd0b2dd540786ae +945a0630cd8fa111cfd776471075e5d2bbe8eb7512408b5c79c8999bfaeca6c097f988fb1c38fa9c1048bac2bca19f2e +8a7f6c4e0ba1920c98d0b0235b4dda73b631f511e209b10c05c550f51e91b4ba3893996d1562f04ac7105a141464e0e9 +ab3c13d8b78203b4980412edc8a8f579e999bf79569e028993da9138058711d19417cf20b477ef7ed627fa4a234c727a +82b00d9a3e29ed8d14c366f7bb25b8cfe953b7be275db9590373a7d8a86ea927d56dc3070a09ef7f265f6dd99a7c896e +b6e48a282de57949821e0c06bc9ba686f79e76fb7cbf50ea8b4651ccd29bc4b6da67efea4662536ba9912d197b78d915 +a749e9edcba6b4f72880d3f84a493f4e8146c845637009f6ff227ff98521dbbe556a3446340483c705a87e40d07364bc +b9b93c94bd0603ce5922e9c4c29a60066b64a767b3aed81d8f046f48539469f5886f14c09d83b5c4742f1b03f84bb619 +afa70b349988f85ed438faafa982df35f242dd7869bda95ae630b7fd48b5674ef0f2b4d7a1ca8d3a2041eff9523e9333 +a8e7e09b93010982f50bd0930842898c0dcd30cdb9b123923e9d5ef662b31468222fc50f559edc57fcfdc597151ebb6e +8ce73be5ac29b0c2f5ab17cae32c715a91380288137d7f8474610d2f28d06d458495d42b9cb156fb1b2a7dfdcc437e1c +85596c1d81f722826d778e62b604eb0867337b0204c9fae636399fa25bb81204b501e5a5912654d215ec28ff48b2cb07 +96ff380229393ea94d9d07e96d15233f76467b43a3e245ca100cbecbdbb6ad8852046ea91b95bb03d8c91750b1dfe6e1 +b7417d9860b09f788eb95ef89deb8e528befcfa24efddbc18deaf0b8b9867b92361662db49db8121aeea85a9396f64fd +97b07705332a59cdba830cc8490da53624ab938e76869b2ce56452e696dcc18eb63c95da6dffa933fb5ffb7585070e2d +971f757d08504b154f9fc1c5fd88e01396175b36acf7f7abcfed4fff0e421b859879ed268e2ac13424c043b96fbe99fc +b9adb5d3605954943a7185bddf847d4dbe7bafe970e55dc0ec84d484967124c26dd60f57800d0a8d38833b91e4da476a +b4856741667bb45cae466379d9d6e1e4191f319b5001b4f963128b0c4f01819785732d990b2f5db7a3452722a61cd8cc +a81ec9f2ab890d099fb078a0c430d64e1d06cbbe00b1f140d75fc24c99fe35c13020af22de25bbe3acf6195869429ba5 +99dcea976c093a73c08e574d930d7b2ae49d7fe43064c3c52199307e54db9e048abe3a370b615798b05fe8425a260ba0 +a1f7437c0588f8958b06beb07498e55cd6553429a68cd807082aa4cc031ab2d998d16305a618b3d92221f446e6cd766d +806e4e0958e0b5217996d6763293f39c4f4f77016b3373b9a88f7b1221728d14227fce01b885a43b916ff6c7a8bc2e06 +8e210b7d1aff606a6fc9e02898168d48ec39bc687086a7fe4be79622dd12284a5991eb53c4adfe848251f20d5bfe9de0 +82810111e10c654a6c07cbfd1aff66727039ebc3226eef8883d570f25117acf259b1683742f916ac287097223afc6343 +92f0e28cca06fd543f2f620cc975303b6e9a3d7c96a760e1d65b740514ccd713dc7a27a356a4be733570ca199edd17ba +900810aa4f98a0d6e13baf5403761a0aeb6422249361380c52f98b2c79c651e3c72f7807b5b5e3a30d65d6ff7a2a9203 +b0740bfefea7470c4c94e85185dbe6e20685523d870ff3ef4eb2c97735cef41a6ab9d8f074a37a81c35f3f8a7d259f0e +af022e98f2f418efbbe2de6fefb2aa133c726174f0f36925a4eafd2c6fd6c744edb91386bafb205ce13561de4294f3a6 +95e4592e21ba97e950abb463e1bc7b0d65f726e84c06a98eb200b1d8bfc75d4b8cff3f55924837009e88272542fd25ec +b13bd6b18cd8a63f76c9831d547c39bbd553bda66562c3085999c4da5e95b26b74803d7847af86b613a2e80e2f08caae +a5625658b474a95aba3e4888c57d82fb61c356859a170bc5022077aa6c1245022e94d3a800bf7bd5f2b9ab1348a8834e +a097ee9e6f1d43e686df800c6ce8cfc1962e5a39bb6de3cf5222b220a41b3d608922dae499bce5c89675c286a98fdabd +94230ba8e9a5e9749cd476257b3f14a6bf9683e534fb5c33ca21330617533c773cb80e508e96150763699ad6ecd5aee7 +b5fea7e1f4448449c4bc5f9cc01ac32333d05f464d0ed222bf20e113bab0ee7b1b778cd083ceae03fdfd43d73f690728 +a18a41a78a80a7db8860a6352642cdeef8a305714543b857ca53a0ee6bed70a69eeba8cfcf617b11586a5cc66af4fc4f +85d7f4b3ff9054944ac80a51ef43c04189d491e61a58abed3f0283d041f0855612b714a8a0736d3d25c27239ab08f2ec +b1da94f1e2aedd357cb35d152e265ccfc43120825d86733fa007fc1e291192e8ff8342306bef0c28183d1df0ccec99d0 +852893687532527d0fbeea7543ac89a37195eadab2f8f0312a77c73bdeed4ad09d0520f008d7611539425f3e1b542cfd +99e3bd4d26df088fc9019a8c0b82611fd4769003b2a262be6b880651d687257ded4b4d18ccb102cba48c5e53891535e4 +98c407bc3bbc0e8f24bedf7a24510a5d16bce1df22940515a4fbdacd20d06d522ef9405f5f9b9b55964915dd474e2b5c +80de0a12f917717c6fc9dc3ccc9732c28bae36cff4a9f229d5eaf0d3e43f0581a635ba2e38386442c973f7cb3f0fdfa7 +94f9615f51466ae4bb9c8478200634b9a3d762d63f2a16366849096f9fc57f56b2e68fe0ca5d4d1327a4f737b3c30154 +a3dcbe16499be5ccb822dfcd7c2c8848ba574f73f9912e9aa93d08d7f030b5076ca412ad4bf6225b6c67235e0ab6a748 +98f137bf2e1aea18289750978feb2e379054021e5d574f66ca7b062410dcfe7abb521fab428f5b293bbe2268a9af3aa4 +8f5021c8254ba426f646e2a15b6d96b337a588f4dfb8cbae2d593a4d49652ca2ada438878de5e7c2dbbd69b299506070 +8cc3f67dd0edcdb51dfd0c390586622e4538c7a179512f3a4f84dd7368153a28b1cf343afd848ac167cb3fcaa6aee811 +863690f09ac98484d6189c95bc0d9e8f3b01c489cb3f9f25bf7a13a9b6c1deaf8275ad74a95f519932149d9c2a41db42 +8494e70d629543de6f937b62beca44d10a04875bd782c9a457d510f82c85c52e6d34b9c3d4415dd7a461abbcc916c3c4 +925b5e1e38fbc7f20371b126d76522c0ea1649eb6f8af8efb389764ddcf2653775ef99a58a2dcf1812ce882964909798 +94d0494dcc44893c65152e7d42f4fb0dc46af5dc5674d3c607227160447939a56d9f9ea2b3d3736074eef255f7ec7566 +b0484d33f0ef80ff9b9d693c0721c77e518d0238918498ddf71f14133eb484defb9f9f7b9083d52bc6d6ba2012c7b036 +8979e41e0bb3b501a7ebbd024567ce7f0171acfea8403a530fe9e791e6e859dfbd60b742b3186d7cf5ab264b14d34d04 +af93185677d39e94a2b5d08867b44be2ba0bb50642edca906066d80facde22df4e6a7a2bd8b2460a22bdf6a6e59c5fdd +90f0ef0d7e7ab878170a196da1b8523488d33e0fde7481f6351558b312d00fa2b6b725b38539063f035d2a56a0f5e8f1 +a9ca028ccb373f9886574c2d0ea5184bc5b94d519aa07978a4814d649e1b6c93168f77ae9c6aa3872dd0eea17968ec22 +82e7aa6e2b322f9f9c180af585b9213fb9d3ad153281f456a02056f2d31b20d0f1e8807ff0c85e71e7baca8283695403 +affce186f842c547e9db2dffc0f3567b175be754891f616214e8c341213cbf7345c9ecd2f704bb0f4b6eba8845c8d8a7 +ab119eb621fade27536e98c6d1bc596388bb8f5cad65194ea75c893edbe6b4d860006160f1a9053aea2946bd663e5653 +99cd2c1c38ead1676657059dc9b43d104e8bd00ae548600d5fc5094a4d875d5b2c529fac4af601a262045e1af3892b5e +b531a43b0714cc638123487ef2f03dfb5272ff399ff1aa67e8bc6a307130d996910fb27075cbe53050c0f2902fc32ffe +923b59ac752c77d16b64a2d0a5f824e718460ef78d732b70c4c776fecc43718ecfaf35f11afbb544016232f445ecab66 +a53439cd05e6e1633cdce4a14f01221efcd3f496ac1a38331365c3cadc30013e5a71600c097965927ee824b9983a79cb +8af976ffab688d2d3f9e537e2829323dda9abf7f805f973b7e0a01e25c88425b881466dee37b25fda4ea683a0e7b2c03 +92e5f40230a9bfbb078fa965f58912abb753b236f6a5c28676fb35be9b7f525e25428160caeaf0e3645f2be01f1a6599 +8c4e7b04e2f968be527feba16f98428508a157b7b4687399df87666a86583b4446a9f4b86358b153e1660bb80bd92e8b +97cd622d4d8e94dceb753c7a4d49ea7914f2eb7d70c9f56d1d9a6e5e5cc198a3e3e29809a1d07d563c67c1f8b8a5665a +967bfa8f411e98bec142c7e379c21f5561f6fd503aaf3af1a0699db04c716c2795d1cb909cccbcb917794916fdb849f1 +b3c18a6caa5ca2be52dd500f083b02a4745e3bcaed47b6a000ce7149cee4ed7a78d2d7012bf3731b1c15c6f04cbd0bd1 +b3f651f1f84026f1936872956a88f39fcfe3e5a767233349123f52af160f6c59f2c908c2b5691255561f0e70620c8998 +ae23b59dc2d81cec2aebcaaf607d7d29cf588f0cbf7fa768c422be911985ca1f532bb39405f3653cc5bf0dcba4194298 +a1f4da396f2eec8a9b3252ea0e2d4ca205f7e003695621ae5571f62f5708d51ca3494ac09c824fca4f4d287a18beea9a +a036fa15e929abed7aac95aa2718e9f912f31e3defd224e5ed379bf6e1b43a3ad75b4b41208c43d7b2c55e8a6fedca72 +80e8372d8a2979ee90afbdb842624ace72ab3803542365a9d1a778219d47f6b01531185f5a573db72213ab69e3ffa318 +af68b5cdc39e5c4587e491b2e858a728d79ae7e5817a93b1ea39d34aec23dea452687046c8feae4714def4d0ed71da16 +b36658dfb756e7e9eec175918d3fe1f45b398679f296119cd53be6c6792d765ef5c7d5afadc5f3886e3f165042f4667f +ad831da03b759716f51099d7c046c1a8e7bf8bb45a52d2f2bfd769e171c8c6871741ef8474f06e2aca6d2b141cf2971f +8bae1202dde053c2f59efc1b05cb8268ba9876e4bd3ff1140fa0cc5fa290b13529aede965f5efdff3f72e1a579efc9cc +86344afbc9fe077021558e43d2a032fcc83b328f72948dba1a074bb1058e8a8faec85b1c019fc9836f0d11d2585d69c8 +831d1fc7aa28f069585d84c46bdc030d6cb12440cfaae28098365577fc911c4b8f566d88f80f3a3381be2ec8088bf119 +899de139797ac1c8f0135f0656f04ad4f9b0fa2c83a264d320eb855a3c0b9a4907fc3dc01521d33c07b5531e6a997064 +855bc752146d3e5b8ba7f382b198d7dc65321b93cdfc76250eabc28dba5bbf0ad1be8ccda1adf2024125107cb52c6a6e +af0aeccab48eb35f8986cabf07253c5b876dd103933e1eee0d99dc0105936236b2a6c413228490ed3db4fa69aab51a80 +ae62e9d706fbf535319c909855909b3deba3e06eaf560803fa37bce3b5aab5ea6329f7609fea84298b9da48977c00c3b +823a8d222e8282d653082d55a9508d9eaf9703ce54d0ab7e2b3c661af745a8b6571647ec5bd3809ae6dddae96a220ea7 +a4c87e0ea142fc287092bc994e013c85e884bc7c2dde771df30ca887a07f955325c387b548de3caa9efa97106da8176a +b55d925e2f614f2495651502cf4c3f17f055041fa305bb20195146d896b7b542b1e45d37fa709ca4bfc6b0d49756af92 +b0ebe8947f8c68dc381d7bd460995340efcbb4a2b89f17077f5fde3a9e76aef4a9a430d1f85b2274993afc0f17fdbead +8baaa640d654e2652808afd68772f6489df7cad37b7455b9cd9456bdddae80555a3f84b68906cc04185b8462273dcfc9 +add9aa08f827e7dc292ac80e374c593cd40ac5e34ad4391708b3db2fe89550f293181ea11b5c0a341b5e3f7813512739 +909e31846576c6bdd2c162f0f29eea819b6125098452caad42451491a7cde9fd257689858f815131194200bca54511f4 +abc4b34098db10d71ce7297658ef03edfa7377bd7ed36b2ffbab437f8fd47a60e2bcfbc93ff74c85cfce74ca9f93106c +857dbecc5879c1b952f847139484ef207cecf80a3d879849080758ef7ac96acfe16a11afffb42daf160dc4b324279d9b +aab0b49beecbcf3af7c08fbf38a6601c21061bed7c8875d6e3c2b557ecb47fd93e2114a3b09b522a114562467fcd2f7d +94306dec35e7b93d43ed7f89468b15d3ce7d7723f5179cacc8781f0cf500f66f8c9f4e196607fd14d56257d7df7bf332 +9201784d571da4a96ef5b8764f776a0b86615500d74ec72bc89e49d1e63a3763b867deca07964e2f3914e576e2ca0ded +aabe1260a638112f4280d3bdea3c84ce3c158b81266d5df480be02942cecf3de1ac1284b9964c93d2db33f3555373dcc +8ef28607ca2e0075aa07de9af5a0f2d0a97f554897cab8827dfe3623a5e9d007d92755d114b7c390d29e988b40466db9 +87a9b1b097c3a7b5055cd9cb0c35ba6251c50e21c74f6a0bca1e87e6463efc38385d3acc9d839b4698dfa2eb4cb7a2ef +aee277e90d2ffce9c090295c575e7cd3bafc214d1b5794dd145e6d02d987a015cb807bd89fd6268cd4c59350e7907ee2 +836ad3c9324eaa5e022e9835ff1418c8644a8f4cd8e4378bd4b7be5632b616bb6f6c53399752b96d77472f99ece123cd +8ffffdb67faa5f56887c834f9d489bb5b4dab613b72eac8abf7e4bcb799ccd0dbd88a2e73077cadf7e761cb159fb5ec5 +9158f6cd4f5e88e6cdb700fddcbc5a99b2d31a7a1b37dce704bd9dd3385cca69607a615483350a2b1153345526c8e05d +a7ff0958e9f0ccff76742fc6b60d2dd91c552e408c84172c3a736f64acb133633540b2b7f33bc7970220b35ce787cd4e +8f196938892e2a79f23403e1b1fb4687a62e3a951f69a7874ec0081909eb4627973a7a983f741c65438aff004f03ba6f +97e3c1981c5cdb0a388f1e4d50b9b5b5f3b86d83417831c27b143698b432bb5dba3f2e590d6d211931ed0f3d80780e77 +903a53430b87a7280d37816946245db03a49e38a789f866fe00469b7613ee7a22d455fb271d42825957282c8a4e159d9 +b78955f686254c3994f610e49f1c089717f5fb030da4f9b66e9a7f82d72381ba77e230764ab593335ff29a1874848a09 +938b6d04356b9d7c8c56be93b0049d0d0c61745af7790edf4ef04e64de2b4740b038069c95be5c91a0ba6a1bb38512a9 +a769073b9648fe21bc66893a9ef3b8848d06f4068805a43f1c180fdd0d37c176b4546f8e5e450f7b09223c2f735b006f +863c30ebe92427cdd7e72d758f2c645ab422e51ecef6c402eb1a073fd7f715017cd58a2ad1afe7edccdf4ff01309e306 +a617b0213d161964eccfc68a7ad00a3ee4365223b479576e887c41ef658f846f69edf928bd8da8785b6e9887031f6a57 +a699834bf3b20d345082f13f360c5f8a86499e498e459b9e65b5a56ae8a65a9fcb5c1f93c949391b4795ef214c952e08 +9921f1da00130f22e38908dd2e44c5f662ead6c4526ebb50011bc2f2819e8e3fca64c9428b5106fa8924db76b7651f35 +98da928be52eb5b0287912fd1c648f8bbda00f5fd0289baf161b5a7dbda685db6ad6bdc121bc9ffa7ed6ae03a13dbee3 +927b91d95676ff3c99de1312c20f19251e21878bfb47ad9f19c9791bc7fb9d6f5c03e3e61575c0760180d3445be86125 +b8e4977a892100635310dfcb46d8b74931ac59ae687b06469b3cee060888a3b6b52d89de54e173d9e1641234754b32b1 +98f6fd5f81ca6e2184abd7a3a59b764d4953d408cec155b4e5cf87cd1f6245d8bdd58b52e1e024e22903e85ae15273f1 +909aaacbbfe30950cf7587faa190dc36c05e3c8131749cc21a0c92dc4afc4002275762ca7f66f91aa751b630ad3e324d +91712141592758f0e43398c075aaa7180f245189e5308e6605a6305d01886d2b22d144976b30460d8ce17312bb819e8f +947d85cb299b189f9116431f1c5449f0f8c3f1a70061aa9ebf962aa159ab76ee2e39b4706365d44a5dbf43120a0ac255 +b39eced3e9a2e293e04d236976e7ee11e2471fe59b43e7b6dd32ab74f51a3d372afee70be1d90af017452ec635574e0e +8a4ba456491911fc17e1cadcbb3020500587c5b42cf6b538d1cb907f04c65c168add71275fbf21d3875e731404f3f529 +8f6858752363e2a94c295e0448078e9144bf033ccd4d74f4f6b95d582f3a7638b6d3f921e2d89fcd6afd878b12977a9d +b7f349aa3e8feb844a56a42f82b6b00f2bfe42cab19f5a68579a6e8a57f5cf93e3cdb56cbbb9163ab4d6b599d6c0f6aa +a4a24dc618a6b4a0857fb96338ac3e10b19336efc26986e801434c8fdde42ca8777420722f45dfe7b67b9ed9d7ce8fb1 +aafe4d415f939e0730512fc2e61e37d65c32e435991fb95fb73017493014e3f8278cd0d213379d2330b06902f21fe4e1 +845cc6f0f0a41cc6a010d5cb938c0ef8183ff5ed623b70f7ea65a8bdbc7b512ea33c0ee8b8f31fdf5f39ec88953f0c1e +811173b4dd89d761c0bdffe224cd664ef303c4647e6cf5ef0ed665d843ed556b04882c2a4adfc77709e40af1cfdea40b +93ba1db7c20bfba22da123b6813cb38c12933b680902cef3037f01f03ab003f76260acc12e01e364c0d0cf8d45fca694 +b41694db978b2cf0f4d2aa06fcfc4182d65fb7c9b5e909650705f779b28e47672c47707d0e5308cd680c5746c37e1bc7 +a0e92c4c5be56a4ccf1f94d289e453a5f80e172fc90786e5b03c1c14ce2f3c392c349f76e48a7df02c8ae535326ea8fe +96cbeb1d0693f4f0b0b71ad30def5ccc7ad9ebe58dbe9d3b077f2ac16256cde10468875e4866d63e88ce82751aaf8ef6 +935b87fd336f0bf366046e10f7c2f7c2a2148fa6f53af5607ad66f91f850894527ecec7d23d81118d3b2ee23351ed6ed +b7c2c1fa6295735f6b31510777b597bc8a7bfb014e71b4d1b5859be0d8d64f62a1587caafc669dfe865b365eb27bd94f +b25d93af43d8704ffd53b1e5c16953fd45e57a9a4b7acfcfa6dd4bf30ee2a8e98d2a76f3c8eba8dc7d08d9012b9694c6 +b5a005cd9f891e33882f5884f6662479d5190b7e2aec1aa5a6d15a8cb60c9c983d1e7928e25e4cf43ec804eaea1d97b0 +93f9f0725a06e4a0fb83892102b7375cf5438b5ebc9e7be5a655f3478d18706cf7dbb1cd1adcee7444c575516378aa1b +900d7cbf43fd6ac64961287fe593c08446874bfc1eb09231fc93de858ac7a8bca496c9c457bced5881f7bf245b6789e0 +90c198526b8b265d75160ef3ed787988e7632d5f3330e8c322b8faf2ac51eef6f0ce5a45f3b3a890b90aecf1244a3436 +b499707399009f9fe7617d8e73939cb1560037ad59ac9f343041201d7cc25379df250219fd73fa012b9ade0b04e92efa +94415f6c3a0705a9be6a414be19d478181d82752b9af760dda0dbd24a8ff0f873c4d89e61ad2c13ebf01de55892d07fa +90a9f0b9f1edb87751c696d390e5f253586aae6ebfc31eb3b2125d23877a497b4aa778de8b11ec85efe49969021eaa5a +a9942c56506e5cd8f9289be8205823b403a2ea233ba211cf72c2b3827064fd34cd9b61ff698a4158e7379891ca4120d8 +83bb2ee8c07be1ab3a488ec06b0c85e10b83a531758a2a6741c17a3ccfa6774b34336926a50e11c8543d30b56a6ac570 +8a08a3e5ebe10353e0b7fff5f887e7e25d09bb65becf7c74a03c60c166132efaada27e5aea242c8b9f43b472561ae3ed +957c7a24cefaa631fe8a28446bc44b09a3d8274591ade53ba489757b854db54820d98df47c8a0fbee0e094f8ad7a5dc4 +b63556e1f47ed3ee283777ed46b69be8585d5930960d973f8a5a43508fc56000009605662224daec2de54ea52a8dcd82 +abed2b3d16641f0f459113b105f884886d171519b1229758f846a488c7a474a718857323c3e239faa222c1ab24513766 +882d36eed6756d86335de2f7b13d753f91c0a4d42ef50e30195cc3e5e4f1441afa5ff863022434acb66854eda5de8715 +a65ea7f8745bb8a623b44e43f19158fd96e7d6b0a5406290f2c1348fc8674fbfc27beb4f724cc2b217c6042cb82bc178 +a038116a0c76af090a069ca289eb2c3a615b96093efacfe68ea1610890b291a274e26b445d34f414cfec00c333906148 +90294f452f8b80b0a47c3bcb6e30bdd6854e3b01deaf93f5e82a1889a4a1036d17ecb59b48efa7dc41412168d7a523dd +88faf969c8978a756f48c6114f7f33a1ca3fd7b5865c688aa9cd32578b1f7ba7c06120502f8dc9aee174ecd41597f055 +8883763b2762dfff0d9be9ac19428d9fd00357ac8b805efda213993152b9b7eb7ba3b1b2623015d60778bffda07a724d +a30a1a5a9213636aa9b0f8623345dc7cf5c563b906e11cc4feb97d530a1480f23211073dcb81105b55193dcde5a381d2 +b45ee93c58139a5f6be82572d6e14e937ef9fcbb6154a2d77cb4bf2e4b63c5aabc3277527ecf4e531fe3c58f521cc5e3 +ac5a73e4f686978e06131a333f089932adda6c7614217fcaf0e9423b96e16fd73e913e5e40bf8d7800bed4318b48d4b1 +b6c1e6cdd14a48a7fe27cd370d2e3f7a52a91f3e8d80fb405f142391479f6c6f31aa5c59a4a0fdc9e88247c42688e0cf +ab1760530312380152d05c650826a16c26223960fc8e3bf813161d129c01bac77583eff04ce8678ff52987a69886526b +a4252dffae7429d4f81dfaeeecc48ab922e60d6a50986cf063964f282e47407b7e9c64cf819da6f93735de000a70f0b2 +94c19f96d5ecf4a15c9c5a24598802d2d21acbbd9ee8780b1bc234b794b8442437c36badc0a24e8d2cff410e892bb1d2 +89fafe1799cf7b48a9ea24f707d912fccb99a8700d7287c6438a8879f3a3ca3e60a0f66640e31744722624139ba30396 +b0108405df25cf421c2f1873b20b28552f4d5d1b4a0bf1c202307673927931cbd59f5781e6b8748ddb1206a5ec332c0b +aa0f0e7d09f12b48f1e44d55ec3904aa5707e263774126e0b30f912e2f83df9eb933ca073752e6b86876adaf822d14ba +b0cbe8abb58876d055c8150d9fdbde4fea881a517a2499e7c2ea4d55c518a3c2d00b3494f6a8fd1a660bfca102f86d2a +b1ef80ec903bac55f58b75933dc00f1751060690fd9dfb54cf448a7a4b779c2a80391f5fda65609274bd9e0d83f36141 +8b52e05b1845498c4879bb12816097be7fc268ce1cf747f83a479c8e08a44159fc7b244cf24d55aca06dccf0b97d11e1 +b632a2fc4fdb178687e983a2876ae23587fd5b7b5e0bb8c0eb4cfe6d921a2c99894762e2aaccdc5da6c48da3c3c72f6c +953ef80ab5f74274ae70667e41363ae6e2e98ccbd6b7d21f7283f0c1cafb120338b7a8b64e7c189d935a4e5b87651587 +b929cfd311017c9731eed9d08d073f6cf7e9d4cd560cddd3fdcb1149ab20c6610a7674a66a3616785b13500f8f43ee86 +870fb0d02704b6a328e68721fb6a4b0f8647681bfcb0d92ec3e241e94b7a53aecc365ed384e721c747b13fbf251002f1 +979501159833a8ba5422ed9b86f87b5961711f5b474d8b0e891373fe2d0b98ff41a3a7a74a8b154615bb412b662a48be +b20f9c13cdeceef67f877b3878839ef425f645b16a69c785fe38f687c87a03b9de9ae31ac2edb1e1dd3a9f2c0f09d35d +8c7705ed93290731b1cf6f3bf87fc4d7159bb2c039d1a9f2246cda462d9cdf2beef62d9f658cfeea2e6aef7869a6fc00 +aa439eb15705ad729b9163daee2598d98a32a8a412777c0d12fd48dc7796d422227a014705e445cc9d66f115c96bbc24 +a32307e16f89749fe98b5df1effef0429801c067e0d8067794e56b01c4fef742ad5e7ab42a1a4cc4741808f47a0b7cb8 +b31e65c549003c1207258a2912a72f5bad9844e18f16b0773ea7af8ff124390eb33b2f715910fc156c104572d4866b91 +85608d918ed7b08a0dc03aee60ea5589713304d85eee7b4c8c762b6b34c9355d9d2e192575af0fd523318ae36e19ae1c +a6497dbaf0e7035160b7a787150971b19cf5ba272c235b0113542288611ebecefa2b22f08008d3f17db6a70a542c258d +87862adb1ac0510614ab909457c49f9ec86dc8bdf0e4682f76d2739df11f6ffcfb59975527f279e890d22964a1fba9b6 +8717ac3b483b3094c3b642f3fafe4fbafc52a5d4f2f5d43c29d9cfe02a569daee34c178ee081144494f3a2ca6e67d7b1 +855100ac1ec85c8b437fdd844abaa0ca4ac9830a5bdd065b68dafb37046fcf8625dd482dc0253476926e80a4c438c9ec +ae74821bf265ca3c8702c557cf9ef0732ede7ef6ed658283af669d19c6f6b6055aca807cf2fa1a64785ec91c42b18ae5 +812a745b1419a306f7f20429103d6813cbdea68f82ff635ac59da08630cd61bda6e0fa9a3735bfd4378f58ad179c1332 +867dbbfe0d698f89451c37ca6d0585fd71ee07c3817e362ef6779b7b1d70b27c989cdd5f85ac33a0498db1c4d14521fe +84db735d3eb4ff7f16502dccc3b604338c3a4a301220ad495991d6f507659db4b9f81bba9c528c5a6114bcdba0160252 +aadc83d1c4e5e32bf786cfb26f2f12a78c8024f1f5271427b086370cdef7a71d8a5bf7cd7690bae40df56c38b1ad2411 +a27860eb0caaea37298095507f54f7729d8930ac1929de3b7a968df9737f4c6da3173bda9d64ff797ed4c6f3a1718092 +a3cdcaa74235c0440a34171506ed03d1f72b150d55904ce60ec7b90fcd9a6f46f0e45feab0f9166708b533836686d909 +b209a30bdac5c62e95924928f9d0d0b4113ebb8b346d7f3a572c024821af7f036222a3bd38bd8efd2ee1dbf9ac9556cd +83c93987eff8bc56506e7275b6bef0946672621ded641d09b28266657db08f75846dcbde80d8abc9470e1b24db4ca65b +800c09b3ee5d0251bdaef4a82a7fe8173de997cc1603a2e8df020dd688a0c368ad1ebef016b35136db63e774b266c74c +93fb52de00d9f799a9bce3e3e31aaf49e0a4fc865473feb728217bd70f1bc8a732ec37ac3582bf30ab60e8c7fdf3cb8d +a1aff6b4a50d02f079a8895c74443539231bfdf474600910febf52c9151da7b31127242334ac63f3093e83a047769146 +8c4532d8e3abb5f0da851138bfa97599039bcd240d87bbdf4fd6553b2329abb4781074b63caf09bc724ceb4d36cb3952 +8bd9b0ae3da5acda9eb3881172d308b03beec55014cd73b15026299541c42fd38bab4983a85c06894ebb7a2af2a23d4c +979441e7f5a0e6006812f21b0d236c5f505bb30f7d023cb4eb84ec2aa54a33ac91d87ece704b8069259d237f40901356 +a1c6d2d82e89957d6a3e9fef48deb112eb00519732d66d55aa0f8161e19a01e83b9f7c42ac2b94f337dcc9865f0da837 +97a0b8e04e889d18947d5bf77d06c25bbd62b19ce4be36aaa90ddbeafd93a07353308194199ba138efaadf1b928cd8d2 +822f7fbe9d966b8ec3db0fc8169ab39334e91bf027e35b8cc7e1fe3ead894d8982505c092f15ddfe5d8f726b360ac058 +a6e517eedd216949e3a10bf12c8c8ddbfde43cddcd2c0950565360a38444459191bdbc6c0af0e2e6e98bc6a813601c6d +858b5f15c46c074adb879b6ba5520966549420cb58721273119f1f8bc335605aeb4aa6dbe64aae9e573ca7cc1c705cdc +b5191bb105b60deb10466d8114d48fb95c4d72036164dd35939976e41406dff3ee3974c49f00391abfad51b695b3258c +b1b375353ed33c734f4a366d4afad77168c4809aff1b972a078fd2257036fd6b7a7edad569533abf71bc141144a14d62 +a94c502a9cdd38c0a0e0187de1637178ad4fa0763887f97cc5bdd55cb6a840cb68a60d7dbb7e4e0e51231f7d92addcff +8fe2082c1b410486a3e24481ae0630f28eb5b488e0bb2546af3492a3d9318c0d4c52db1407e8b9b1d1f23a7ffbaf260a +b73fe7aa2b73f9cae6001af589bf8a9e73ea2bb3bb01b46743e39390c08d8e1be5e85a3d562857a9c9b802b780c78e6d +8e347f51330ae62275441ccd60f5ac14e1a925a54ced8a51893d956acc26914df1bb8595385d240aa9b0e5ada7b520ea +8dc573d6357c0113b026a0191a5807dbe42dcd2e19772d14b2ca735e1e67c70e319ef571db1f2a20e62254ed7fb5bcd6 +a5dacbe51549fe412e64af100b8b5eba5ec2258cc2a7c27a34bc10177d1894baf8707886d2f2ef438f077596a07681e9 +8349153c64961d637a5ff56f49003cb24106de19a5bbcf674016a466bfbe0877f5d1e74ccb7c2920665ef90a437b1b7e +96ad35429d40a262fdc8f34b379f2e05a411057d7852c3d77b9c6c01359421c71ef8620f23854e0f5d231a1d037e3a0d +b52385e40af0ed16e31c2154d73d1517e10a01435489fc801fbea65b92b3866ab46dab38d2c25e5fb603b029ae727317 +8e801c7a3e8fa91d9c22ebd3e14a999023a7b5beea13ec0456f7845425d28c92452922ca35ec64012276acb3bbc93515 +a8630870297d415e9b709c7f42aa4a32210b602f03a3015410123f0988aea2688d8bcfc6d07dc3602884abbf6199b23f +8cd518392e09df2a3771a736f72c05af60efc030d62dbbb9cd68dc6cbbe1fb0854eb78b6ed38337010eb1bb44a5d5d30 +921aa4c66590f6c54bf2fa2b324f08cbe866329cc31f6e3477f97f73e1a1721d5eb50ed4eacc38051fe9eda76ba17632 +a37e595cb63524cb033c5540b6343c3a292569fc115e813979f63fe1a3c384b554cecc2cae76b510b640fe3a18800c81 +b0bb57e4e31ae3ce9f28cef158ed52dabfad5aa612f5fcc75b3f7f344b7cec56b989b5690dacd294e49c922d550ee36b +a3c618ce4d091e768c7295d37e3f9b11c44c37507ae1f89867441f564bf0108f67bf64b4cf45d73c2afc17a4dc8b2c68 +999e6650eda5455e474c22a8c7a3fd5b547ec2875dc3043077ad70c332f1ccd02135e7b524fcbf3621d386dec9e614fa +b018f080888dec3c2ca7fcfeb0d3d9984699b8435d8823079fc9e1af4ca44e257fbe8da2f6f641ee6152b5c7110e3e3c +a2bcd4bcd9b40c341e9bba76b86481842f408166c9a7159205726f0776dcb7f15a033079e7589699e9e94ce24b2a77fd +b03de48f024a520bb9c54985ca356fd087ca35ac1dd6e95168694d9dae653138c9755e18d5981946a080e32004e238fe +a6c1a54973c0c32a410092441e20594aa9aa3700513ed90c8854956e98894552944b0b7ee9edf6e62e487dc4565baa2f +845d7abf577c27c4c1fafc955dcad99a1f2b84b2c978cfe4bd3cd2a6185979491f3f3b0ec693818739ed9184aba52654 +9531bcfc0d3fcd4d7459484d15607d6e6181cee440ba6344b12a21daa62ff1153a4e9a0b5c3c33d373a0a56a7ad18025 +a0bbf49b2dd581be423a23e8939528ceaae7fb8c04b362066fe7d754ca2546304a2a90e6ac25cdf6396bf0096fae9781 +a1ec264c352e34ed2bf49681b4e294ffea7d763846be62b96b234d9a28905cdece4be310a56ec6a00fc0361d615b547c +87c575e85b5dfbfd215432cb355a86f69256fff5318e8fda457763ac513b53baa90499dc37574bdfad96b117f71cb45e +9972edfdeec56897bef4123385ee643a1b9dc24e522752b5a197ce6bd2e53d4b6b782b9d529ca50592ee65b60e4c9c3c +b8bcf8d4ab6ad37bdd6ad9913a1ba0aba160cb83d1d6f33a8524064a27ba74a33984cc64beeee9d834393c2636ff831a +83082b7ec5b224422d0ff036fbb89dc68918e6fde4077dfc0b8e2ee02595195ecadb60c9ab0ad69deb1bac9be75024fa +8b061fce6df6a0e5c486fd8d8809f6f3c93bd3378a537ff844970492384fb769d3845d0805edd7f0fcd19efabf32f197 +b9597e717bb53e6afae2278dbc45d98959c7a10c87c1001ed317414803b5f707f3c559be6784119d08f0c06547ec60b1 +b9d990fd7677dd80300714cfd09336e7748bbf26f4bb0597406fcb756d8828c33695743d7a3e3bd6ddf4f508149610ef +b45f7d2b00ceea3bf6131b230b5b401e13a6c63ba8d583a4795701226bf9eb5c88506f4a93219ac90ccbceef0bfd9d49 +a8ccaa13ca7986bc34e4a4f5e477b11ae91abb45c8f8bf44a1f5e839289681495aba3daa8fb987e321d439bbf00be789 +ae0f59f7a94288a0ead9a398fdd088c2f16cccb68624de4e77b70616a17ddf7406ca9dc88769dadeb5673ff9346d6006 +b28e965dcc08c07112ae3817e98f8d8b103a279ad7e1b7c3de59d9dbd14ab5a3e3266775a5b8bbf0868a14ae4ab110f1 +84751c1a945a6db3df997fcbde9d4fe824bc7ba51aa6cb572bb5a8f9561bef144c952198a783b0b5e06f9dd8aa421be8 +a83586db6d90ef7b4fa1cbda1de1df68ee0019f9328aded59b884329b616d888f300abb90e4964021334d6afdea058fd +8fcea1ce0abf212a56c145f0b8d47376730611e012b443b3d1563498299f55cbcbe8cbd02f10b78224818bb8cbbd9aaa +8d66c30a40c34f23bae0ea0999754d19c0eb84c6c0aa1b2cf7b0740a96f55dd44b8fee82b625e2dd6c3182c021340ac6 +92c9b35076e2998f1a0f720d5a507a602bd6bd9d44ffc29ede964044b17c710d24ce3c0b4a53c12195de93278f9ec83b +a37d213913aff0b792ee93da5d7e876f211e10a027883326d582ad7c41deebdfce52f86b57d07868918585908ebd070a +a03995b4c6863f80dd02ed0169b4f1609dc48174ec736de78be1cdff386648426d031f6d81d1d2a7f2c683b31e7628c0 +b08b628d481302aa68daf0fa31fd909064380d62d8ed23a49037cb38569058e4c16c80e600e84828d37a89a33c323d1f +a0ee2e2dd8e27661d7b607c61ac36f590909aa97f80bdfd5b42463ca147b610ac31a9f173cbecdd2260f0f9ea9e56033 +967162fba8b69ffce9679aac49214debb691c6d9f604effd6493ce551abacbe4c8cc2b0ccee6c9927c3d3cfbdcb0be11 +8deab0c5ed531ce99dadb98b8d37b3ff017f07438bc6d50840577f0f3b56be3e801181333b4e8a070135f9d82872b7f2 +b1bfa00ec8c9365b3d5b4d77a718cb3a66ed6b6cf1f5cf5c5565d3aa20f63d3c06bb13d47d2524e159debf81325ba623 +90109780e53aeacd540b9fe9fc9b88e83c73eaf3507e2b76edc67f97a656c06a8a9e1ec5bce58bfd98b59a6b9f81b89d +88a1009a39a40421fdcc0ffc3c78a4fbace96a4e53420b111218091223494e780a998ebecf5a0abd0243e1523df90b28 +90b77146711ee8d91b0346de40eca2823f4e4671a12dad486a8ec104c01ef5ee7ab9bd0398f35b02b8cb62917455f8b3 +b262c5e25f24ae7e0e321b66fdb73b3bf562ded566a2d6a0152cf8bafb56138d87b6a917a82f5ace65efc73cfc177d81 +ae65a438c7ea46c82925b5ec5f71314558ca5146f5d90311431d363cfeac0537223c02cbb50fa6535d72fc2d949f4482 +8984208bfc193a6ef4720cc9d40c17f4be2f14595ef887980f2e61fa6927f9d73c00220937013b46290963116cbe66ac +a8f33a580508f667fac866456dce5d9246562188ad0f568eb1a2f28cf9fd3452dd20dc613adb1d07a5542319a37ecf1a +aedadd705fc086d8d2b647c62e209e2d499624ab37c8b19af80229f85e64a6e608d9cd414cb95ae38cf147d80ec3f894 +ae28077a235cd959f37dc3daedc3706f7a7c2ffe324e695f2e65f454bf5a9fc27b10149a6268ebfaa961ad67bb9b75d7 +a234c7f5a5e0e30f2026d62657bd92d91a9907ec6a2177f91383f86abb919778121ff78afb8f52c473fe6fb731018b52 +816a2ea7826b778f559a815267b6c6eb588558391c0a675d61bb19470d87489ba6c1e2486ea81dd5420a42ee7c35a8de +9218b61948c14234f549c438105ae98367ef6b727ad185f17ad69a6965c044bb857c585b84d72ef4c5fb46962974eed7 +a628031217a0b1330b497351758cf72d90fb87d8bdf542ea32092e14ff32d5ef4ca700653794bb78514d4b0edfd7a8d7 +ab4e977141be639a78eb9ed17366f9642f9335873aca87cce2bae0dddc161621d0e23264a54a7395ae706d748c690ee9 +b1538c4edff59bcf5668557d994bac77d508c757e382512c4368c1ded4242a41f6200b73fe8809fb528a7a0c1fc96feb +965caabe5590e2ff8c9f1048bbdda2817e7a2847e287944bfab40d94cb48389441ac42ff3a7b559760bfab42ff82e1e0 +a64b7484d22c4b8047c7a8ef54dc88cb8d110c61ef28ba853821b61e87d318b2b4226f7f0d1f3cdf086a0e1666d0212c +8915ab7e41d974eef9a651b01c2521392e8899e6ab91c22aeee61605c78fb2b052399ba1d03473aa9cfb52d1a8ba4257 +8dd26875d4a1716db2f75a621d01e971983267770e2da92399aecf08f74af1f7e73643ac6f0a9b610eda54e5460f70ed +83dabcb84c9cbce67e1a24ecbfa4473766b9519588b22288edbaa29aca34cefd9884f7310e7771f8f7a7cbced2e7eea0 +956be00c67987fb4971afca261065a7f6fcef9fb6b1fcb1939f664bbc5b704223253ebfda48565624a68fb249742c2cf +a374824a24db1ab298bee759cee8d8260e0ac92cd1c196f896600fd57484a9f9be1912ded01203976ac4fab66c0e5091 +a225f2ed0de4e06c500876e68e0c58be49535885378584a1442aae2140c38d3ca35c1bc41936a3baf8a78e7ab516f790 +8e79c8de591a6c70e2ef2de35971888ab0ca6fd926fdb6e845fb4b63eb3831c5839f084201b951984f6d66a214b946b8 +91babc849a9e67ab40192342c3d0d6ce58798101cb85c9bd7fc0ac4509ffc17b5ea19e58045cf1ca09ec0dee0e18c8f9 +8b4897fc2aef5bbe0fa3c3015ca09fc9414fdb2315f54dbecc03b9ae3099be6c0767b636b007a804d8b248c56e670713 +8f63ba42e7459ea191a8ad18de0b90b151d5acbf4751e2c790e7d8328e82c20de518132d6290ff3c23d2601f21c1558e +a1a035dc9b936587a16665ea25646d0bb2322f81960d9b6468c3234c9137f7c2b1e4f0b9dbe59e290a418007b0e7a138 +81c4904c08f7bb2ac7b6d4ac4577f10dd98c318f35aac92fc31bab05eceb80a0556a7fc82614b8d95357af8a9c85a829 +8c40e44e5e8e65f61e0a01f79057e1cb29966cc5074de790ea9c60454b25d7ea2b04c3e5decb9f27f02a7f3d3cb7014f +ad8709e357094076eb1eb601539b7bcc37247a25fbc6ada5f74bb88b1b371917c2a733522190f076c44e9b8e2ae127fb +92d43cd82c943fd71b8700977244436c696df808c34d4633f0624700a3445f3ecc15b426c850f9fb60b9aa4708f2c7c0 +b2cb8080697d1524a6dcb640b25e7255ae2e560613dbd27beaa8c5fc5c8d2524b7e6edd6db7ad0bb8a4e2e2735d4a6f7 +971ca6393d9e312bfb5c33955f0325f34946d341ff7077151f0bcafd2e6cbd23e2ad62979454f107edc6a756a443e888 +b6a563f42866afcee0df6c6c2961c800c851aa962d04543541a3cedeb3a6a2a608c1d8391cf405428cd40254e59138f3 +986bd17bad9a8596f372a0185f7f9e0fb8de587cd078ae40f3cd1048305ba00954aff886b18d0d04640b718ea1f0d5a3 +ae32dbccfb7be8e9165f4e663b26f57c407f96750e0f3a5e8e27a7c0ca36bc89e925f64ddd116263be90ace4a27872c4 +83725445ec8916c7c2dd46899241a03cf23568ac63ae2d34de3bce6d2db0bc1cfd00055d850b644a059fb26c62ed3585 +a83f7e61c05b1c6797a36ad5ded01bf857a838147f088d33eb19a5f7652b88e55734e8e884d1d1103a50d4393dfcd7a8 +aa010b4ec76260d88855347df9eaf036911d5d178302063d6fd7ecad009e353162177f92240fe5a239acd1704d188a9d +a88f4ba3cf4aff68ec1e3ded24622d4f1b9812350f6670d2909ea59928eb1d2e8d66935634d218aeac6d1a0fc6cae893 +b819112b310b8372be40b2752c6f08426ef154b53ef2814ae7d67d58586d7023ffa29d6427a044a3b288e0c779866791 +b5d1e728de5daf68e63b0bb1dee5275edae203e53614edeeeefff0f2f7ac4281191a33b7811de83b7f68111361ef42e1 +953fb3ddc6f78045e53eaacfd83c5c769d32608b29391e05612e4e75725e54e82ad4960fbef96da8b2f35ba862968a3e +936471136fb2c1b3bb986a5207a225a8bf3b206a1a9db54dc3029e408e78c95bfb7539b67006d269c09df6354d7254ac +ac353364b413cae799b13d7dc6fa09c322b47e60b9333e06499155e22d913929b92a45a0ad04ba90b29358f7b792d864 +a0177419ead02ba3f0755a32eee3fd23ec81a13c01eab462f3b0af1e2dba42f81b47b2c8b1a90d8cec5a0afa371b7f11 +b009eeb5db80d4244c130e6e3280af120917bb6fcebac73255c09f3f0c9da3b2aa718cd92d3d40e6b50737dbd23461aa +b8a43426c3746c1a5445535338c6a10b65474b684a2c81cd2f4b8ebecc91a57e2e0687df4a40add015cd12e351bbb3eb +94ff3698a6ac6e7df222675a00279c0ea42925dc6b748e3e74a62ea5d1e3fd70d5ab2d0c20b83704d389dd3a6063cf1a +90e4142e7ce15266144153e21b9893d3e14b3b4d980e5c87ce615ecd27efac87d86fa90354307857f75d7ebaeffe79ef +a5fd82c3f509ec9a36d72ba204a16f905e1e329f75cfd18aaa14fb00a212d21f3fac17e1a8e3bc5691ab0d07f8ec3cd0 +962e6bfd75ea554f304a5fee1123e5bf2e048ccd3b401716b34c52740384579188ac98bc0d91269fc814de23f4b2dd34 +b50b4e45c180badf9cd842cd769f78f963e077a9a4c016098dc19b18210580ad271ae1ba86de7760dd2e1f299c13f6a0 +84cf08858d08eca6acc86158ffda3fbe920d1d5c04ac6f1fc677760e46e66599df697397373959acf319c31e47db115c +a697a38ba21caa66b7739ed0e74fe762a3da02144b67971fcad28c1132d7b83e0ac062cc71479f99e2219086d7d23374 +ad1f6d01dd7f0de814fe5fbb6f08c1190ff37f4a50754d7b6291fc547c0820506ea629aabacf749fec9c1bbfda22d2d0 +b11fd7f8c120d8a370a223a1adc053a31bef7454b5522b848dec82de5482308fc68fdaf479875b7a4bc3fc94e1ea30eb +93ecf90ebfc190f30086bcaeee18cda972073a8469cf42a3b19f8c1ec5419dff2d6a5cc8ef412ccd9725b0f0a5f38f88 +911f25aaa5260b56b3009fa5e1346a29f13a085cf8a61b36b2d851791f7bcf8456840eccbfc23797b63ecd312e2d5e12 +a52f17a8b2db66c98291020b1db44ab23827e1790e418e078d1316185df6aa9f78292f43a12cd47131bd4b521d134060 +9646fca10bf7401e91d9a49753c72f3ecb142f5ed13aba2c510a6c5ccb8d07b8e8d1581fc81321ad5e3996b6d81b5538 +aa1da4a5665b91b62dda7f71bb19c8e3f6f49cc079d94fcd07b3604a74547e8334efa5a202822d0078158056bbda2822 +a2432ae5feeaf38252c28aa491e92a68b47d5b4c6f44c1b3d7f3abc2f10b588f64a23c3357e742a0f5e4f216e7ca5827 +83c7b47735cd0ef80658a387f34f259940096ebb9464c67919b278db4109fea294d09ea01a371b79b332cff6777c116d +a740a2959e86e413c62d6bdd1bc27efe9596ee363c2460535eab89ba1715e808b658bd9581b894b5d5997132b0c9c85c +b76947237fa9d71c3bece0b4f7119d7f94d2162d0ced52f2eac4de92b41da5b72ad332db9f31ebb2df1c02f400a76481 +a20e1f2b7e9cc1443226d2b1a29696f627c83836116d64d2a5559d08b67e7e4efa9a849f5bb93a0dadb62450f5a9eaab +b44bff680fba52443a5b3bd25f69c5640006d544fca1d3dc11482ee8e03b4463aae59d1ec9d200aa6711ce72350580fb +a9490f5643bacec7e5adcda849ab3e7ff1f89026bf7597980b13a09887376f243158d0035e9d24fdee7cb6500e53ef29 +96081010b82c04ad0bfc3605df622db27c10a91494685ef2e6e1839c218b91cbb56e043e9a25c7b18c5ddee7c6769517 +a9522d59bcf887cbbbc130d8de3ff29a86df5d9343a918f5e52c65a28e4c33f6106ac4b48ecd849a33d39eeb2319d85b +aa5e0cea1a1db2283783788b4d77c09829563b75c503c154fdaa2247c9149918edac7737ef58c079e02dca7d8397b0eb +8c03f064e777d0c07c4f04c713a86bf581cc85155afe40e9065ead15139b47a50ead5c87ac032f01b142d63ff849758a +a34d672bf33def02ee7a63e6d6519676c052fa65ca91ed0fe5fdd785c231ba7af19f1e990fc33f5d1d17e75f6af270be +8680443393e8ac45a0b07c30a82ac18e67dcc8f20254bd5ede7bf99fc03e6123f2fcd64c0ca62f69d240f23acd777482 +a4e00ab43d8ae5b13a6190f8ef5395ec17fbac4aa7dfa25b33e81b7e7bf63a4c28910b3a7dc9204dbc4168b08575a75e +8249259066ee5672b422c1889ab5ed620bddd1297f70b4197c40bb736afba05d513b91d3a82ee030336c311d952cd60c +a0651d8cf34fa971bde1ec037158a229e8e9ad4b5ca6c4a41adedb6d306a7772634f703dcfac36f9daf17289f33c23fb +b02ff6e8abff19969e265395ceaf465f43e7f1c3c9cfc91f1748042d9c352b284e49515a58078c877a37ff6915ee8bf4 +927fb7351ac28254458a1a2ea7388e1fbd831fbc2feedb230818f73cc8c505b7ff61e150898ce1567fcb0d2c40881c7b +a9d3861f72090bc61382a81286bb71af93cdeefab9a83b3c59537ad21810104e0e054859eeafa13be10f8027b6fc33b8 +a523306656730b1a31b9a370c45224b08baf45773d62952a0bf7d6c4684898ae78914cfafbd3e21406407cc39e12afdc +947a090e7703a3ea303a4a09b3ab6b6d3fda72912c9f42cc37627557028b4667f5398a6d64b9281fa2efbe16f6c61ed6 +b41d24d40c10239c85d5b9bf1a3886d514a7a06b31ca982ea983e37162293350b12428eabc9f6a460473ad811e61ba40 +b0bb9805724f4ca860e687985c0dc6b8f9017fe71147e5383cfbbbdcb2a42c93c7062ba42acdead9d992b6f48fc1d5ac +aec775aa97a78851893d3c5c209a91267f1daf4205bfb719c44a9ed2614d71854b95bb523cd04a7f818a4a70aa27d8fc +b53e52e32ca90b38987610585ad5b77ecd584bd22c55af7d7c9edf5fbcae9c9241b55200b51eaed0fbdb6f7be356368f +a2c5ac7822c2529f0201717b4922fb30fb037540ab222c97f0cdac341d09ccb1415e7908288fabef60177c0643ed21bf +92162fda0cbd1dafbed9419ae0837e470451403231ee086b49a21d20de2e3eed7ce64382153272b02cf099106688af70 +8452d5df66682396718a76f219a9333a3559231e5f7f109a1f25c1970eb7c3408a5e32a479357f148af63b7a1d352451 +831ea95d4feb520994bc4904017a557797e7ad455a431d94de03b873a57b24b127fcc9ff5b97c255c6c8d8e18c5c7e12 +93d451d5e0885ccdbb113a267c31701e7c3d9e823d735dc9dfd6cfdcd82767012dc71396af53d3bedd2e0d9210acf57f +a2126f75a768dcc7ebddf2452aebf20ad790c844442b78e4027c0b511a054c27efb987550fcab877c46f2c7be4883ae0 +aa4d2dcba2ccfc11a002639c30af6beb35e33745ecbab0627cf0f200fdae580e42d5a8569a9c971044405dfdafed4887 +ab13616069ef71d308e8bf6724e13737dc98b06a8f2d2631284429787d25d43c04b584793256ed358234e7cd9ad37d1f +9115ee0edc9f96a10edcafeb9771c74321106e7f74e48652df96e7ca5592a2f448659939291ff613dd41f42170b600ad +97b10a37243dc897ccc143da8c27e53ccc31f68220bffd344835729942bb5905ae16f71ccaed29ca189432d1c2cc09b1 +875cf9c71ae29c3bde8cdcb9af5c7aca468fbb9243718f2b946e49314221a664959140c1ebc8622e4ed0ba81526302fd +86b193afbb7ff135ce5fc7eb0ee838a22e04806ceec7e02b3fb010e938fff733fc8e3a1d4b6cba970852d6307018b738 +b3403a94f1483edce5d688e5ed4ab67933430ede39cd57e2cddb4b469479018757d37dd2687f7182b202967da12a6c16 +83edfa0a6f77974c4047b03d7930e10251e939624afa2dcafbd35a9523c6bf684e1bb7915fc2e5b3ded3e6dc78daacf2 +88ff3375fe33942e6d534f76ed0f1dfa35ae1d62c97c84e85f884da76092a83ecd08454096c83c3c67fac4cd966673d7 +af0726a2a92ee12a9411db66333c347e1a634c0ab8709cc0eab5043a2f4afac08a7ae3a15ce37f5042548c6764ae4cf6 +81cfa33bb702e2f26169a006af0af0dcaa849cec2faf0f4784a06aa3c232d85a85b8123d49a1555cca7498d65e0317e4 +910a16526176b6e01eb8fb2033ffbb8c9b48be6e65f4c52c582909681805b3d9e1c28e3b421be9b9829b32175b8d4d80 +93d23befa411ca1adbdba726f762f2403e1cc740e44c9af3e895962e4047c2782ca7f2f9878512c37afd5a5a0abbd259 +82fcf316027fedfe235905588b7651b41e703836f96cb7ac313b23b4e6c134bff39cd10b3bddb7458d418d2b9b3c471b +8febc47c5752c513c4e5573428ad0bb40e15a5e12dbfa4c1ef29453f0588f0b75c3591075fef698e5abcf4d50c818a27 +83dab521d58b976dcea1576a8e2808dfaea9fa3e545902d0e0ce184d02dca8245d549134a238ab757950ad8bc11f56eb +898cfb9bf83c1c424eca817e8d0b99f5e482865070167adab0ecf04f3deeb3c71363b9f155c67b84d5e286c28238bef8 +b845e388cc1a8e8b72a24d48219ac4fd7868ee5e30960f7074b27dada842aa206889122acfce9e28512038547b428225 +b1ce4720e07e6eecc2a652f9edbad6bd5d787fbaff2a72a5ca33fa5a054dd3b4d5952563bc6db6d1ce1757a578bba480 +8db6990dd10741cf5de36e47726d76a12ebe2235fdcb8957ab26dba9466e6707d4a795d4e12ec7400d961bd564bdee7e +a3ca7afd20e16c2a45f73fc36357763847ed0be11cb05bfd9722f92c7ba3fa708cf10d4e0ae726c3eccae23cc55fd2be +8701b085c45b36f3afb589207bbf245ef4c5c82aa967ecd0c334daa1f5a54093c5e0fcacd09be540801920f49766aa0f +84e3736727ba76191d9a6a2a3796f55bb3c3a8bbb6e41f58e892ea282c90530b53ab5490bbf1a066723399bb132160fb +87c02a01917333c7b8866f6b717b1e727b279894108f70574d1b6e9e8dc978eda8778342baf3c6464d6e0dd507163e76 +b8da532dac81fafaed759e99c3ae011d75f3fda67a8c420c3b9747281fe32e31ac3c81e539940286440704c2c3e3b53e +a0cc63c3bef75a5c02942977a68a88cd3d103d829b6c0f070f64206da7e3638f10f42452788092de8fbbc626ce17b0d4 +b5c9317b3f6b1d7ee6871506c0430cdf73e28b02c001ba6ca11061c7e121c91152d2b80c4f80e1d8f51ff5653bc0db5b +b798fb572da977dd3ef2dce64042b012a470d6bd2cb61a16267abe2b8399f74540d7c70462a6b2278d73567447e31994 +b868eda58739effda68c834745cd2cf66a09f0f215607b65685bb5ca3eba71150f43a6e47b81a0c19fb58eeae3da56e8 +9041c93a7e8f2c34812fd6e9744b154e898e1ef69db72bf36242c71e2c251f3db7e86cbd802da603a92cd0b06b62ea63 +a834d648e974230582fc17b3a449f4f65b3297038a3a5401e975b9b60ff79b2006a33e1486d3428106580276993311e1 +a3ce874da6ade9f0f854d7ae7651fc3ff63cec748a847527539fe0d67e6c99eaa3011065a4627c2192af7f9569f7ab57 +ae78ad16de150cc0400d3b6b424c608cd2b2d01a7a38ea9c4e504d8463c0af09613774dbefdd5198415b29904e0fbb63 +b966db5a961067e743212d564595ef534e71dcd79b690a5a2c642d787059fc7959b9039b650372461a1f52910f7e857b +8069904f360af3edfd6cabd9b7f2adf5b61bd7feb0e9a040dc15c2a9d20052c3e5e0158f3065ec3200d19b91db603b71 +9600917dbcd80a47f81c02c3aafecfcef77f031bf612a0f1a8bdef09de9656f4bb0f8e3e95f72ece1c22bd2824f145b6 +834a0767b7b6199496c1faee0e3580c233cc0763e71eebc5d7c112a5a5e5bd95c0cf76a32ea5bb1b74f3cf00fbd2cfb4 +99469a893579ed5da7d34ec228854c4666c58115d3cae86d4fc2d03d38f10d8c5dc8fb693763a96ab6be2045cc8d518b +a52cc0aecda6594de57d8ca13b146e77212cc55854929c03f2a8a6cdfa46296791c336aebcc2610d98612d5b4c0452df +97864434d55aa8a7aad0415d36f9558ce6e6c00452923db68a1e738232d0cb2d47e3b0b8f340c709112838adeaee4695 +a4a7f2c45db3661b6af7ec759f9455ba043b0de6fd4787e3372cba215b9f7c641d5d817a0576e7aa28a46349d2fe0ae6 +864e857652d95e1d168c1b9c294777fc9251a4d5b4b00a346b1f1c9c898af9a9b5ec0ac1f3a66f18a370b721dbd77b23 +ab8eac458fa8e7eb5539da3964ccd297a216448c3af4e4af0dcfed0ce29e877a85e29b9601dc7508a060b97a05f37e15 +a6fd0782c5629c824fcd89ac80e81d95b97d8374c82010a1c69f30cef16ffc0f19e5da2d0648d2a36a636071cb4b69a7 +ad35a75fd8832643989d51d94ee6462d729e15f6444ffdf340dfb222af5d2b6b52e5df86082dbc7728fde7c1f28ac6b4 +8e06831cc8a0c34245732ea610ea6aae6d02950299aa071a1b3df43b474e5baee815648784718b63acfd02a6655e8ea7 +994ac097f913a4ce2a65236339fe523888ee43494499c5abf4ac3bce3e4b090f45d9abd750f4142a9f8f800a0115488c +a3e6a8e5e924f3a4f93e43f3f5aafb8b5831ce8169cddde7296c319d8964a0b6322a0aa69e1da1778fcc24b7de9d8b93 +81a9bd04f4c6e75517de4b5e2713f746bd7f3f78a81a2d95adc87ba0e266d1f5e89c9cfb04b5159c1ff813f7968a27a4 +b24de8f3a5b480981c6f29607b257ded665ecd8db73e2a69a32fcf44e926fdc7e6610598e10081cf270d2f879414b1ab +adc1b3f8ed1e7d5a26b0959ffe5afc19e235028b94cb7f364f6e57b6bf7f04742986f923fae9bf3802d163d4d0ebc519 +a9fa5092b6dd0b4e1a338a06900b790abbc25e2f867b9fb319fdcdfb58600315a45a49584c614f0f9f8b844aa59dd785 +b29c06b92b14215e7ef4120562893351ae8bf97cc5c3d64f4ecd0eb365b0e464cf27beec3f3ddac17ed5e725706b6343 +adc0d532ba4c1c033da92ba31aa83c64054de79508d06ee335dcab5cabae204a05e427f6f8c2a556870a8230b4115fd0 +9737150d439e6db2471d51e006891d9687593af4e38ee8e38bfa626abcefa768ca22d39133f865d0a25b8bbf7443d7db +a10d1e6a760f54d26c923c773b963534e5c2c0826c0a7462db2ea2c34d82890f9c58f0150db00aa2679aa0fdb1afcb08 +816947dc6c08ee779e9c2229d73dbfd42c2b3b6749b98ec76dbad017f4b4d4f77b5916600b576691978287208c025d6f +a2dc52b6056219d999f07b11869c254e8b3977113fd9ba1a7f322377a5d20e16c2adf46efb7d8149e94989b3f063334a +8153900aae9cf48ebc7438b75c16f5478960ef9170e251708f0c2457967b7b31521c889b5fe843d2694a07c0e804fa48 +a9e9d8d66c8774972cc1686809ce1fa5f0e16997ef2178b49bcd8654541b5b6e234cb55188f071477ba1cebcf770da45 +b1fa775f9b2a9b05b4b1f0d6ad5635c7d7f4d3af8abaa01e28d32b62684f9921197ba040777711836bc78429bf339977 +b1afbbd522b30e1ae2adf9a22993ab28b72a86a3d68d67b1833115e513632db075d047e21dfe442d6facc7b0a1b856bf +8779b7d22f42845a06ae31ac434e0044f5f9b4e704847fb93943e118e642a8b21265505ad9d6e418405d0cb529e00691 +ab2c6cef1c4e7c410e9e8deb74c84bedeb3c454ae98e3bc228eb13f6b7081b57977b3e849ba66346250e37c86842c10c +908d6c781d7d96aa2048c83e865896c720a66fdec7b06ab4b172192fe82f9ff6167815ffb66549d72bfb540bb35c36c6 +b790440f205ece489e2703d5d1d01ba8921dd237c8814afb5cb521515ed4c3b0a6df45fd4bd65ba63592c2fe1d008df3 +aec346251f9c78336b388c4e9069a1c6c3afbbb6bfaffdad050a9e70e92fb3cae3609067b4903552936f904c804b0ea6 +a0e528cc2cb84b04cc91b4084e53ead4188682a6050b3857c34280899c8233aa8c1a9c6fa4fd6a7087acf1b36d67734a +aa8d7632be3e4340712a1461a0ad0ae90ba6d76e2916511c263f484c6c426939fa93ffbb702cd0341eea404d6ddffebb +a4ea871d8a1d4b925d890aefb9897847599b92e15ce14886b27ce5c879daa9edead26e02ccc33fcf37f40ff0783d4d9e +ab63e4dc0dbdaf2ada03b3733aafe17e719d028b30dc9a7e5783c80933a39935dbe1ef0320bb03f9564cafdf7a4b029b +8219761bbaa39b96b835f9c2b4cec0bf53801f8e4f4a4498d19638be2fa0a193b2c1fbf94e26c1058d90a9ac145a7a12 +a609ee5561828b0f634640c68a98da47cb872b714df7302ef6b24d253211e770acd0aa888802cd378e7fa036d829cd36 +90793ff0736f3c80b5e0c5098b56cda8b0b2bca5032bb153d7b3aa3def277f2fc6cea60ac03edc82e3a9d06aff7d1c56 +8760085283a479d15a72429971a0a5b885609fd61787a40adb3d3d7c139b97497aa6bcb11b08979e2354f1bc4dbf7a0d +b168ede8b9a528c60666057f746530fc52327546872dd03c8903f827d02c8313e58c38791fb46e154d4247ea4b859473 +842c1149ca212736ebe7b6b2cb9a7c3b81ae893393c20a2f1a8c8bfef16d0a473ff865a1c130d90cc3626045f9088100 +b41d0e2c7d55108a8526aa0b951a5c8d7e3734e22fe0a6a2dd25361a5d6dea45c4ab4a71440b582a2f9337940238fe20 +8380bd49677e61123506dd482cdf76a8f1877ea54ed023d1deabfc05846103cfd213de2aef331cdf1baf69cfc6767be9 +a026f92030666b723d937f507e5a40e3f3cfd414ad4b2712db0a7a245a31a46002504974ed8ba9d8e714f37353926a4e +b492e9e9917b29eb04cde0b012df15cbd04f3963d120b63c55dc4369e04f5ac7682b2c7dff8c03410936c26ca73ad34c +81fd9271b4ee36be0ba8f560d191e1b6616dd53c56d1d8deac8c1be7bc67bbc53d434cf70d04e7fa9de3e63415389693 +835c3711abe85683d2344a3ee5f70e68342fd1aec025ad248efe66aab3e3d5790fad2f45bae0d7a53a80998fde45f0aa +b46599be80b8f7dbad0b17808dd5ca91d787929c0bef96fbbcf6c767727d07ed6785bad164d733ecb015eb6c8469a16d +b36bf5c17271d39f5ccb3d82a5e002957207a0cdf9ae7108a4946e6f3ed21a5d353fa940b6fe949c39422b452339bae9 +a12f5444e602d6fb8be51a08b8bc4ec105dfd759d2afe98d51ff4edd673c92e4fc91ff32417ae8070e12169004f8aad3 +892ce3ca0a2961a01f7f0149b8a98fdc0f8871c2d85e76daf7c8aed2a18624b978a4d0a84213f81f9d2a81f7ca4826d0 +b1e6229ebd5b3d85e62d0474d1fed34564f1b5b9c5856fae36164dd0eff378d67d6717dda77536379006fb462bced9da +ac852921dcb81e54e1e315fd6226219932f7b785c2ceb2035710e814899784d7001101f1515d68e3fb74cdbb4baf9e26 +989a42d851123d708a213f3a02cfc926df15af058ec9b5a9df968fe16decbd781b5e65a4c17fbfedd2ac17126084700f +b1d0fc2f7c948e466445f307da7b64b3070057c79c07c7ebbbe6f8ed300a642b3567aed2e5f28988ac566ba62e0d2a79 +83057263b41775bc29f1d59868a05b0f76d3bdf8a13c1014496feb4c0ee379bfd0d4079785252f51fbeb641e47a89b69 +ac9e6a208aa9c557155cf82b389bb4227db5ac4b22a0c7c8d1c3d98946df8b82b0c49d093ba55c8255e024a6d67c14b4 +8294a11cd3f5111b1f8bd135be23b4de337ac45711db9566ebf6e162cd58e7859b1309eba8149b0f0a43e07f62a92411 +8c15f3388b196603c05adec195c1d2cc589e3466da3169e9afd37157fa55cd34bfafbfc5ff10ac0e04aa6a0d0b2ce3db +b8faf8ba89c3115576ab6b340f6cc09edfea8f7331f5a5e8003960c584e839fcecf401113dfbb9a5c11a13721b35c263 +955c63b1166514c02847402d0e92dccfe3c0dee3bc70d2375669afb061594c85651e6569f471a6969759e5f373277da4 +963bd4f9ae7361d6936d209592a07d9a22cc9ef330cf0c5cb845cb4085d76e114aee66d7599bf5b9f11c6b1c05dade8d +85509b3c97e06e0db113b8b40022c8989a305cec39acab36ba3a73a4b4719573e5bdb82dc4795699c26d983465cd61b0 +b870cfd7f691f88db8d1dfbe809b7b402eabd3b3299606b7dfdb7ef49415411f01d2a7e4f7ebd919ac82c7094f628166 +a5533e7b58a6a9e5c25589134f501584163551247d36f50666eeb0a0745cf33e65bb8f7a9c2dc7fe7cb392414f1ece4a +b93d1ade01ff5678fcd5b5b4f06a32b706213748076cae3a375e20a97231133ec37c1c3202cbc4896b66c3410210f446 +86ed3a58000a46fe2c37d4de515430a57d8f54ab4300294685534372fed1d68e192dd43d43ea190accf3dc9b22e1548b +a8c7d8dc30057bb8ad66b9cfda5e223334407730aeb0f51705922c18e7a07d960c470d463d1781899203e1b1ed1df484 +8d86821d006e957e8544f95a98b110c89941bcc6985562e7a97285f5826b35b690963b2c141ff3f389d92ee18ec76d24 +a4e1108cd3cf01810e74dbbf94340487011b80013b9bfdc04f019188c0d4d077a54b71a3f97a036601aad42a268531e8 +a822cd61db07f64bea00de226102f5fc0adf8fa9f05a6c7478b0ff93e48f6cc3191302d22e1f369b571877d5eb96139c +b1ad4094d0bb4c325dfe072b17711962247dd7ff7e4bce4612e80a6f3c1bde04880ba1682f60d5f1451318afd4d3ba60 +88e7beb0cfd7361288ea27f6b2cb18870e621152ff47994440c18d45284d21bad80d9806ed7d9d392a5cd791d5150ce2 +aad3724a176cf4476595cdfb9e2c3261c37052324c0b5373a30b6cbeb481bccd303720840c49a84ddca916d470eb6929 +a57983370d159e7078a273746fb22468000a6448b1a31d277272e35c6f548f97928e9015f1daf577511bd9cfee165237 +a54136e9db381cdd6dfb3fff8bdec427d4dc1072f914f6fecfec13d7b8f95bb3b5f30ad7677288c008ce134edfb039a7 +a25dfc4019f165db552f769f9c8e94fa7dbbf5c54a9b7cde76629cc08808c1039ecbd916560c2b6307696dd9db87d030 +a917d25328b0754d70f36e795fe928e71ae77e93166c5e4788716c1ef431115c966f2aad0ce016f4bacc2649f7466647 +842ce5e4ad7d8d4b8c58430e97ff40a9fce1f1c65ecba75fed2e215e101d1b2d7ab32c18df38dab722c329ab724e8866 +a8eb2ed2986ff937a26a72699eb3b87ef88119179719ff1335f53094c690020123f27e44fc6b09f7a3874bf739b97629 +96753c1f9c226f626122dad6981e9810a3cf3bbee15cfc88e617cfd42753e34593610861be147a7b8966bcdec55bba8d +94119d31606098f5b129931b51b4b42c4e3513a128b9bfb03cfeee78b77b9909b1c2fcf0a292e49d63bc4e5fe823dfef +a869654f5880d9c21a0af1ff4cfa926e03ec1f2d80fe5524605e04f484e09dc80d6769249f31fd378ff3926ab4cebc69 +b2a539bdd8de4499c5f35cd8824974c2abb1933b3f50d0175dd044563ca829eaa0fc47bdac97eafa98434d1cd05d7c5d +85f53b2bfcde1986ce7279f3a2f5f841f87d75af5d197c897f261d4874bc6868c575ecf7556a32b7b33f7b2795454591 +964f087ed02228b30f401d8aea35c1a7f76698e4075e1bb343398be74c716884e9ca1a31b81566e1ff7513cf76a2f0cd +a1c9d9c9bfbc9c4e281a2953d5991e7b22ff1a32ddaace9e8d9a42e080efb802b853d3276973b5189a5745943c9b4389 +b0c45a9852663a427d7f50c608a6419fbd00f90e8452757a45269d25c0386ec29942f48a34aafc0187ef6020e581d290 +aa3ca7b01862d5d2aea714fa06724b7dda7062b6608605cb712588b2c49fc3c7d89a8799e6e7c31e7a9ef28b1ad4d1f7 +88f5e98ae8c5ae7add42f6d358a35667e590aa80e1869593cbf597d7ee466efa35b429f1836ba2199d8280fe7f60ce3a +8a3bff472e8008f7e50362acc1a0b53c09ac60430942544532722e938470376f0672662261992146765b7c75a380c318 +b9847be7f7aee7532282c279dde928698a892a183ca3047ceda521e9e0a50d96fd3ce59f8e58f31af49508ade6d4ba51 +98065dc23ea3df6d9f8459e81887d88d5752b7e7ba6050ec5c3f0dce93e463e0bf12be3c94ec74c16e2f7ba62e447845 +994aff677b97ee790894dbdb21b1f9210734e008cee2aa2200c8f2579ea650b872f39776a13a8c31e95cc817091bae1c +b292811674e18912ebe79df1af4a132b04ab702c125c039e0213f735f658fafd36c38e5bbd7cad35842576431f5f3630 +96520d750ec10bb10f75019f8f0e4a93ecbc6b678a710d76cd10aa27a6642ad1461bd58fc2aab8e0391b3f788339ed29 +80d478da7fe246ad0e81a00141229e9d91ffb7fd1b29975c8ec358ed5e864e481bf01b927a9ba002c5ec4aa226d0cb57 +ae58049d93a11ae845dc5be2505e95657f83b95d83ff3591a3c565d587157be795ff4481f42d59eda95e6d523444e199 +85f1f5ad988b9f8a7e24b6d6a22b9de9fb3fe408f95711389c444d7ba2243987225b04318aa97a4cde2cb4c30c05508f +922092d0cb828e764ce62f86cbc55c04dce07233cff041888fae48cfe93818780b4aec9b4ff4718275bb2bfa6bd9e9ba +a85ba97125feff0590a05fb78f19a7338639ad1748802918af4d59307bc994536c0ad638b97b9acd26a08b6b4370dfbf +8c46fcaa8d13266d650bd9366180e5ebbfa002c339e4424a030de19ed922e2daa9a353ae54921a42299607ae53feb075 +b8549832230eb1ec6ee3c33c078deb47f556a0907d2a85fde7720391c82d2ed63dd753cf544a6a0a46eed4b8d1ecd9b8 +b7b96f24504c7f8fbed9c1c654a2550feeee068407b809c43f1082c9558c8665806d911d5d244308169d8a531373bf56 +81c483fd9d9ad7af7869d617ac592e7e951e39738da041d8c4110637689108eb29c8acadfc85366c70885cdf77b353c3 +acf33bcfd9080dfdba828727fe36803327a94e8a3ee5b6e445274f0e8267ad3c943994a8dd6d09b8072912b57e1e25b8 +b3475e7456ff96861bc11068198d51b69b899f5ff13022694b501d3adc8bac58a16204b12011d61e880c8459f4badbbb +8ceb9562026aa96d6e786ec2e5cd49200b5b424349a2214cd3ff5c8f1c2bf1b9872480428f5428e45cc61106cbfbd953 +af56f7e482c24a1367fd798201a20c464848ece431f2d8a31a6ef4f9bdbaa50991e748dcb4ef0c08fdac0ef8ddda3b80 +896dae8b12549909d512fd5c02a2f72dde4086aef6c8007ddb26bb04dff51a707ae94ff87e45191fc10339967fa28958 +8ed1c606840e07a2ac6ff16ac6e81ed3e1c90872ababfe68d56ed2dc50d9294579b9c3546dc63292874299a3162d59f9 +b4d7a5c0836e419a46942281ce77d0aade8e39eb1bf1190dd274ca5070898a1c02ad9d165855629d6e1c96df1a6bd5f3 +aebad8939ac117deb28b789d9846c2c80359dc260920ac8408dbae0b6228dbf496dac0023a3b4302bb9a53e8ada18e61 +812d07c74a8650dc3f318c9b2dbf265f181041fb432fee989cedabd44b933dc6590e36c71dcf9dbe7b4bbf74ea0d7c50 +87b131dd3489889e090839c392231e0ee198acac65bb2e9e63e7d6da322391d1685cfc8ba60699308054c4b0fd89c90c +8b12110ece0b99b2e653b4bc840a12bce5b85abf6fb953a2b23483b15b732a0068824f25fcaa100900e742886c7b4a0d +8765fc9b526a98512e5264c877bdca567e32fdcde95cdbcf4f4c88ce8501e1c7fab755f80b87b9b32d86d18856f1d005 +ac806a32a14019337dfdb5f781ecba5cdea8fb69b23e0e57a0f885e0082a9c330ba808621a48e24316604f6c6c550991 +a711970fa40cf067c73e3edee9a111bf00cd927112205e9d36a21897529be9a051be45c336d6b56725dca3aeea0aed15 +908adbc17fc18821f217d46c25656de811d4473779a41eacd70d2a0d7dd3010de4268a562378814e619e13ac594bb0c3 +894251b79be5ae763f44853f6999289b3a9abda64d52797c6c7d6d31ff2a79e9b3906da72f9ebb95b61d6b29479e076f +aadcf11ea15bcb6d979c3ea320cff8dfcc23c5118ed075f35e77f71459b2141253060e3a90839adbcd3d040ad3bdc5e2 +b4e55d7d2eeaaffb0267448ecce0b75166e4805dc0e261eb5634d4a3f3c08964a597302fd8f6b45ec48178619291dadc +a8e2a02c93d6bec7f42f9265269660b4b404940c3e3de9515b4d826ea7e71f18c6f90a71ce3fbe452d0713de73cb391e +8e2467accfe207cb1ba37d60662920f95338ee212927edb706228c25345734217740159310edf17687f58b333754cb65 +90376b88f653381b3bab673c48c2b84fa82a091e18f710a732fef836e0d39043fcd5527aa97a3a385c0a77cf53746993 +b16530e289198c235ab680f86851bcc177f0c16a58483d83a89213077b06d6840600b03834b6b7af0e22b1914f72de43 +8c4fc3854f938ef1c2b5df065e4e75e9f299798afae8205706439491bdf9784c756134922e77af007e349a790afa52b7 +a68aaec4341d29b92b35322f89b1ae3612e7b440c89a86135a07c261dc5799217a651460c92113d099b486817226d8cd +a653f965feefd2df24156478f0cf3755274ca395afb79e8c72d3b6e1d1f5ba7f3e4f9a4c5ee85355de6f3c81935ff579 +aaf6c8d2717b57f6b14e06c742a11a3bc736bfc0327ca4b8a005b6e924f06871141d231737698a9a59286e44f244a168 +8de32e3c104b4278e27aac695d224f134001c3619f15186466c57c0c46f67e2efe537501d0d9f52f4cdbc724a170b92d +8e9b5858b6d4ffe811f6498bd80e454f0d6b345d4729c946626c7cdc196c803a349a14515296aadb7258bb7a5b37e930 +82fc711043aaf1d7a9c712d00eafd816a710f82eb10818ba6af09f591447f36814dbff6e6a1cb2b5c7f16c73930dbbca +b2f0205327fc8ff687f751e7b97788732afaef4fcf51bb17fd7579ed07501915790b70fc36624371fe4fb87a0179d850 +add87d5b1288d30f3449d3ccfa11cba4dc7756d85cee1cb6171b493680a625a01f273d0bb8e6332d0410250036b3acdd +a411f75ef7dd8de8062331ea40929db989e4d65ae8f33d3fa6cc19c98fa8a8ec2b7c7534a5c5eee9e5051626a6a2e47c +89d40a647781e7f2e8ab3a0f7dc7133669944c0cf627376433687a2ea15c137be26f582a6b07ff94b266ac0910009f7c +b2b5f808c26b40ed507922ed119b0fb95e0d6d8b084bbbba58ca456b4354d03110c99989b93207998334ea5d1b70fe49 +8c8db028671969a1e80e595283ce5e678ee955d785043bb5fd39fdb68a00e4c15b462600a7ab1f41486b6883e725894e +958087ce0c75fe77b71770c2f645ef3360c1a9c98637693b988c5f6ce731f72b24ab8b734e8eb6258ee8b23914451f0d +aad6c00df131c1eec6c556bae642e6dcc031e70f63eee18682f711c7b2fcd9afbf1f18cf8a4af562759130add67bd4a3 +b6d23c567291f019cd9008e727704e7e6679b274feb29abba0d92e036f349b1f0fa8c5271ec7384e8d70a2c3977b1f8a +a942c770e903d4150b5684e4b94bb72d0e171df2c7cae6f46e002c41c6b04d774ac6e2753ba8dccdbba3ad1e297a9ae5 +aa542d1849390f86d797408ed7f6a31504aa65d583481a00e475028af20f8b69248a87a8ffab1dace0377db77fe5f9b2 +a1ed3f9564a97f7cabe7c67e018eaeaa42db73a2f3d2332041ca9a7bea57436d848784d6dc402862c22a47f0692b1286 +925c757750c91db8b1b3c220fcbdd80742b4a060abfb0a402071d215c780ef6b420132ec5a43043b9fd7a06bf1b323db +94e575daa7fa0bbb35b4386f510fc3877c9df57bcf15349c5923f30ad6a8df95372835cc078216b41a7192921c1e8973 +9346a41174865d9ab31c7fb9a5329f322bfce06002386d3f5a2e2193de9bfff12bd0bd93307928f7b85e1097b2aaddff +a6e54c9324baa1bff7e9bf39c94fdd308ec6f210aad937112ec727565f8a6141375c04196831873bf506294854f6a20e +98d47b662504f400f1a0e14e24b43829490d022ade02a56288aaf148d466b45d89b5fc146cef67c9ba548cd37ad5e354 +ab690dd59a69904b6b3a4d5a42d17ea4898d9b00c6753aec216d5d4ea564f9a1642697df44d5a62f2c2ab19aaabf1532 +8d0aa8d3c5ec944af49beb99e403cc0d6d1adc6003b960075358a4ff1cbfa02a83d6cb4d848d9e83b34882446a330883 +af9334b7300780c752f32eaa68f3dcecd07dc50d265083f37f9800b02c2595ba24dab89f5fc27c1ecfdbf5291b4d77bc +81c4a6aaf7d4ccee9925c512dae5da6d916a6dd59f7a4cc79d216a91201b4d300114a309e3ddb3291bb95f85bec2a8ea +8c804e810c0785789de26e12b1beff56a163769733be7a31f34f81093782d6410293768a166c9191ef8636fc8724a31e +a91222b48de238f6dfe79c84080cee618611bd0bdca15cfe44474829e42481f8511a82589e69964e19f8cba04e3f5f3f +b26a8885aa594b0c8ad4a1711d80bcf687df996442075dd1497db1b446d16c74e28bc6f0e92b2ecea9c3e15c9c7e828a +85940f45d324ad1d335bd1d7d6f81758f52213e63d5770d9fe0c0c9507d5550795e538b6a2dd463f73d789b5ce377aed +931a277c78082f416880620df3aeb6d0bff2103d19679dd092ea981f5323e438c50a0d094908034ff8a2cb47b1a44108 +88dd85e4e2aa349a757b98661fc00d4538ec1d3f53daf44b16ffcf7f943dd4f2bba5b8ba3b05c529251dfeed73f6f1e9 +b7fd7182cd33639710b8216c54a11bb02e199bbc54fe33492a809dbe17771a685d6238ea3ebcfc75e3b0d4ea5369bc9f +85d77194d910f8cdad7330e1bca9087529a40fece17492f1d17cc4790833891b6d01d24f036b6422175c732b438faeb5 +9845265892d672d9517fbd22f88be4f225711b4abafa8327cc059f000656e4737188506051565d97912a0c19c3d063c0 +90a81987aa841c7f640c298b816643a0ae00cd3609c3a31d0b01245283cc785d9bb27763131b31a4f21aeda4e50073e8 +8b1256eb41a600bda8a06ac08b98a220ebfd52f89a0e4fdce32425db7a0481e9b7873ba3b7a24ad9fb782ee217dfdbf6 +870548998deed85c59507cec7e69cc001c279bb2a99c45a4d030a35c107e69feb76afecb9e435e67965051d6d7a88220 +b1504d194a0dd8df48d431ce991f89d7a0f72f573d21bd5bb46474c5005e43820877a44e62db555f194427ac8a4b9168 +a00d7423ec2cf0c9e9da07f3dae092d09e1ff4be852e07e531aa54d62ad937bfb52c8bf44683ac3a70f6dfc125575da1 +8019625ad3d218018803aacc2efcedba3a41c24aca8c5aab2005556e58fdf2ed614831277df7937aa594e97a2fc65e7d +8595596284f3add0155ecfee3fc0b66a6b6fc7923d82ca8302952e2ed906d119a1c053aed1123b51f73e1d30d93aba57 +a8ba033f5e7d06177e9ae2d99c40ed4e99e14e1c1b61795997f62e21ed8af1531c4720f23d6a39b0f75c6cd91c58c700 +a94f4167c0f6ae214bae75dd92c63299dd954b00b0d8b0416b8af929fe5aec6a259e44f83a183412d7ba4eb3a49728c0 +a73ee3c3a0fd2a369e0a279c3e214fb662d0378eea3c95cfb91412d7213a1f05958bd0de8f2a4f80f9f80d7eef943b41 +8ef6f3e241f6a761c9ab412629a49648c08b70b837c2cd8bea620bc93056ec73754e3e11f0df50f8e9fa67a9867501a9 +80b473ac4ba8cb82b4ae684206cde124d10fcf619f55a6c90d035981e1b08b9e141b4e5fa9a9af0b7f0c281b355dd593 +a566e2be0b41f01978dfffbb32f442b5e6706f5b9901110e645cf390f6a82869e3ca16887ffa35782a004d251d29c26e +a74e01eefa03546d00afdd24bf17015eee95d36de28c03c9b055e062cd5e8d8f20473c6d7ad21c94f9058fc5e84f9628 +acefc74de146911275dfd19bbe43d72729e89e96da04aff58e5fcb90962856c0b24eb13f43e30329f5477a1b65ae9400 +b5f113ef36e75de6d6d44130f38e460ad3ffc65cb9a5606828c4f7617981fecf76f5e862d7626ccb117aa757cc3c3e52 +96d3aeb1d3a66b136244062b891fc7f93ce745b776478d361a375ae57bdba9b4fcb257becbae228c1a3aff4a1c4fb5e2 +ab26c4a110877e5495b674569a32025dad599637b5dafedcfe32f205dfa68cd46f3ddf4f132a8e5765883b5c83214a07 +922a7a738066692193af32ccbab74edef067668ce3253e18a3275afcd5a6df7168deb2f5175c5fb413dc08fdaef63b17 +a47542f8e4a3a35ef6049280d1a9442c920887d5f1a1483149e143ca412318495a36decb804f81c9f5a7672a14965a4c +8fde57991e72a2aebd3376b4d9fdd795943ba3833431e52b136683567e6ee2cc1c1847dc49dc9534983060c54bf22f7e +addb041f01a99e7238ab2f9f2f94579861d0470b93b91cfb29f3a2e4c82386c868b2cfb6f3778b8a9cf908788acafe58 +a8c4e1df726431c43703739776e2cc51f5ebac57051244991baf53582538120133a44ca603d0722a4b5193e1be3c5ec0 +846379125968d1154376c5dc63100bdcd99b9403d182e3566fe48d79099099f51523cd81d21f0d1dcd622b715bdd851a +b828bf0d936d275abb40e3d73ef57fcd7ce97e9af35e194ae61463317bac6c1b0c3e4b40afe08a1061037bb7149108fc +abd07c71754973e698fa26c5019afd9551548f8369e2249b9902513f19a097057ee7065a1d88912e8f52e6e0fbfa6d82 +a9e36b6fcc9a3cc98e76d5751c76c50e1f92b7670f8076ab6ca8a30de4ec14c34669e049fd39bd293cde8789b1ca67f0 +8c060835496a04c7b51790790035862b20547e62fa8bb4e8857fb36891ec6309520af5c0f45d5ea46e3d228747d710a4 +8cc472ec62b8dce244373f40a821db585628989b6a7c4d394edffbc6346c8be455f4528d528fff41f91f2c875bd9fc0f +b4a75571f84f93451f15b3a86479063d7324d2789b6d2f2f4f8af68c66fac32743dc09b51df29608d62aaba78f6904af +916484984743b5ac16d40d0544faf9184819d92f779254b7fb892eb68cefbe59e75be8a6336a585e120f6ccae0a1eeac +b906ae585a73119764024e9eb87d92e53ee0c673474fec43fec4d344a3bbf471ce3976d25e37d197604689bbc944f1ab +8552708487305f16f95db3e01fbbfb969398f5b6d116844cbb000c9befd03f15c767584bf9541a42141949a4dc787a3a +a6025a2773f78c247f78c0d895ade8a6baa76e5499085f6175935d98a05fc41c1359f7843e0c6c323f1be256c45f45e6 +96dac695dd9288aeb6e32dce50e51ddf1fbd41de6146e3605c7a81f2253b17babf2bfda4f5a9d0c28352b9746c0dfa2c +a215b21f8eb2290f9d308278f2859a999eb3a31f4888f84a65f9ed05e1151c17777f91054d4d0de759ac5c3547d91929 +8fd7c9a279e9b619acf927d501b35dc551979731a89eab91d38b2356c0d73569baddacb9d1096d20a75c917ecaedadd6 +b985e8baa5195e2f1ea1091122d55aa321178d597f87b732b23eccb12b891638be1a992305a1ffcf5233af34339fa02c +ae1a9604b7f569aa48d2daa1889e76d3d103065fc8c3deb9ae127a6d94145695cab3bef640fa781612e8082c6d616c47 +a8fc67f9069f753360349eb874fa4dcadb2ec48d97c61abe568faee5f370ec3c87786c7faf0f73fc0ae7181a36eb89ca +a506d13acc3a9f80509fac936aef848cd30698631fff6130ed6217512ed9527d075f653cf6ef91f68e48a24c903eeb3a +a415093755cc012863043bf586b970bafdd87653ad14d1929672e04949bae4a753d16aa3eb5bd1afe3df3691b80f240f +ace3b792a1960580348b6fae8513149242378a18382741bbc2fb2f785cb8bf87550da4b5e0df2955970ab3a31f99f5d7 +a47d7fa7522664c8f9c404c18102f6f13a1db33ba8b0a56faa31a78a3decba3168c68f410115c5d9f240b3dc046dc9b4 +a9c930db3ea948cd2dd6ea9d0f9a465a5018bbaf6e9958013f151f89a3040cc03ae0b8eaf74b0ff96b4e7a6cd8aa5b4f +88abd235e3e760166cdedff4be82cf6ba02d68f51c6d53b1de326769f1f635215890f9a4c35b06dd16a9b93f30f3a471 +8f8d7b2fcdb70bfedde1ffd7f0b94108f0fa432f6ae81097988521dd2c4da928c10c5da3c7f33f11bd5331f2da8ec219 +b7abdbd48cece30d8f795a58a94913d76842cb006892485a9382a0502826538ca4ff951cc1ef4493e45de8571360d20d +b3e7b125f350c52695f7c5ec4a30916ea6c11744f1151a18ea0510e6cf6ed6f6dba4beaa4ca56988d306bd80ec360056 +9a004423c95e1f1714f98fb97ab798d6ab16cb5f6d6cad860635585d4d4b43ffcda63d8e931351189275e5a2cef28c2f +a8eab6ef917cacdc9b1932eb312309e1f85298d63e55ed9c89ab79da99d3eb60f1643d16be920e82d9285f60c7f7cab3 +934df955485113d10c4dde476ec14a98771145aadf3c8b61af26b09b9948757fa1abcc945ac91466a18c18c2fdce40d0 +99ed9146561597cff8add2196ff3a0f161dd5302685ceb846afca6efb5225f642e8f4a0970eecb01cdf18694fa697095 +b37062dd12a81267bbbf89bc9d6e30784c0e11e713cc49c6c96440f800f2a6a2a7e7f6c7f6c9eed4bc3c8890f2787342 +83a3d70055b6044e0207b3ece4da849755ab5798317b36b20c3555a392c27982f811e1c5007697554eeedc737b37f3ef +a85392c07ff8658935fbc52acec7221cd916c5fde8537a8444eefd507220e76f600350ae8f5dc3353911087b88b91045 +b1ea23558ad805dde9cc1eade995cd8e7f46d9afa230908b5fbaaa09f48547f49c2bd277bff8ab176f1c240beedd2b09 +8a16a48b9105d94700e8e5706b8d8a1ed14cffda5558a596974ea3191c5c3449da6e7efe2059e7baf4530a15f175ce16 +ac5fa54381fc565842417558e131df26e9505027759416165035357816a7e1859a7c14c228c79b4e5ba2ef6758e12ad8 +8475e290c399cc9322c05264a516cf766bf5fdb6b9dec7283961da0b99012d499b244b33fc0eaf94b461ab777f2a9537 +a7922f3c70e6857652805af7d435646c66d94eec174be997c4fe973d8f019990c4f757eeb730b2cfdf8154e6e97f7d5b +b90deb797fba3150cf265a23ea6bd49a382855cd4efe171cbcb1664683a9f1687cfcadfdca4e39cd971ec13aa5cdc296 +91ca761dd9659007d2fe8970bbd336c19ed0d2845d0d8aaab397116affcc793de2da73d89e6625cf4dae5983cceffa56 +9121ae9b60323ab1301e97555bcc74ddba0f5b1e62bfe9eaa2c239e1d685c4a614d397b32a59febed4db9968db44f38a +8477b07da4bbfe9087975f30d2c2333fccfcd7149f90e0e6fabecee627eee3ea324df31cf6a680393f5dedf68a35c9de +946a9c0f02fa6bf9f9d4933e7fc691749f4ac2f82a9b880666b5185189d4f3432da9096d0ea4d6baacbc079e19c887ce +b24663332914ea519435874d4c42d11842ea84dd3dc55292d5b0f27f64587848d095bacaec235a37003bdb5185daa6f2 +b980f46f84ac21dea75b4650f9412f6123325842758589a9b47caa68545905061f03fcad23cc102e2ce8ffeb1ae634a8 +90e9ebb060182d3043ea4210a2d934858559522a19eab9f0ff81a367484a05ec7cce78ee6a91dfff96145869db6a4e80 +b04228a009c91847693eab29c9ea71d1d6ba07060bc2b0b3bb81c46a125baecb3e1412f6ce4305076a97d316d14e4665 +8d3268370dbf38d378c7228c7b54e91f90f43cbfddc0d8468de11a4312616ca6372619209b89114152b16f334f4d2780 +964a63ffae653e0249685e227d937937b079ec3da9c977dad2b2e052af5eb560ce7d175941f2ae0df90e3d0a20b77e75 +855604c2910be885b14b27896e16d8dc339236b975398c771d29ac74e4278a2305fcf85203050a8faffddf64ea19cf78 +8e0b1d61a4349411eec77cf3490555843187a25a93e1f45bf66ad3982b9cc141b07805f8cb252b0fcc125e0052a7c450 +a03bc9588f971a1257cd0cfd2ca406c76aaeb634001864b0e4dda91e009d3361b33fc39f34922835031a423a13619a82 +b703fa855c2c4e1641d2687717fe8c5061acab71cd2dab55cdb069a6865464c3080f7936ddfd320516b6791b36c64b8c +aad1cfa7295e463fc3d5374ea4b952020010d67a77c7a86fe2c351a5959cd50df6a0045ad588257567a99bfd0e9400b3 +97906fb82abf5c1d9be8f72add8e6f175a6a5a4300b40295cb5ec8527cc7ec700fa03a7a494122d9605d212457452e41 +a83366cf93ad9a07f617e4002a10b624270f60083559b045ab5a805aaa592ac37b90c1e8b5437158f3bd942cf33bb633 +a585168e157e111bfa329d0ed6651a96509b20b30f6bb0691c6a5875d134d4a284867ab52511cdc19e360d10638e58a1 +b17d480a0b39f2487b7f3878714658fda82f2147c5ecbccd4004eb92d267c4663b42c93bafb95ce24e2f2f0a9ea14b8f +9362297a1a3951d92db4fd8ea6b48c403d6d8d2f7e7b6310b9cf9b4e4ba9e84cfe1ae025830aab9466c32fd659144474 +b1a62fbadfd4ea4909d8d0714c1e3ee9f95237fde20720f88d5ad25c274a6792158b99966d7b93151f769c832b6a132b +8d9af736949a33fe929548abe72384281365385862821a584f5198eed63bc5388f89fc574cda35a9eaabed0d336b86b6 +90ee2235f4ec2c6089b5cb7b8a41c9bc39e4a57935022ef28bed490e2ab12680922af7395bda4f708809e2bfc62192c9 +91f3a123d420bca34d3d751119bbebc435630c6605fb59a8d80d16a4895972e56cfe4cf1998e0a527c18ee38c2796617 +a2c4fbb20e7fbaae103b86ca9d8dbc2828e6bf33d1d7ce153bd98e8880fe7ac62abbf7059194b1eee64f4526a36c63a9 +91a7f93310ac74f385f11509f4bea9a4d74f2ce91cf2024fee32a4a44d5e636a73339c6b4027ee4d014a24b90de41ecb +914a6d405fee0a15e99704efb93fd240105572335f418d95e1f2de9afeb97f5f4b80aaf20bd5bf150b9da9abc2b6d6a5 +9462cf2c7e57e224389269b9fdddc593b31e1b72ab5389346aa9759fad5d218039a4a5bc496f4bf7982481bc0086292a +b7596132d972e15dc24f2cd0cf55ee4a6cc3f5a0e66dff33021a95e5a742889e811afd1dc0cd465cee6336ad96f25162 +99409bba2548f4ece04751308f815ecee71222869d8548fa142788fb19df5366d093a5131e57560237471bbd5279bbe5 +8e7560988a844b5b844ad460b19c452a5a04346d8c51ca20d3b144a3670ecc60c064b2415c2eeebf140d6ae4ba5c5360 +8cd9e18d311e178e00eb81ca839cfaa8e64e50a197de8461f07135fca28c1d895dd9c2401b923a4175ff711853497317 +91ebf99c95e8f653402b3079ecbd533ed7cd3b6c857a710142354ce8330cebdee7cf0fd0400417883b66055bec9d0552 +a9d0cf8cc6bbdc44426dcb716df667826426b4559056d73738bf3eaa6df373403861b6bbd6fa0454b1d2730e3b0015c4 +928320b452ef21d2443dee360110550f531d7a4275b2cb227814150f3e9e360e05a884d6e3bc4415f202120ea5ac333e +b9551f2b2e7bb984618f2e7467e33b5b5303b8707f503f2e696e49c2990ea760c31e0944d52257c7a38b553a67cf621c +b2ec34126fe61345e5c6361fe55b8fb3218cdcc9103bba5b200252d50b758153cd549226b7aabedd265906401e755190 +a8cf814926082a96a921d471036a9919a58e68d02ee671c215ea304759cd92a7c2c9ccebdd5e9ec5572164ad2abb22ad +8c0563c28c261bbe9a1ec4986f8b277324bf05b4fe5e2b79a862168e646bbea50ce7c4622b2aa7ca899c1a728c226d24 +b558cdc334ea894d3a13347ea9e30f78a0a20621903d6c009c54feceba3ba81d2445a43572e088ae691f65489702e963 +a62ba0b20f46c367cfd409beb300e39f1a6cd5be95e63457b6ad3cb66374aed754fd037b8e4215d651a7d8e1a442f762 +8543e2c6135df471bd7a5c09f1313674c7f6847cb88f15eabf40b2bc9535d0ec606725b97103334a0c162a20d9f5bb53 +8c0367d7058d63b425450f8ee9252e64234c0c2e61878c7c2d4b17bab22a72f40c75ac3bf8b64f264c00d9c5963af041 +acb7207445993d563f1b6e7b179bbd6e87044399f80e6d15980acf7aaccb9d85071fecb22250afb3aba850712fbda240 +b93725e66184bb03f0ab4078c737a7fb2b10294a3a09995958de3dcf5316b476ce9b5cd8d180017196d9482abdfcab88 +afcb52bb7b8f45a945299da6fc6a877ba9f69f7f23d5f94b5f5d9a04c3cf3089333bbd50fc305e3907825003da73b9f6 +961de781cb238cef52d43bc0dc7d8e3a75bca4c27ab37a2e9353137a9aa9403444a5841b595adeca75a3de5485ab97f6 +9408c828d3ed6df40cc167d72ca9882a9c9cf8e765d6f9125e02e0d66ee0ac94f449803afb50bf1b92176feae92473d6 +a85480591e7e033b9087fd0efe5cf3c88c10a75de4a5d7da4443df1cc1fa1aa59b6cde3ce7453fcabe555495e49ef6f7 +a2611bd82344bc5d70d7e6cf3f0d25866b9f709ac4bf6f75d1006da2a11e2cd07a4c0ac71505e5062a04f71db7a3063b +ac466aaa96febb5b810ba350c7a874797ce4bd6c9585f6b9d114d646894a67c9af9526ade4f7ec834d3a69e18ab643af +b73fc98a79fe77cdbc524c76a09cb9f2d5f8b0a5508846bed1ba5ea9ae3bb62120e01d3b8fb544d90ac9ae0c3d4ccefe +aed333c3403adc899a870082f70aadc770c9f880dc057f05a46d7400be9d893354121a0a31e5475898f437bf722eefcf +97f02133c72187178a8c48db26031f0b2c0317a6648d2be5f7450f00c37391cec935bea46b8144ec9fea5327ee959f27 +940b582b41f1d0f09f0c5f51bab471e4eb143e91b1e96dde83e94650421d51f9c9baec10cc802fb83cd63b56d0b907c0 +b1286a55a74a88a75da47671994916be428be1ca3f42783e497d6478eaa6aca69d50a421b210e9ed3283d578b651b8cf +97cd4e87e21c71d11f1df1c0b6518c00e1610661be4b13cdbdbb026d60fc3f4a2b8549326a648b3fdecb7de8f6aa9fb7 +8f36bbcccee986c35328633bf6ee8f70b5dbf42d0f677c0f4e009d2289976e512af6af91a6ddcd87dc0df93bc4ecd02d +9253ad44ad182e67ab574d718733a69c05cd5bcc43e6292ef0519a9430460aa6a233fe26269da7298ea88cf406e733c0 +b616b5ea74db0dcf8f10a2db79df6ec3566c06410f68a933eff150194608c591b2b175908d4b4ccaef1018b0fefc5693 +80a712ba89394381cbb83fedcaae914cc4f21ab024b8da8a7bbad7762a22f82940451427b1a3f5d84c246d5ba0c7ccc7 +a806909a5517a970879143ad789c6cb6256b82553b649f6865cdafbbc050b1f86528241b3cb600e784186e1a672b588f +b6ae801d1f0e4adf3ce57659d7c61f94abd3c8d1635ad28133a79eff0586fc48bdc195615335449e9bfee39e8a955eb2 +b8a000561211844bef72adf3413f3b438a8789fcddf6676402ca6a1c2c63b9deed322030de2ae3a0aeb3cedbb89406c3 +8bc3615b28e33fc24a7c989f8b4f719c914c4c65b35ad3d4cf15e2196e37c62e42ca34e8b1275e0f32589b969bdfc21b +b2f9637f370a79e7591e5056dac004f56b375f33645ae9f5a192cc6b7b6b3d8a1105cc00f10d8bc8ef250ecc2ac63c39 +b51899978b9c5b737999fee1935a5b0944261e7005bea411b5903d2c16ea045a3b0bcd69395b6733752caed43bc4e343 +873c71a01009dddb9885c48658f83aa6320e74bc152e09de8b631c763c2b4e2e8cbac921418a0d9085ff5c53a2b52d39 +96470f48efd7d2ac2daea8753ef097c09c6fc128a54cc7ef758ff07e32c0b0ac7d122f97b53e88a29cc26874dfee5e0d +8dd2decbd3504b7961d65edb8d51b96377f4edd2e0d2cd8a4d98333f373c79a8d7ca8f8408718d0e7b5e48255857c339 +b536ae387bdd0f6e40850c71fcaecb1051b2c8f7bf5cf92c6bda030de72a03e9212d00390c53a72a08e9fb2bff1249c0 +b1566076f59064e3545adef74fd1acadc1bee0ae23543c30caf9e1ad1fc20ebe84ee25004c612525b26857253f5345b7 +afd180e25444cb720342923b8897d38a6537bc33a0ca1fc9c6e4d524b280193618f19e2bcfbd07606b78b734fe6114ed +89b2a6c8811e5a6d07aa74c79dd854bdfc292cc104b525bc37e4c7c1f9485e19d759c8e27cd7cd73c46346f56ce3b189 +8234196e196898b2501b79d0dc016f6df3d5878952cdb8a93735e4ce2ecf77d07924c701e084533a20f0c50a7d1ee376 +adea7ce2efc77711f50138691ef1a2b946aaba08e7e3b21378708dd5a10bae933ed121e71834b43b14e2ea30a7b306e8 +a566d406a35fae703b3d1ea1791d9207116002e5ee008d01e053a1ea4fe5af2feb63605b011ae6a14414028aa054b861 +b83bbb063682386456719179b6f6bbc8cf6f791229600b7d402167737492f99437b45886695b26a28731e952e56f1ee1 +a8f5fffc2c335d3ad5c7593e81f0862351413cc348392afa86d50921dabb929a5a1de20d604666af9e17a13bbc30bc3b +8d5dcdc1335f01847f6ef650ff64b26e7c4cecb934a7bbce11254e8ced9fa9e4fc87eec55248f69bf499180101c63f5a +83fec30b8bc62f9fc28301a03ef18158d6364738f1c42de311bbfba2e62b25d4c9ea9d6097698b24c84fff956a6748b9 +96394fbe0c2d03cdaa56e13326aeb62344238ad3043ee2fb4f18ebf0a6f7f090f410032a2d15bfbeca9449202d59f2a0 +94880f5928fe71a797362a37d05849d23e118742697f75bc87173a777e7b9d4383b8796a8a2bbee27fb781f363301dfe +af229535896ab86fdf6d2ae676a0dbf44f868f6c7f17bd9a65567631c7aa2e29758f41de050ca5311bd1528bcc811532 +8d4fa4968575b483b3ac16345e7f1ea3f81e8dad72c945a48b7b982054fe1030584be2f89b2f53af84d2490cda551b84 +8052aeb115e4d242078c8726d376a13156cc832705243f14adaa3ef3889e1f2fcdfd46e087acab6fa85a74afde5f5eef +a1349c8a22788a1937a837fceecfaada9e93a63e582a09c56b53da52c9db1600254dc85f63f5eadfa30b89b31dcbdb30 +a10178cdb263ff1a5e0cc034b6deaa160d00c3c3fe1fd1ff0c55fdf1ecb83d771070c10930f88832b75fef39a10024ea +938b17e4405934ea5ef29c2187d6787c5ff5d8c9a02665efb453117d462dbc50ef2c202cbc884305cd807a70b5cc177b +84f01f0da6b58c71788616be71fb3c259ceea7f8bd131a5661c5c03d0205feaff6dac2915919347b0559c381477b3d89 +98787f0a2fac2b04bb7aa247ac77236bbe690aae64203e553be328a2c3bffb772e7a0244e585d27558cc64b089a5ee11 +a14501d8b6b3a84b13b9006d521667e8d168f642ebf154c4e90ec8c75d11985fd0c9d86fc2efa6c7077dafecfdf0ab13 +8215dee75eed04de83a3e910129bee8c48ce01cf1317ea477ff35c09a6f9e9771a8b05aa79e6b0f3e71b9874695e7a2a +85763c3072c7400a2c5668ef5cc53e6f4b8dff474146028a8be370ca9d8af9bf9ee10cd7d23d33eb6d6e257dd3af38d6 +91bf62245c5a59d514d39bfb74db7f72ca7160c1c5d5be3844fff37e53e99d451e18a6747c65e33f98f48a55f38962c6 +8c68817c6a6ea348d9aedce99929371c440fbad72718c2d239ffcaebb26ecc8a4e8c38c2819d945fdb7f02ffda70a5e0 +a96ce2745866a22267a49faa7ea00ebf009ea8d0b0ca2c233c62759b9d5514306b5822dd2eee0124c9e28380e2f97aa4 +8b18d5757c73843dcd55f0f0dc894bcd17e0ecf4c9fd901eacd38480844a15b4ce5e9598ccee039f9d93185137630cdb +a5b45c403b6735aaae14389bcee23ca10571f5437f1f5ab0c2b4e573dfd3341c638fff2cc780166af96b118d47ff2299 +ac849a0ccd354dd46bf55ea837d509b4ae3eefcbd5b8eb2582d301fd56c27b89950c6eefdd4e98e608ef4a6b75251311 +89f13ac14bb064e9c6b49a482831ecea6344faec490bd18bb44028b83a0f22e21145861558029bd172ba7c5247c2cba7 +aa57b057a2ac32c101e442c33831630c81b2e061a542e3e1d6897b2b7ca8a7241ef717a548b3f751d60d89be384ba5da +8a43db4e12682b98230364f25c75b49002f5002bd72a1674cf2a9d53197b5ef1b95e48429af98af503b0d5c3e0e017b2 +a10cd7b8e1574d78c4e917cf833d3d845b878e8e8b60312e6a994bd4f391a5e8c38dcd774087b93c9241238f43f80937 +8b61ccb949088286216cd628811df1a362a7f5c333654ce823e63ebd04b069d5b0f627fb6c96d54c7b853de8aab05472 +887b902020ad45f70f2d5bcfa7324fcbe7be09fd2b1bd40f9ae43a89d487986e89867aee0945ea6a0fe8dfd051ffec56 +822fcd260a7876cad31f54987053aab06108de336878b91b7a15d35013d6d4d6de2d4b30397bb6f1d5c1a7b48e9d1ced +80b89ff95d725858b50e84d825ea99fb6a8866f10b91a5d364671ccbb89cb292bada9537c30dbde56b989c8bdc355baa +b53cab156006c3a1766a57dd8013f4563a2e8250995dbeda99c5286a447618e8ac33ebf25704b9245266e009a0712dc5 +b6e2da9c1156e68c15861a05cd572976b21773e60fc5f2f58c93f3e19c73ad6c2ee3239e6cb4654040c8e15df75a505d +8b7e187d473a0bd0b493adcdb91ca07c9310fd915dec46c2c9f36a5144eb7425dd35dfa50feb0e9ef747caed9f199944 +9743ec3917e953e0a420406b53f4daa433adf4ad686207e9f296e7c83d1ffdbf81191b920ba635c85416e580178c16ff +98d1476fd4504a347c5261012298ca69c8593fec91919d37ddfdf84155b6f1c600cd8dbb92b93f3262da16cf40a0b3c6 +94f50d52982a3c81ac47a7b3032dad505b4e556804f8606d63d821f2c1a4830917614630d943642ba375b30409546385 +b5c0eb5f4cf3f719be1a9ad0103349269e8b798dbffe1b5b132370b9de1188a6d71dcbc3635dfdb4b888400f790b6ea4 +b47fb45ec73392598866d27994c2feb0b0f3d7fc54303a2090757a64b6426d183ae41af16794ced349ede98b9b3fd48c +b5f45fd0aee6194dd207e11881694191e7538b830bfe10a9666493ae8b971d65bc72214a4d483de17c2530d24687d666 +a50c149ea189387740d717290064a776e2af277deafcf5f0115bbbdc73c0840d630965a4e0214b738d1cb0d75737e822 +b941afc772043928c62e5dbe5aa563fa29882bff9b5811673f72286ac04fddf9a9ed0f9faf348268fa593a57bc00ba6b +839051a7838937270bdf2f8990fd9aa7d72bfc86cffe0b057aa8eca7393abf16b70d71a6470d877f8ec6771efa5a8f26 +835bc9d049418ab24dd1cbf76ed5811381e2f0b04035f15943327771f574f723b07c2b61a67a6f9ddc1a6a20b01f990d +8935cf5634d6ae7b21c797a7d56675e50f9d50240cb2461056632420f7f466fdcd944a777437dcb3342841ad4c3834bf +b5698fe3da1f9d1e176c9919fddd0d4d7376106774aa23a7a699f631566318d59b74ae8c033eba04d06f8cdcb4edbbed +ad11421ba75d74c600e220f4bce2ca7eacb28e082b993b4368d91218e7b96029acfbdf15a2ab0b8133b7c8027b3c785b +886ef813644599051dafdaa65363795cf34a3009933c469bd66a676fdd47fc0d590c401cc2686d1ba61fce0f693426d4 +8858fdf3e98e36d644257ab6076f7956f2e7eacc8530ec1da7f3e9001036cba7a0855fb5011925cdc95a69600de58b2d +b59eca7085a2f6dfeaa6a414b5216ff0160fbea28c0e2ad4f4ffd3d388e1cc2c23a32dbe517648221b75a92500af85e3 +abec62d259bcd65b31892badad4ac8d2088366d9591cd0dab408a9b70ad517db39c2ef5df52348ba4334dce06a4e3ba5 +a9acfe8f5a310779509621ed2946166ffb6168e68ecf6d5a3b2f6008df1728c8fceb811636c50d2e419b642a848a9ca9 +9929bb1a3537362848fac3f1bcb7cfb503dac0a0b1bebbfd6ddf14c9a73731e2248cbaf0fbb16c7d9c40cc6737c3a555 +981d06c7431e6f4654e32f1c5b27e7be89e7c38d59c4e2a872a0f0934cb852c6aeff2d2eaee8302131795590b8913f5e +a6ba9dd43354320f65fd5cdd5446cfa40080bcf3ef4a083a76ad4e6a609b0b088bcf26c4957bfab829dca6064410ca5f +9367ef28def311c79adfd87e617651fcc41ad8caf047d73ce9a1f327e8871e9b35d5b203fd0c0138e32e2ef91e20ba62 +855d1bb508a9036f42116c8bbb830c576189798baee27c7c3477ef1b1fc5d7b0c2c7203457f1eb48d4b029dd6f646be2 +8539a5d0528d3d601083e162b34cb33b5bf6736b4feeeab4941f10eea127c56b7e0b8d57f34b72f8f674d89c10bf302c +a3b71a9a9ac2dfcd681bfd8f6a5d9abf5df6950821705bdfb19db25f80d9b8a89fac7a922541cc681325679c629743d2 +8e95929dfd4e5b56e5a8882aad6b7e783337e39055a228b36022646a13a853d574603de5fed12b6c1f2585621ead7afd +8b05c885575d6894cb67ba737db5915639a6f281bf249480df444ff9f02724e28ed7371ee7ec26d50d25f3966010f763 +90f1a45de0cc0641181d54ee86630b5d182d24e7c30c2615803f16de90ec7c982a00b21f250ccebc2e94ef53a13e77e6 +90f0e97a132092e51a4521c2ecaaa47e4e4f319e67a3cdbd00ed85c2f10dfb69c339bc9498e2abbffcd54b1fdc509a20 +a9995234520cab9d1bdec1897b0b67571b718d5021c0fcf913140206b50ab515273b5f8a77e88fe96f718c80dd9be048 +aebc6495d54d0e45a3c74388891dbcfab767f574fed0581566415af872dc5b3bd5d808c44f6e1fbdde7aa9ffd260b035 +ae757f8f4b1000a623a7d8e337a50c3681544520683207e09d05e08a6f39384b7aaadf72018e88b401e4a7bb636f6483 +a626a28d5ce144cc0c6a30b90ec2c1412cbbc464ee96ac49035e5b3a37bb3e4ed74e8934c489b4563f2f7db1caf8b2ad +8c994e81dfd7a5c2f9d4425636611d5dd72d0b091a5862f8bec609d0cdd3c423eb95b0c999c48faa5dbb31e510c22b61 +a1c0e59e076b908de760d9becff24883c6eb9f968eac356e719c75cce481f2f7bcb1a41ed983a00c1a3b9369a7ff18f9 +8d7e199044fe2e552bc514668fe8171c3416515f7a5019f239c0384f0ade349e88df26cd30f6b67d02b83bf005d85de8 +80190f2255199be690fb502d02ed159aa568c390a684f7840512efc3d2a62f28a49d5d1928ad99a5f975ad81a245acd5 +889d84cefef33f5714e14d558f41d406072ba66b427bf27918b669c5be46261c3de0139610a2c2eadef8e6508e937bcb +a480a686d5085b854ccf9e261e7f1f2d40d978fc30b62b1a8fa9561127745529405820df21a680ee2258b8cefa5f0201 +ae6243400d416a8c13b80b6637726959ef07b8d9b6aff2bd3bb23aaaf97337c7a6b466c5db617bf2798e01d4ccc68e4d +85e0ff143657e465f3d934ee781de5cbd2bfd24f2fbbe6d65c698cdd93204a845f6ef1fa8941c2578463a06a8a418481 +8f4f8b45f1a9f6c2a711776db70f20149dd6d0e28d125906ba9893c5e74e31c195b0906f04c922c8b556ced7cd3d611d +877b852c33483b25c4cd8da74b6b589d8aa96e217c3c4d813466c77ef83af95a94a47364aa8421f0396ce631ad87d543 +852cb06bc4222ce125287a7a55a79ad0bf55596f26830dd6d79da3c60f80e3ba7b9a9b42b126dcb99d2cb9ce142783ef +810cd64c1dfce85d509eeb57a5c84efafe1d671454ef601a040de8d46fb33bc419577f6a6c404e28ffdfe315ffec558a +b60ff8bc804d101a32079b8ed52285fdbb47fd60c3c15cef17cfe7f6b0567de6b50128b9dbc49a1d9811b62b22c99143 +a9df7068b26a6a58f7a499e67b17d34f2a2e8e5029c6e51e2b4c0d19324fb5cd9734c4c4d5034e1bfc274cd0c74a82d0 +ad93c50802ded1e21217a58b874c074ea52322492d589820691572084d8edaede8c2ce8021c6df8c0060f395f3c25ee8 +a17b98e090f7ef5800477132b436c1fccc1802f34956711bfc176e36890c7df95a108e03f34659142434cbd8aee9dccd +acb14aea5575c293dc0a2b58c5350390801d57e9bcda876d87c56565043ddde1a544a88b48ad0d8ec3d41f690aef801e +88b8e26cbc83faa053fa247e26c95d1bbb77955b336e1b0e41d080633248238de8adc9b98688c98fdfc67e7286bc5be4 +899f69823cf1b2204c8da91bb4f943c04d943137b08b1c46e160919e3378bd22a666a079a66e63d81c05336c742efdd2 +8d7ffbc0b47a32408c9e88676ac4f87683cf37c37d214163ca630aec2d3cc014d88caff35022ff3b6d036eb8343d52a3 +b7760f27db0704a6742855998a0c31333bb34d60ddebc95588e25b72445ae2030427aab088ec023f94563118980f3b74 +ad06ecc0f3745861c266bf93f00b30d41ed89d41e99ab63fedd795c970d3ad40560e57ab7333883a72e5575a059df39c +8687d28b1cbc8aa34a0e5dbdb540a517da9bda36160daaa7801fce99754f5d16eda3bc8e1df6b0722cfb49e177e9bcb6 +a38332c3ebbd7f734c8e6ab23ae9756f47afbf7d1786fe45daebc8d7d005d6d8fd22f5dbd0fa8741e1bfb2014d3f9df7 +b86f84426dee88188be9c5cc10a41599e53b7733ba6f2402392b0ea985effc7525756ca1b7b92041ae323337618b238f +958731a6f1881f652d340832728bc7fadd1acebd8daebd772b5acea634e9f7b7254b76d38a7065ea1b2cdea83b18a54f +adb90bff1f0d7d45b8ba28b536c0e0f7f4dc4b9a0354692ecf29539631d7a57d308db3e438e0f907810234c490b42153 +a5188c775ad76617d3bb6e7f1f3b2449f48b7bb7a84035c316284396529564a227e3b9762a89c7114fa47b3ca7ba418a +a3826ef63c98793a5c8c5d5159e2e00cc85fb5e5124f06421b165de68c9495e93c2f23cd446adf6e6528967aa3ed3909 +80eab97de89f3824ace5565b540b229adcc6ef9d2940e90de185af309234cd8aa4ae9c7ce1b409b3898c8fd10c8c2896 +8824f5acd4c2330c459fdb9ece9313263a8b20419f50f8d49958dc21754c21a77bcf7fbf3e0041f78d8fb667a3342188 +95091cf06911a997a09b643326c2fadbbe302555ab2521db806a762a5f4492636507ca71d7a093840236ac3c096614f7 +a392c81a546196d7e78b61f3ceaadfb2771d09fe43f862c0af65f5e55ce490a0293b9ab754cb5ab03ff642a9a8213a23 +afd76cce1dfa2c9e4af4f840376674f090af37d8c6541824963373f97b9dd1f405c50b2ff56165e1d4dde760e590738a +8fc4f513d3b40c10872603e1c29a4b2cf4c99320962644ce89f69ffb57f844344e1d472b2d43559119bdfb5a2c21749a +9951ca8e13b9a2b4a789e851c04c4f030470772da62f101074ef304612e9653b43b37d2c081b5d0a09196b3a167f5871 +b4f16fc2a113403ab5fc1b6a9afddec77be7406413b70ee126f0e84796168a572940550d61e443e5635591d4b6c46ca9 +8d71452cf39e7345c7298d514b9638a5cbe78af7652f0286d42632c5c6d7953ed284551fb40c77569a7721413cdbf79c +953625b58d52a308cb00ad87c44a3fd936786ada44000d45bb609ea9db6b156a0d0f9475e13ee5e053eaded19a09990a +a0983a3baa278ad5f5de734eb1b65a04f668408994e396fb0b054991ad2e56e27ac522b04fe37c9583b754e344f795b3 +8eaa454257f77a6754b2c1c5ff0036fa5b03e214576fabc657902c737fcbf298b1795b43c5006e18894f951f5f7cd203 +90183fdeae2ce2a295a567fa61b997b1f975d1be7b03d0101728cd707bb2a7111c222588ab22e573518fa1ef03719f54 +8abec7f31f6b897a1d497368a42733a6bd14ffbb8b21d3e49fc4cd3c802da70e8886827c1aea0b18d1b44635f81ec461 +a6d1e6fd24b0878ff264b725662e489451c590b2aadaf357d64210a3701fe763f529826fa6e0555267c1f5ecc2c52c05 +8fe6d2a4ea0d91702cb2a8a1d802f5598f26d892f1a929ff056d2b928821e4b172c1c1c0505aa245813fe67074cf9834 +82a026a408003583036f16268113ca6067ce13e89c6e9af0a760f4b2481851c62fadeeef0d361f51dcd9fa5674ec5750 +a489a574b862d4056091ef630e089c163c16c2f104d95eb79a27ae1e898b26d6c1adc23edc1490f73bb545d3a6e3b348 +939d85148547fc7b9894497841bd4430bc670bb670f0efeac424b529a9aebf2c02ac18a9d1402a12e4e590d623de09f0 +a3ab52cf911a2ba7fb0cd242d7778ec0d4fa382960c9bd5b476bb1cd44ff1430a3871bbbcea0a0db2630c39ee639fd1e +b7629509d8c3a3b88b31f1af137a25c38f536284f11a5bbbe0d05b86a86bc92ebbf70f17c256dc8b0d48374e1985e6f3 +8a8647ff33e0747dd6c6ceddcf7938a542656174a08a31b08337ea49b08d814e75f8363fb51676a2cd2746569e3bc14e +a7a7f8d94d32b7cee00b3ff272d644b8dca86b8da38c726f632c2bcdfa0afb13fd0a9a5685ddaeb6073df4d9cfa3d878 +b7136eea8d05bfee2265b0e9addb4bdf060270894de30d593627891584b9446b363973de334b6105e0495cf8cb98e8f7 +a9fcd33ea59315ad7611a3e87e8d1fd6730c8cbeeaebd254e4d59ed7d92c97670303a2d22e881ab16c58779331837529 +965fd41741a0d898c2f2048945b2aefc49c735228c25deaf17fed82c4d52cf3f8e93b3fb8825ade632dc4940311b1542 +b9f400a2c7ca7da8b36470ee5d26c672b529b98e6582012cbfc2a3c24b72e73f5633de4265c417c0d47c474155a603c6 +85f333b0b1630a688a385f48bf0175cd13ecdd92fa5499494f4ad5aea0ef1b9d180fad8f936018538d842630ff72884c +8da95a735a1a98ed8e563099bd87d13a237dd7ec6880cfac56c6416b001e983a56f3d72dda7f68684bb33e4f64cadd30 +a29b66a2095e1acce751f6aec8dfeae1e5b24187dfedb5d1635ca8deae19b580ef09329a18b3385ebb117cd71671f4dd +b001deeeaf5eaf99ac558c60677b667b9f3d57cf43a2c4d57fd74b125a6da72ea6c9dc81b110655e0df01ca7b8a7a7ed +912e11dfff77c778969836d5029747b494dd81d9f965f8be2c9db9e8b08f53858eface81862c3ee6a9aa10993d0d23f3 +ac166a00e9793cf86753aa002ca274cb6f62328869fe920f5632a69a5d30d8d3ce3f0c5487cb354165763ca41d83495a +b74df519ae1a8faeff2ccd29892886b327c7434360ab5c5355752667069a77d466a48cb57b1950d10b6c47c88b2a8538 +8751679aeffa39da55f2c2a668f7b26fb8258f70c5454b13e2483e3ad452f3ac7cc4fa075783e72b4a121cd69936c176 +ae0cc16848b8bf8fffbb44047d6f1d32b52b19d3551d443a39fb25976a89d1a5d2909a4fc42ee81a98ad09d896bd90a9 +a0c8acd6a2f0d4ab0e0a680fa4a67b076bbbf42b9ec512eb04be05fb2625f6d2ed7b4349eebe61eb9f7bd4f85e9de7fa +85c629ce0deeb75c18a3b1b4e14577b5666cf25453a89d27f1029a2984133a2b8e7766597e2ff9ee26a65649b816b650 +938dbb477840d3ed27f903d09fd9959f6fec443fbc93324bc28300dd29e602bd3861fd29508da0dfdbb0fff7f09c5a6c +a7c76cd4a42ab7904d036fe6637471d9836ad15d0d26a07b1803b7fb8988b8c9edf522e0d337a1852131d0f658565ae7 +838a30260cf341ae0cd7a9df84cbc36354c6bc7b8f50c95d154453c9e8ec5435d5f9b23de2a5d91b55adde3dbdb755b9 +8f870b1f798c0516b679273c583c266c2020b8dea7e68be4b0628b85059d49e5a680709c3d6caabe767a0f03975c4626 +89bad0b6499d671b362ae898fee34ad285aa8c77d33ca1d66e8f85b5d637bbd7ae2145caae7d9f47e94c25e9d16b8c4f +af963d3dd3d983864c54b0ed1429c52b466383f07a1504215bbf998c071a099a3a1deb08d94b54630ac76d1d40cfc3da +b5686de207c3d60d4dcfe6a109c0b2f343ed1eb785941301b827b8c07a8f1311e481a56a4baab88edb3ddc4dace6a66a +95e5978739a3e875e76d927f7c68bdf7ab20966db9fa8859f46a837760dfe529afa9a371a184dfb89d2962c95d5fcf3b +96d2855e20c37ed7bd7f736e11cfba5f61bb78a68303a7ced418c4c29a889a4798c5680be721a46d548d63525637e6b0 +b134bceb776cd5866e911f8e96016704c9a3caeadcabd7c0f37204497d789bc949e41b93e4c2d597e4c924853f1b21e3 +a1949ff397013acde0303e5d64432bf6dd7f01caa03c5fc38e7c8ae705b9d5c2646b4b02d013004e5eb58e344703260c +8036a5f79d8aeb6df4810974cf8dbd0ac778906d2f82b969ac9dcfbe7ece832a7e8aad08a4dc520f7abeb24b1610ae84 +982b6b0af8602a992c389232b525d4239edc3ae6ceea77d7729d1fffc829664dd647ff91c4cb9c7f7c25cea507f03167 +b34c7d24fa56ab6acdb8af5b4fa694a1985a1741cc53a2b0c5833611e8ed6fb3b663a4d9a126bb4a1a469f2072199d66 +8166366fec4ee2b3eda097dc200cdfa0533a742dfbe7082dfa14c1c1ecafc9d9fa71f518476634f29d06430869bd5e02 +86c0251ac00b8200618c8b7ce696d1e88c587f91e38580b2d6ae48a3ef904e0ba1b20b7f432719ca40e7995f2281a696 +afd89f3bc7843a1e45ac961e49c1971114c5238d9e21647804b1852b8f476a89c12d1edfb97fff71445e879d6bfd3b70 +911d8bec4d4c3e73a2c35469b2167569f59705404425bd95440408fb788e122f96e9b1bd695f35c6b090f10135b20cd3 +b3f6350ff7afaa0660f9dddd9559db7f164e89351a743fc695d987c88f89fc29136e3c5eb81963edabf2b6f2057120be +a371229680d1468777862e9c0e864156f9cd7c12ce7313a8de67b7bd34e3d1b6fa45ce891a81f8316f4afcbdecf3b6ca +a6a9a875ef9efe8ba72523e645b5773aa62c4fb41efd23da3fa38105472308b8d293be766342ee0a2f00758825bd3b6a +a840d495a184f4499b944ee08f07193a1e1bb8ab21f8ce7aa51d03bd8643f2bc2616c17b68d3fe7c0fb364136926a166 +b55200ae7d6ebb0b04b748051c5907293184b126cf8a1c2f357e024f1a63220b573e2875df83d9b5e0c6e2ace9300c40 +b1e0870f2e3719f42a48256ee58cc27f613308680f2d3645c0f6db0187042dddcfed0cb545423a1a0b851b3a16146d70 +b43a22ff3f838ad43786dc120b7f89a399ed432c7d3aa4e2062ad4152021b6fa01d41b7698da596d6452570c49a62062 +88b1dc50873564560affaa277b1c9d955aebdcdd4117dab1973306893b0e3f090899210102e7e1eef6f7cdf2f4e0e5db +9223c6246aa320b1b36eb1e28b5f9ccc2977e847850964f9762c7559da9546e508503050e5566ccb67262d570162b7a3 +aeeed21b932752709f43dc0c2c7d27d20263b96a54175dd675677a40a093f02bba80e2e65afe3eb22732a7617bf4ff9d +b47cae580ae84f4e4303db8f684f559382f075ef6e95698b9a629e92b67bf004f64e7cf47e401768fa170c4259efbda1 +849821e1ead81fe2dc49cd59f2bba305578c4ea0e8f4b8ae8fc275a1c4a6192f8819d5b6d7da786c94dfc16aacf3e236 +8c60d9a8baefc72a3d3f9dd2e24cca40fb5ce36b19d075122391d9b371c904a0a15d2196c0f2ac9da3acf188d15b0fe8 +946edfe168bbe5ddb0fa6c2890bb227d8418bfbebe2bafab84909825484f799407b610d8aab6a900c5ff9eb796cdc4bf +ae7bf8ae71de5d7ea644d9541e49da1ec31eca6ff4c3fbec5480d30e07ef2c2046cc0a486af7b3615a6a908846341e99 +b4d31a6f578463c9a5ccde0ea526c95b1981eb79468665395c0e550829abfdfa86689699d57830856e324092a423f231 +93415ad3a732417cca9771b056ed42db7ce50879aca7c6f71883ad297eaf5a37fd4641d44a0b7e28b90c168834141340 +98960617a413a3ba86d8257a7386355a69258943aa71834166bd624ea93b0af06178e86538e237f88fd039eacf7cb04a +881335200a487545e38d5b1ffda3080caf5729e1b980603bcdf9ea652cea7848335b83aeeaa321d3476ae4a8d9073582 +b39e84c14666d51895b7a8341fd8319f9e0a58b2a50fc3d7925cce3037f7c75367b5fb5bf25ff4720c9992cab7b8b9f4 +8ea4bab42ee3f0772d6bd24dff3643d8b61147b46ada374414d8d35c0c340e458e449d31023d96e66decf9c58e30cc34 +a5198f6759a045b6a4ba28e4bc3bb638fad44c5a139064327580e285adf38ea82a7570acebf925e81a39d9025f3a6f2e +80267097e2d27c1b19ecf95d184dcff822d34e03326b9fc139a4f8b75b3f80777bb97a9dd284d9b755f14dd401d63c0e +946f346220bd3b6f733e94b61a1ad0b44e45c356fa6036dde5882d93b5613c98e23b20e91eddc6b3c5acea38085705af +a5f559e110cad99bbcae2d9362434aee7db0f3b6d72311291649dbda3f84c10e9760b66b988db3d30067bf18ae2e5238 +8433b38e5c7b293ef532f8c70cef1ed9be7f31f60d5b532e65df7d2885203be78b7ad78ab3011bc54cd9f64c789bf837 +a5a4c0a9b0e0b6bb912cf6ecd30738b0acc0146d77442449b486c3f32d7e60244f643a5cf9cc6da2de5408d0c5f17691 +a81feb329fb51b72464bddcfcf4e02149d995b548d88c64ba143144ce16b652c9913c8ee948ee837596ec97cc43d8cc9 +88e5a7e93a738d61330425bc21ade88d33d7160d124bf174eb3e12a00283654431036977c4f1a47a1bbbf2ef8449ac89 +ac75ad7c099383069e662bfd3624b92b64b5838246902e167fc31b9411efda89b2c6bbd1d61b9eb7d304faacf438d70b +8583bcd1c7cb9bb4bb6bcff803b0a991912b8403a63c0d997761ff77295ccc357d0292318601a8c61329ab28fed7bb83 +a1f9aa0523f1dff00023a44a6c3a9e4e123be0f6722a1c6682ac3c6047efe9e62f4773daf4767e854e1fcbf8ee7339e2 +85f65ebcf5c7e574174b7c4c4166a9a5368e7986b8c0ef846c2e13b75dea7311a87483503149ebfb3cb839b3ef35c82d +abc55eeb72699031a367b9675a2b91a8434e1f01467660903ced43a0b2a11a85ebdf48f95c13ff67e4e2958065a50ff3 +a4ff77c9b86939a15647499b9412417b984bfb051e5bf27b35392a258a5dac297bbdbcf753a4be6729ffb16be924a2ff +af0d41c15b5172efa801cc85ed101b76844dcd06712d0d21160893235a2dbedd15d187a9b31cf0d0ca6c14de6ab2b707 +92661339199f18e5dd9a210783c1d173a26dfa315bd99a33d6f04bf506c871a2b47745c1909faa209d5e6c5c645124a4 +b35813dafb52df709dfa47982bfb44e1bf704f9f46085b2a0e92511dff90e5597110f614f8915830821fc5ed69ae0083 +934a05aa713fa276a4d47f1a28ef06591e5a9a69293c1651c223174df0af4927fc9cd43d374d89c1b4f7c8dc91abe44b +8f83a0ef05202c0b7170ac96f880135e2256fdf8964dae5aed5dd0f6452a6d8e123321e8c182b3aa6f1f8ab767caa735 +b92db10c21c321cf1349fd34129d7180e5088daf2bbe570de6427299aab68992c011c2e2939a44247396f5427c1d914a +95ce1892d1ce25ef2bc88a23880055a4d829a3b31f3806635fd49bec32cca4e965b129b6dd3e90f7e3a2eb293ffc548d +970cf816ee7501ade36b0b59f87c7e352957f67f1f75bbacd8ed52893f9fc40572c76f49c23db44866af7e34a63cd3f9 +a2fcd08581d3569fff699fd7ed1ede5f98f2b95956ecdf975a29af053d9f4f42600b3616ad6161e958c3ce60139c20a4 +b032688b6cc8a7e63dcb82694f71f087b1ee74c4d5fa27323b1ead3ba21722d7fc49eda765725b5553db5260005049c3 +b0b79e4329f1ad25ef6a603390baf889757cab5af10bfa6953a61f89aaace0442b9ef08e57ba778f1e97bf22f16f0ace +a2e6ac06f8973266cd0df447f82cec16614df65174c756e07f513e2c19aa82c10d8670047860960cfba3c5e4c42768c8 +811e66df0f3721a1ae0293549a0e3cd789f93fb6be2cab8e16015a6d52482af9057b1b75e9456322a5a9e87235e024cd +8744a80b3d9e37da4c50c536007981a4958d7e531cb93916dbf985cdc22f4ff482a5cc4fe50915c049d2de66530f1881 +b20b6e8c7be654c23c8ca440be2c37cf9cc9f4e81feedfd0cd7c56f37eda8f295fe5d415e9bac93d5f0a237edd8bc465 +b33fd84377f31f7819150d464b5eb3ef66e06cb8712665cf0587d61e1b1c121d11cc647f3753bbc18604941c77edbc1f +83acb8a3ec5f477b6d44cd49f9e091bc2bf7c9dfee876cde12075a7db9262314cb66ad2e7557114e0c19373e31c6eff1 +acfe4172327832ee207eb07da9cd37da3b009c776f7a8290529f0249f58da213254baddc7c3074fbaa1d226ba1e52b7c +81911b4dea863424b9d77a981987732382702e0294d8c8e1ec48e89678ecb0e64836b45205a120885fa8f8a3a4b9d4b0 +b11f61b1302579a11077bb2f1f0db371ab943573b261be288dc76172eee8a5102b992a5b526092d160ffd20aac2d4856 +ab491f7f1e002a44944c02537f365e525ebb6d5614bba8e5e8e8bd12064c702a1759571ddbeee592a0ba8b73cfce8810 +89211da3d92aed6b111de001b8b5a9231a1c2d09fb1cd2618ec457b635a6c8590fe119acca42fce76dce791c35b889c7 +a5f076c8f7164bcab8af59021ef97a0afa93d0877e52241c3ff5a9a9f81227a55c119ed6a84d34b196e94ec851ca5ca0 +80d91417d0d6c1adb5a3708165da1d54a83caaff482a4f65abf3fb335cbbc738c74ed19a8c451ca98befdf9b2d8b5f90 +aecba33a67f66401614eec5fa945e763da284edb9dc713bad4ac03972630781a09a3e2a291aac0605a9560c5f3444de5 +8a0aa1320bf5217a049b02ad02a4f892bfd6a3f5b48f472041d12f3aaab8dd197307f144f9de5f9e762c6b4971a121b4 +a4120a569e446fe4129f998e51f09c1cc7b29dc2b353d6f6f05daad1a4ef99acfcbaa4950a58aacf7ee1b3fde0af33d0 +aff71370d58b145758a5f24cf3c0c6667d22a1f950b8137c369fa845a5265cd645b422f24fa95e1cd7db1d68686120b6 +a839f075a8a702809a51fbc94595eab4f269a2e7a027aa1f4fc472e77f586138bf5aa4e5570a560e139eb6cda4cca161 +9484f1caa3e35cda0e3d36e43aff3dd8cf45a5a51fc34aafa3a63ed3543047ba9d6af2a9bc7c201c028499e6b4c41b28 +84ddb374c5c9170903bb3e1054fad071b0a147a9ca2ebe2fdb491ebb2431d53b398872a39cc385f973e38579d8e60158 +acaad8babaeaeb52c5b5a16ae689fa5ae15846f2d1f3596a52371bd8681819603822ee8d32ab8cda1bd5290d601e483f +946b69ca5361b60c3dc31db13669b05e5c0452f3c80e7e185f9667a36f351e9ed83bcb5c6dd2439ecd4490e3a87d260a +99f457221ac40df86f9b4bef0bf8812720b2f7218273a0aab08c4d4d4fb18a0fb0ef6ba9bf7fa53c116cc6f16742e44f +8bc0e812d8b718dbe48ead74a6bc7bac68897d01d097422be04110a25589bacd50d336d2c8b70d0dfde6c1b8bc372dc3 +895d118dae2fb35a4b0de22be0d000ec0f0f317b9494db7c12f10d7db81b6f3eaf6d6f3fdfe952f86ec4143d7469368d +893bf3d7e579e800526bc317438a69590d33759931830daf965cec721baa793ea335e9624a86b84b8fed5effc3e2bbac +a112d30dda88c749ca15d6dc65bcbc7fe838b2d25329d44410a9a96db195c7ce6a6921196a61ba7c9d40efdb101a164d +b88b5340af052fc3b8e1a8cf7532206801e79d878f1fb02b32ac4f8e91b64e0ec9252d808b87c4579de15886a20aaef1 +865f76475bb5da18c6a078c720c7b718e55d310876c98017c30ac31882ae347258b508ec34001918324250241d2df5b7 +b6d8a15913eb1714061d5cacbd0bb05edd83ecdb848a89b864e7411598e9f7814d0c039ebe4735437c8370d2ff183751 +a95fedce8351ae9c24d7fa06ebc5cd4e3aef87afaf04a7150e561a6a7f2347bdcec1e56b82d6e5f597fe7124f6cc503b +8526004ca0c802b073d50b0902ea69975949e7567b2e59ca2cf420bc53d91951d26096f2abb07a2955a51506e86488dd +99ccecaab68b6e5adadb9c848cb577de7e7ff4afc48d3b6b73bc0872730245b8a1c68cebf467074af6756d6226f4f4a7 +b5497d5c0cd79b7e6022e295642e1f2161254379eb78ef45e47f02c84ef5a3f6b6297718e4fac8093bf017287e456917 +b6943f30012b2093c351413c2b1b648afc14a5c4c0c338179d497e908451d2779919fe806181452ed386c1e8f8e8c25c +afdb56ce89bcd3247876c918cad68aad8da65d03c7c73ccbee0c4c39f3ad615aab87ffa0db5b3b63b4cc915d0b66deb7 +a44659d7be2f11d4d4949571d7bf84a6f27f874d3281edc34ef1098d321a4dcad9a42632b39633f8f9d20a39f54a2464 +a3e489b4db5832280dd58c62120262471b6fb4355c2ad307bd17c5c246b3f1e1b00f925930f5f5f6987de234fcbb7d16 +87a4e3a190340ed4949597703083d338e9c17263ba8a39b67100589f0dddbc420d9557f9522c17c71ae04b76876f8db0 +a35a3978e928eaac8c182a0a613c611ae7b4827c5e999f938eed06921c0294befdc21d02e68d035a2fc8d03c82641126 +a6898d90265dcf0fb215629f04b07c7918e022667583efe0bfe02f258b446954876c6ca9e369ffe1bb079e2314ebda32 +922fc52e648b6b2b6768c079c67ab425da72907a46add801715f8a2537280869d7071d527b833aa63ef562ce059a392b +8acbb7c4297196d8d1c131040c34cc7064656a148c2110b19c672abb094b1d084fafe967f7122ba9dd1523a4eaec3b42 +82dbf2cdd581fe3b81b156792228eae2485710e6c21dd5fd14614dc341bb0afbebbc0f32340eda9f094b630afcfc17e8 +907a095dca885da219e4558e9251ec765cf616e995c61546bc010963bf26f2d8adbd9b2ef61f2036e1740a627c20fbed +a7a83f849691d04640137989a2d0c90a7ed42a42b0ad328435d7e1fba557a27a58eec9170ab3d0099ec97da0c950765a +b7d435a801c2a5652cb479027f2c172eafa3df8ca0d896bbb9d49a42c42660fb382a8439bfed09ddf7e0214cb6066761 +8bc6b5e79af5512589f90de8e69bc858277055cf7243f592cc4edd193f03f71d16c9300097ddafb79752c63f135c884c +913264fca800467bee58a429e1f245ef303f5dbeea90f0ce6bb3c7ae6d1bd0f99ea75d3d309634684d2178642c81b5d8 +83ba558f9c23b785a123027c52924a1d7334c853a6165d4f5afd093b0b41951a36860ba0a20fa68f73d7db9df0e3ef38 +875b2df7cb54ecdf7ba31181b9dc7dbe02761ab8ffb61757d42a735c8e20d44bad5b904e76dcec6bb44883fdb9f4ad84 +af3dc5d2dd29565de8f4c700d5f1ab71dadb4351f06e9ee2eb5ee7a9b5da827d0c6726c6dc780748a26aa3b4d10e6c2d +a113ff09296b25f550f6d0d3f37dd4517b14cf6d5517293bd3068aa3aea765a8640fcd4bf0ba96db5c00167267fbd574 +a138c5cca485b9180ef091c9e327982bea203c165cb83564f416c36e813bea1ef1f6345f57c8a591df360541b7b758f5 +85793441e917ed520d41dda6e762269fb9f9702e5ef83cee3e90652d324536bf4233425cd05b54a383609076ab84ea13 +b422ac9de53d329e6321a8544c264d63cffc37965d627d7e180a999c3332644e21fedf10cd2f43cf6ba4fc542db91155 +a85d31d4bfa583a493681e57bfccca677ec5b85870a53de37f7be7833b573f8c8dcf029cea4ae548d83048030d77d56d +ab8a0702a371db496715a4ee8fcb6d430641b0f666d7fe3ef80c09df0bf570293cec1aa1675381c6bbd9ecc1f7cdccf9 +b308ef2b87438d35957191294782e9f5014a3394fadad3e2ccaf6ebf20fd889a36dbb8ddb3634baa8e2e131618aa4e70 +919e972e5b67cd65f377e937d67c27b4dd6fd42cfe394a34a70e8c253a1922f62ff36b9dcc7fbbc29b0960ad6a7fde88 +a0e4d4be28301af38a910971c8391ef3ec822ce35757226a7fd96955cd79afa14accba484ef4e7073e46b4b240a5863f +9422f6d424c1736b4b9bb9762aa62944085e8662c4460319dac4877b1e705aa5cd8b6b3a91268363ec3857c185685f4b +b7cf9f2053119d284a37df4e4489b632594df64e5dc846652ee26b4715e352e6333118b125021481138e4ec3e9f9987b +aea983e81c823472df8652654be8a60a8bf40147d599f87e323397f06bf88c98e9c6db0f28414f6ea4091f3eb0f6a96d +aa20bf03cd8b6ffda09fe0ef693fc0aaa3bb372603e786700e52063a4f7ee742771c41cf5e67e6248f99b7fc73f68dbf +8748a4978198071d7d5ddc08f8c8f0675d895dc19df0889e70bd86d44c469c719b93f6526c7e7e916c7bfeb9a1379aaf +b8fcd863d55dab2f7b1c93844306e00056ba17338ddfa3f02689a0b58b30239beb687b64c79b8420ecea8d0d082d9ffa +abb1a35952dc8a74dd1cdbc8ae7294c6bfd1910edab6f05c879e9ed06c636a949fe0017ec67f8f6f73effcb5817cccae +8bef43422b1c59e354b7f46c08a8eb78e26c4d01c236a4fe781cefb7465293a4444f2bdc68c6a221cd585a2494d9a1d7 +93527258940feff61befa18fcd6626fcff019d34a3ac8c6886599cbef75b15c15d689e8c1bd2177cc93c4c1792dee8d7 +b7f114eea99c8278841180ec8886ad2bab1826554a1657b9eeb17aa815f31b59c3931913ddec40aa9923bc92f8975635 +91a96446158b194a0a6ada2e37c8a45f3017c34034f757245f6f3b98c65d39d084e74d2a9dc271e5918faa53990ec63f +aea4ada0a853753db03f9790e20bab80d106f9b09e950f09aeaba5d869f0173bed673b866a96d6b0dd8123a539caac9a +b8e3e98ff0d3e512441e008a4a6783233045a4639e0c215c81984846b43ff98de99d7925cf717b1ca644f6229b6d16a2 +8987ef81a75213894e11e0310e8ba60fe06e2b264cc61655e5b51bf41cc8c3d6c10696642ea3517770f93be360207621 +8d4eff7335252f74af4a619c78625fd245df640f2086338dbb6c26b059f83fe70f3e81f5b6c12d62c0f784e572d56865 +a56f6389b0bac338f20c615d7d11e16045a76cbea23ced0a9d9067f538421c378200bfd4523b7c96094ab67f47f98d42 +83f5ab0727fd6ce8b3370ce3fac1f3a9c1930ea7ebbd16be61cc26f34aa1291ba4b5f16729d7d4f5924eaa4a1e31a04e +8cc62366874bf8751067a526ea32927584cef41174e2ec5a53079ee557067bc282f372b831cb2547c5e21a2f178c91b4 +b609e141006dc8d8649457efc03f8710d49abb34bc26a33ed4e173e51b85d7acdf18d74aed161b074f679d88f5aa2bf3 +873c7aa784c17b678443320950e494250baff8766db42619b9fc7ec4c3afa4eee290cd1f822b925d5b9e55c9cdd1af2f +859ba787f052d3665481c3dd58159ec8c238d918fb6d2787ebe275ef9acd377cb7aaa03a69820c78247bf51afee3d5bf +8eb1e6d2b0f51a3275b4a8be96957cb2d518b32c815dc0dfd5f75340c7dee73e5edc45db7c7d375c4ffaf8c59767d0c1 +85f3876ff5edbb826a9592e68db3dcc975725bfdda4fcac197758a8b27e4f493e6c531b1342ba0f5a75f965273720345 +8a1272f2678d4ba57e76c8758818965e6849971e8296b60ff85a522feeaaa3d23d3696c040d8bdaf1b380db392e988aa +85002b31ce31be7cc8757141a59a7cf9228b83144993d325b2241f5bfac09a02aca0c336307257f1a978c0bbf79fa4fe +b96bd26a6bbbc705c640285fd561943ef659fca73f25e8bf28cfcd21195752b40359d0edca0adc252d6e1784da267197 +936cfe367b83a798ab495b220f19cfe2e5bde1b879c8a130f84516ac07e3e3addcc791dc0e83a69c3afc225bed008542 +b1302f36190e204efd9b1d720bfaec162fcbba1b30400669dbcdd6e302c8c28f8b58b8bbde10f4512467dd78ed70d5e0 +8291b49f56259c8d6b4fd71525725dd1f35b87858606fc3fe7e048ac48b8a23ba3f0b1907b7c0d0c5ef6fa76cddc23f0 +97aca69d8e88ed8d468d538f863e624f6aed86424c6b7a861e3f45c8bf47c03e7b15d35e01f7add0a4157af171d9360c +b590d896e6b6f2e4dcffebfa67fc087fa518a9c8cb0834a5668cabe44e5c2b6f248f309b9cd74779030e172dba5d9e29 +97e7099bff654bcb37b051a3e8a5a7672d6ab7e93747a97b062fc7ae00c95deef51f5ced2966499217147058e00da4be +83435b739426f1b57f54ebad423939a68ad3d520db8ca5b7e28d1142ebfb4df93f418b180a6c226c0ca28fa0651163a0 +946c9144d982837c4dbc0b59544bdbc9f57e7c9ef0c82a7ad8cfddea78dedc379dbc97af54ba3ac751d844842a2990a4 +90ba1eff9c25adba8c3e6ef5b0d46c13de304632fec0646ee3a7bee69da2bc29e162dd3fb98a37ed1184ae5da359cf0a +b17b7a5c0a48eb9784efb5ff8499230b45efeb801cf68e13fe16d0d308511af5aa60e3b9a5610f96d7c2242ae57d455b +9991245e5617c4ea71575e5b2efe444f09cbbed13b130da08f8e9809d62512e8298a88d41f6aa3dbf3bcbc90654ceb18 +a1190c4cbccf2898a7fe025afd03f8652973a11cef59775fb47d69a6b4dcb9a5a0c554070421a5e10a75e43b63d37b79 +857c0a5f291eb35a76be11543a8c3d798187bd0717e2cdee50d390b66322d0d9529520fd3377136cdc93cfee99b6403f +944d11e5f9a3493c67786df94f129352d892fbdc43e98206b8dbf83cce240f65305e1768b38e5576048a31dca5c18f31 +818f361c5dae709e067a82b81beffbd9674de8df2bc1bfc3a27ddf326260e124e46b1e36697fb8de539b7736db093e9e +b07f5b737735a0d628e7ac2d335080b769bdb3acea38ad121e247a6e4307916ba1d029da5d341f079ea61eeaf7d8554e +a69e338803f3ee0fbbddc7ee481a13f6b64d25d71bae0d76f4b5145b54923cf1616c77ba0fd9ca37a3ae47208f490423 +acaee66b94e226622e28a144f93f6b1b442b9c79d7a8a1740c4d53044d0675a661e7453509b9e716e469fe11ce45ee31 +9402ca799d2e1cce0317ed49453ee0b2669b05e68ff101b89306db215c3941b3786ad3402d00369cb1dee020b56d3142 +849440c539fc0df3c8d06e23e271e6faa50234d5c057b8561e9376415f4396e548351cc677b0abeafe4f51b855a3dc83 +865b99587eb3dbc17e412647673f22b2e89185d1df1ec8ea04515585ad2edfb731be458123118dcd7b41b475026477b9 +9390618833b5adbaf24bd38cf9fc6f25104717f314259bb4da5c7a1f6963ecdc04d07bed391d8cd765c3d53567b2b6b1 +95383e8b1d0a629cec238b5ae2bda236a027f4e3b5f99ceace05f1d5a781ec1e7a43058f44ef0a5aee6b0db5697a0d89 +91739b8946d90db3a5244f7485295cc58143ba0449c9e539df1ba3c166ecf85ff914c9941192963c32d35033ae2f0980 +b5d88848d856d882db5947b9182025f0abf2bc4335b650fa0a48a578e2c87f32cc86d42d3b665ee2eab46d072bf1eccd +91f4c754549f5a53b1902ef84274ce9acf0bfd2e824e62eb127d67e3214ce05fc2430c05ea51e94dc6e8978f5d076bab +91fff8c75f8ad86afe78ec301de05e4ca71421d731419a17c747a9a0bf81129422c9499e4749107b168d1695dc90292f +99fbd7bede9cc1e2974c2a21c70788960c2dbf45a89552da8d73bb1d398b8399590707f2f4ba4b43cb356e703eb01b5e +80a51cd83e3d748c07b9ac82de1a697b09031e3edc7bf585f06cd0ffa8ea319517fcc2b735614b656677b54b4910814e +886b27de1f93311d1a31b6d698aa28b54fbd800decd8e25243d89e352ee38cb252d5648b5134a3e1ed021bae46e9da48 +976e70c94db905f83b4ef72188d840874bf005814c0c772f3832aa65b1f21927403125eea7a07b6d3305b1a781b36ab7 +b4adb9d1c49eb31462583580e3ffa625bea4f8b2a7d4927e4ff925c1759d4b3c1e43283d635b54fb0eabfbe1f4c12992 +b66b466bd48485ebeedd47e749d86cbaa3deffbbee2e69cfaa5e9f3bd28b143d7c1c0255a7a1393a2cc1490b2c485571 +8bded5bc0794513947ddb00ff6b780c5cc63a74e2a0b0284153c346a31c82e1eff07c073939da39e6f87a06c14ff1a80 +aceea8c6f799589f6b7070abf69fec724e6679514e60f1eaf9a52c37e9cebb72abcc833a81d8da1a4f5194c1a7eeff63 +89a9f76d053379687fd221ebcaf02c15c2c241bb673ef5298e32640a115d9e0f2331c3e185572cd65946dd6c5bd42412 +a57b6f1e3fdd92eadc6220760f22d0685a82cada1c7a1bda96d36e48e2852f74f3a83c757dd8857e0aee59e978da4919 +9106cf0891bb39ce87433c5f06a5c97a071d08ad44a7cbcd6918c0729c66bb317fbbee8aa45591cee332ad1234c7257d +96c18cca4a0f0299e0027ff697798085f9f698a7237052c5f191b1dba914e5a015ae356b80c17f0fdd31d08c5a939ebb +a892103c93df126c024825c07d8769bdac5f1d26ea9509ee26530dc594384b2a5095cc34e0b41ab3db0392a29792c9e8 +b7c2dbc95edb6fc25802ea051803b7bea682f87a99f8a9fdcc3091c81d914b9493dfb18a8894c964805298a6c22b07f2 +8e40948927d560a6840d7fb99802989ce72b43693e9dc7ed9dcda4bca7daedf75271cf656bcc22b3f999a550faad8648 +b354de1c6f0603df3ed9036c610281e55b51a48950ee3ce57a00b4692232de7ca57d19722700e15cbe67a91fcec2f786 +adf987b90737b933436d8036c1d3f0c9104f26c540052e22e703964f72739ac1261e4289b8f27dec47281a0f3f51378a +8ed5248e9c836fffa7c924178db593e1aaeb54bcf2e93c1983c1f3899cad538deeb2b836430fddc9b2f283e0797ea11e +907e5410e3bd5d7f55340e2f497bd1ca10bfcb4abed2c66a3cdf94dc40bbd7c43ac98754e0b4b223ea4c61eebf2f27f5 +8e81b441ea0397db28840fb4b3c3bfe6d8e31418816f7bda36f9c1cfe4556daee30c43639d90a2dc9b02a3d65e5f4ab2 +897085c477f5030f9fed06e181b05953a8cd2001d959dd6139738d40f1d673b2c7120b5348f678547acfdc90ffc9fcc6 +b0bf2784c4b3808a04be5a00a0593035ce162b3886e1500247b48365eac8ec3d27c7e5e6372e030c779c75fb79772d0d +af3fe6c75f2a1241ac885d5091ff3882cf01695d957d882e940f0c31f7a5b5e269c1a2bae7336e9a7cda2b1d23c03bd1 +a6d94e065f85736d77080a4f775885ccb0dd5efdbe747e4595280bca0ebe12450257c1beadcbec77566ef57508c5d4df +a5c50fe56b5532bf391da639a2f2b6cbb2634fc6637416fea7c29a522dea024d4adaaa29b6d472b4d2cc3e3b85c72e2a +afc35f5a03b245a6286318ef489db05d397bbd16c17b4e92eeb56509f875246c0176c01804139eb67dc4247c2a36ff9e +99ba14ab5a9612c078f9bbaa0e68fd1d52ecceb2ed19bd9abf8f98dd4ed1f9c4fa6e4d41bcef69be2ff020b291749ca8 +8018cdd3d96f331b4c470a4c3904bed44cadecbeec2544ca10e4352cf4ae1a856cf55f6383d666bf997ad3e16816006e +a9964790c318bb07b8fe61d230dd2161dd3160e186004647a925cfec4c583b4e33530bf5d93d8a14338b090055085b05 +ab89d8401df722101c2785cb3ef833017f58376ee82cedd3e9405b2534f259bb76063434a247652c7615a6de5194de65 +a72c3d320a0d40936dee8edfb36703be633aefbb8f89530df04eb6aebe0305ef4f4b6709436f8036d417272a7e47e22a +b3457661ad62634cc25e2918921a97b0bf5c59ccc7063bc8eb53194783f07659f42f8978c589228af5b12696588d8b2f +926fa35cd3ed4c8ad78af6284b87ae53b2e25a1ff50398034142a2bbed5b989ba3181ff116838931742c0fbcd8b8a56c +ae57fe506626432f27ae4f8791421c2df9efd9aaabe4b840ccf65fc3d0dd2f83e19eb63ae87bfa6898d37b5da869ddb2 +99c0a26ac74211db77918156d7ae9bea6ecf48da3ce9e53829a9ad5ed41321227c94fbd7449ae2e44aae801811552b1b +abdd2635b61cb948e51b762a256cf9d159b9fcb39b2fb11ba2fed1cb53475a03fc6e024a6a824a67a689396119a36a7b +a5ca98b98da8bb8eb07b1e5e3c85a854db42addefacd141771a0c63a8e198421dccc55ef1d94662ca99a7d83b9173fc3 +a821bb5cf1eb3aeae6318c8d554e2ea3137d73bb29d2e4450c9a33f441355ea77bb0e0e0ce7c819abc3ed119110a3a92 +95cdfb19b3f7196c26d60586e2c1efaa93352a712f8c8ef6209f6f318cecd52d7bebdfbfee4be1f5903a1595f73bc985 +aef6e6a400106e217f9888afcef0a1e1299b59017e77dc5453317dec0c32ae96873608bef3f1b504a7e4f45b06edc9c6 +96399ad093299ba26dc09ae85dbec9a1801dea4a338dd5d578bcdcb91246db0059e54098ba8a56cbb24600a40095cf79 +ad8b018ac99857ad4b38bdf6d110bbef64029a4d9f08df85a278c6ddc362a5f64e1f3a919f798ccb2f85a7f4ca1260b4 +b211f3b5dd91941d119c4fe05e2b4c7bb0ce0a8d7ef05932a96e850f549a78cd20cded0b3adb3f9f8b7058889ae2cb4e +ab780dd363671765c9c9ab0f4e7096aacf5894e042b75f40a92df8eb272a6229078cd6eadcc500eead3650860aa82177 +a4d96b16ab3abe77ead9b4477c81957e66a028f95557e390352743da53d1a7ba0c81d928a7ea8bc03b9900135ac36a6a +b4d4e028099bf0f28ac32141cd8de4ee7c3d62d4f519fad6abbb4ba39592750812220a4167d1da4c4f46df965f7cf43d +aa929c5f0bd8cb44a861bfb3d18340a58c61d82afa642447b71b1470a7b99fe3d5796bdd016b121838cb3594f5a92967 +a038e66f0a28aba19d7079643788db3eed8e412fb9ab4c0f6cacf438af4657cc386a7c22ae97ccc8c33f19a572d6431c +89c1ff879faa80428910e00b632d31c0cebb0c67e8f5ded333d41f918032282fb59fbcbe26d3156592f9692213667560 +8d899072c9d30e27065d73c79ce3130a09b6a4a4c7d9c4e4488fda4d52ad72bd5f1fd80f3a8936ef79cf362a60817453 +8ffb84a897df9031f9a8e7af06855180562f7ca796489b51bb7cca8d0ca1d9766a4de197a3eb7e298b1dfb39bc6e9778 +836ebd0b37e7ef4ff7b4fc5af157b75fa07a2244045c3852702eaafa119ca1260c654a872f1b3708b65671a2ece66ad2 +9292dfd6d5bfc95f043f4eb9855c10cbcf90fbd03e7a256c163749b23a307b46a331bdbd202236dca0e8ea29e24906de +8bc37eaa720e293e32b7986061d2ffcbd654d8143e661aabe5602adc832ab535cffbe12a7b571d423675636a74b956e4 +887455f368515340eb6f9b535f16a1cf3e22f0ceda2ead08c5caefccef4087e9f4b5d61c5b110ff3e28e4ab2ad9e97c5 +a6e5ec36e7712056fec00de15b8696952b17891e48ebe2fa90c6f782c7d927b430917b36b4a25b3d8466da3ca2a4985d +895cae36ba786104ec45740c5dc4f2416b2adce6e806815e3994e98d9e1be372eaec50094fbb7089015684874631ab7e +9687444fe6250c246b1711a8f73992f15c3cac801e79c54ffd5e243ad539fdd98727043e4f62d36daf866750de1ba926 +b17f75044c8e9ce311bb421a5427006b6fa1428706d04613bd31328f4549decd133e62f4b1917016e36eb02ea316a0ca +8538a84d2f9079dd272a7383ff03b7674f50b9c220e0399c794a2bcb825d643d0fc8095d972d5186b6f0fe9db0f7084f +af07b37644cc216e7083bac1c4e6095fa898f3417699df172c1f6e55d6c13c11f5279edd4c7714d65360b5e4c3c6731e +87eed8fe7486c0794884c344c07d3964f8fc065aebb0bb3426506ab879b2e0dfaefa5cece213ec16c7b20e6f946c0bd2 +8a4bf42f141d8bc47c9702779d692a72752510ef38e290d36f529f545a2295082a936c8420f59d74b200a8fff55167c4 +a7170e5e00a504a3b37cb19facf399c227497a0b1e9c8a161d541cb553eb8211449c6ac26fe79a7ff7b1c17f33591d74 +a9a2cc7232f07ef9f6d451680648f6b4985ecab5db0125787ac37280e4c07c8210bab254d0b758fd5e8c6bcf2ee2b9ff +8908d82ebfa78a3de5c56e052d9b5d442af67a510e88a76ba89e4919ae1620c5d15655f663810cfc0ee56c256a420737 +a9d47f3d14047ca86c5db9b71f99568768eaa8a6eb327981203fdb594bdb0a8df2a4a307f22dcea19d74801f4648ea89 +a7c287e0e202ebfc5be261c1279af71f7a2096614ee6526cd8b70e38bb5b0b7aca21a17140d0eddea2f2b849c251656a +97807451e61557d122f638c3f736ab4dab603538396dca0fcdf99f434a6e1f9def0521816b819b1c57ecdfa93bd077eb +a8486d60742446396c9d8bc0d4bed868171de4127e9a5a227f24cbf4efbbe5689bbd38f2105498706a6179340b00aed5 +a03b97c2a543dfefa1deb316db9316191ab14e3dd58255ce1027b4e65060d02fb5cb0d6ac1a2bf45bfeac72537b26429 +a7d25060f6861873410c296a4959a058174e9a1681ac41770788191df67fc1391545dab09de06b56cd73a811b676aa1b +96bb9c9aa85d205e085434d44f5021d8bbafc52cd2727b44e2a66094a4e5467b6294d24146b54c0d964c711e74a258d4 +b07b17f11267e577191e920fa5966880f85ff7089ac59d5d550e46f3a5cdadd94f438a547cd1ec66f20a447e421f96c6 +964e33e1571c97088fe7c8ca3430db60a8119f743a47aa0827e6e2fb9bae5ff3bf6cecd17b11dd34628546b6eb938372 +82a0513a05870b96509a559164e6ff26988ea8a2227ac6da9adc96fe793485a9eb6bdcab09afac7be4aef9a5ae358199 +b1185bc679623e7a37a873d90a2a6393fb5ccc86e74ba4ba6f71277df3623cde632feae4414d6429db6b4babde16dee0 +b3d77504b7032b5593a674d3c0cd2efbf56b2b44ed7fe8669f752828045e4e68202a37bf441f674b9c134886d4cee1df +95ab31749ff1f7b3f165ce45af943c6ed1f1071448c37009643a5f0281875695c16c28fc8d8011a71a108a2d8758e57d +b234dee9c56c582084af6546d1853f58e158549b28670b6783b4b5d7d52f00e805e73044a8b8bd44f3d5e10816c57ecc +86da5d2343f652715c1df58a4581e4010cf4cbe27a8c72bb92e322152000d14e44cc36e37ff6a55db890b29096c599b9 +8b7be904c50f36453eff8c6267edcb4086a2f4803777d4414c5c70c45b97541753def16833e691d6b68d9ef19a15cb23 +b1f4e81b2cdb08bd73404a4095255fa5d28bcd1992a5fd7e5d929cfd5f35645793462805a092ec621946aaf5607ef471 +a7f2ca8dacb03825ef537669baff512baf1ea39a1a0333f6af93505f37ed2e4bbd56cb9c3b246810feee7bacdf4c2759 +996d0c6c0530c44c1599ffdf7042c42698e5e9efee4feb92f2674431bbddf8cf26d109f5d54208071079dfa801e01052 +b99647e7d428f3baa450841f10e2dc704ce8125634cc5e7e72a8aa149bf1b6035adce8979a116a97c58c93e5774f72b7 +95960a7f95ad47b4a917920f1a82fbbecd17a4050e443f7f85b325929c1e1f803cf3d812d2cedeab724d11b135dde7a3 +8f9cd1efdf176b80e961c54090e114324616b2764a147a0d7538efe6b0c406ec09fd6f04a011ff40e0fa0b774dd98888 +b99431d2e946ac4be383b38a49b26e92139b17e6e0f0b0dc0481b59f1ff029fb73a0fc7e6fff3e28d7c3678d6479f5a3 +a888887a4241ce156bedf74f5e72bfa2c6d580a438e206932aefc020678d3d0eb7df4c9fe8142a7c27191837f46a6af6 +ab62224ea33b9a66722eb73cfd1434b85b63c121d92e3eebb1dff8b80dd861238acf2003f80f9341bfea6bde0bfcd38c +9115df3026971dd3efe7e33618449ff94e8fd8c165de0b08d4a9593a906bbed67ec3ed925b921752700f9e54cd00b983 +95de78c37e354decd2b80f8f5a817d153309a6a8e2f0c82a9586a32051a9af03e437a1fb03d1b147f0be489ef76b578b +a7b8a6e383de7739063f24772460e36209be9e1d367fe42153ffe1bccb788a699e1c8b27336435cd7bf85d51ba6bfdd6 +937a8af7ed18d1a55bf3bbe21e24363ae2cb4c8f000418047bf696501aaeec41f2ddf952fd80ef3373f61566faa276a9 +ab5e4931771aeb41c10fa1796d6002b06e512620e9d1c1649c282f296853c913f44e06e377a02f57192b8f09937282eb +893d88009754c84ec1c523a381d2a443cb6d3879e98a1965e41759420a088a7582e4d0456067b2f90d9d56af4ea94bba +91b2388a4146ebaaa977fec28ffbfb88ac2a1089a8a258f0451c4152877065f50402a9397ba045b896997208b46f3ebf +8ce0523192e4cc8348cd0c79354a4930137f6f08063de4a940ea66c0b31d5ea315ce9d9c5c2ec4fa6ee79d4df83840dd +b72f75c4ab77aca8df1a1b691b6ef1a3ff1c343dd9ed48212542e447d2ed3af3017c9ad6826991e9ef472348c21b72a4 +af0fa5a960f185326877daf735ad96c6bd8f8f99ab0ab22e0119c22a0939976ece5c6a878c40380497570dc397844dba +adf9f41393e1196e59b39499623da81be9f76df047ae2472ce5a45f83871bb2a0233e00233b52c5c2fa97a6870fbab0a +8d9fc3aecd8b9a9fca8951753eea8b3e6b9eb8819a31cca8c85a9606ce1bd3885edb4d8cdbc6f0c54449c12927285996 +901969c1d6cac2adcdc83818d91b41dc29ef39c3d84a6f68740b262657ec9bd7871e09b0a9b156b39fa62065c61dacb1 +9536a48ccd2c98f2dcbff3d81578bbb8f828bf94d8d846d985f575059cd7fb28dfa138b481d305a07b42fcb92bacfa11 +8d336654833833558e01b7213dc0217d7943544d36d25b46ecc1e31a2992439679205b5b3ab36a8410311109daa5aa00 +95113547163e969240701e7414bf38212140db073f90a65708c5970a6aaf3aba029590a94839618fc3f7dd4f23306734 +a959d77a159b07b0d3d41a107c24a39f7514f8ce24efa046cfcf6ace852a1d948747f59c80eb06277dce1a2ba2ec8ea9 +8d2cb52dd7f5c56ef479c0937b83b8519fa49eb19b13ea2ec67266a7b3d227fb8d0c2454c4618d63da1c8e5d4171ac7b +9941698c5078936d2c402d7db6756cc60c542682977f7e0497906a45df6b8d0ffe540f09a023c9593188ba1b8ce6dfcb +9631d9b7ec0fc2de8051c0a7b68c831ba5271c17644b815e8428e81bad056abb51b9ca2424d41819e09125baf7aaf2d4 +a0f3d27b29a63f9626e1925eec38047c92c9ab3f72504bf1d45700a612682ad4bf4a4de41d2432e27b745b1613ff22f9 +80e3701acfd01fc5b16ecfa0c6c6fd4c50fe60643c77de513f0ad7a1a2201e49479aa59056fd6c331e44292f820a6a2c +a758c81743ab68b8895db3d75030c5dd4b2ccc9f4a26e69eb54635378a2abfc21cba6ca431afb3f00be66cffba6ab616 +a397acb2e119d667f1ab5f13796fd611e1813f98f554112c4c478956c6a0ebaceef3afae7ee71f279277df19e8e4543a +a95df7d52b535044a7c3cf3b95a03bafd4466bdb905f9b5f5290a6e5c2ac0f0e295136da2625df6161ab49abcdacb40f +8639fc0c48211135909d9e999459568dbdbbc7439933bab43d503e07e796a1f008930e8a8450e8346ab110ec558bcbb9 +a837bcc0524614af9e7b677532fabfb48a50d8bec662578ba22f72462caabda93c35750eed6d77b936636bf165c6f14e +97d51535c469c867666e0e0d9ed8c2472aa27916370e6c3de7d6b2351a022e2a5330de6d23c112880b0dc5a4e90f2438 +aadb093c06bd86bd450e3eb5aa20f542d450f9f62b4510e196f2659f2e3667b0fe026517c33e268af75a9c1b2bc45619 +860cef2e0310d1a49a9dd6bc18d1ca3841ed1121d96a4f51008799b6e99eb65f48838cd1e0c134f7358a3346332f3c73 +b11c4f9e7ef56db46636474a91d6416bcb4954e34b93abf509f8c3f790b98f04bd0853104ec4a1ff5401a66f27475fce +87cb52e90a96c5ee581dc8ab241e2fd5df976fe57cc08d9ffda3925a04398e7cffaf5a74c90a7319927f27c8a1f3cef5 +b03831449f658a418a27fd91da32024fdf2b904baf1ba3b17bbf9400eaddc16c3d09ad62cc18a92b780c10b0543c9013 +94e228af11cb38532e7256fa4a293a39ffa8f3920ed1c5ad6f39ce532e789bb262b354273af062add4ca04841f99d3aa +99eb3aeb61ec15f3719145cf80501f1336f357cc79fca6981ea14320faed1d04ebe0dbce91d710d25c4e4dc5b6461ebf +920a3c4b0d0fbe379a675e8938047ea3ec8d47b94430399b69dd4f46315ee44bd62089c9a25e7fa5a13a989612fe3d09 +b6414a9a9650100a4c0960c129fa67e765fe42489e50868dd94e315e68d5471e11bfbc86faffb90670e0bec6f4542869 +94b85e0b06580a85d45e57dae1cfd9d967d35bdfcd84169ef48b333c9321f2902278c2594c2e51fecd8dbcd221951e29 +b2c0a0dd75e04a85def2a886ee1fda51f530e33b56f3c2cf61d1605d40217aa549eef3361d05975d565519c6079cc2ac +abb0ea261116c3f395360d5ac731a7514a3c290f29346dc82bacb024d5455d61c442fefe99cc94dddcae47e30c0e031f +a32d95ae590baa7956497eddf4c56bff5dfdc08c5817168196c794516610fcc4dbcd82cf9061716d880e151b455b01e0 +8bd589fb6e3041f3ef9b8c50d29aed1a39e90719681f61b75a27489256a73c78c50c09dd9d994c83f0e75dfe40b4de84 +82d01cdaf949d2c7f4db7bfadbf47e80ff9d9374c91512b5a77762488308e013689416c684528a1b16423c6b48406baf +b23e20deb7e1bbbc328cbe6e11874d6bdbb675704a55af1039b630a2866b53d4b48419db834a89b31ebed2cfc41278dd +a371559d29262abd4b13df5a6a5c23adab5a483f9a33a8d043163fcb659263322ee94f872f55b67447b0a488f88672d6 +85b33ddf4a6472cacc0ed9b5ec75ed54b3157e73a2d88986c9afa8cb542e662a74797a9a4fec9111c67e5a81c54c82b3 +af1248bc47a6426c69011694f369dc0ec445f1810b3914a2ff7b830b69c7e4eaa4bafec8b10ed00b5372b0c78655a59b +94b261ed52d5637fd4c81187000bd0e5c5398ce25797b91c61b30d7b18d614ab9a2ca83d66a51faf4c3f98714e5b0ea5 +953d4571c1b83279f6c5958727aaf9285d8b8cbdbfbaff51527b4a8cfdd73d3439ba862cdb0e2356e74987ff66d2c4d9 +b765dae55d0651aca3b3eaef4ca477f0b0fda8d25c89dccd53a5573dd0c4be7faaadaa4e90029cdd7c09a76d4ce51b91 +b6d7b7c41556c85c3894d0d350510b512a0e22089d3d1dd240ad14c2c2b0ce1f003388100f3154ad80ec50892a033294 +a64561dc4b42289c2edf121f934bc6a6e283d7dce128a703f9a9555e0df7dda2825525dbd3679cd6ba7716de230a3142 +a46c574721e8be4a3b10d41c71057270cca42eec94ca2268ee4ab5426c7ce894efa9fa525623252a6a1b97bcf855a0a5 +a66d37f1999c9c6e071d2a961074c3d9fdcf9c94bf3e6c6ed82693095538dd445f45496e4c83b5333b9c8e0e64233adc +ab13814b227a0043e7d1ff6365360e292aca65d39602d8e0a574d22d25d99ccb94417c9b73095632ff302e3d9a09d067 +b2c445b69cff70d913143b722440d2564a05558d418c8ef847483b5196d7e581c094bae1dbb91c4499501cfa2c027759 +87cbde089962d5f093324b71e2976edbe6ad54fb8834dd6e73da9585b8935fca1c597b4d525949699fdfa79686721616 +a2c7e60966acb09c56cf9ad5bdcc820dcabf21ef7784970d10353048cf3b7df7790a40395561d1064e03109eaac0df98 +8ea7b8af208678178553946b2ee9e68c0e751b34f3652409a5e66c40d3aee3a40ba6ffe2175ce16c6a81b78ecc597d02 +960234239e1e3ea262e53d256ad41b2fe73f506b3d130732d0ee48819eb8a9c85bb5106a304874d8625afae682c34015 +858459694c4e8fdafa6cdaee1184e1305ca6e102222b99b8e283dd9bb3ebf80e55d6c4d8831a072b813c8eceb8124d95 +a30a8ce0f44aeb5590dc618c81c7cac441470ce79fd7881a8f2ea4ca5f9d848ebde762fcaee985cbd3d5990367403351 +a83867643672248b07d3705813b56489453e7bc546cdba570468152d9a1bd04f0656034e7d03736ea156fc97c88dc37f +a7bb52e0fc58b940dc47ea4d0a583012ee41fad285aba1a60a6c54fa32cfe819146888c5d63222c93f90de15745efb2b +8627bcc853bdeaad37f1d0f7d6b30ada9b481ccdf79b618803673de8a142e8a4ce3e7e16caed1170a7332119bcdc10a9 +8903d9dc3716b59e8e99e469bd9fde6f4bca857ce24f3a23db817012f1ea415c2b4656c7aeca31d810582bb3e1c08cc6 +875169863a325b16f892ad8a7385be94d35e398408138bd0a8468923c05123d53dba4ce0e572ea48fcdadd9bd9faa47a +b255b98d46d6cc44235e6ce794cc0c1d3bd074c51d58436a7796ce6dc0ae69f4edaa3771b35d3b8a2a9acd2f6736fab3 +9740c4d0ee40e79715a70890efda3455633ce3a715cbfc26a53e314ebbe61937b0346b4859df5b72eb20bcba96983870 +a44ce22ab5ddc23953b02ec187a0f419db134522306a9078e1e13d5bf45d536450d48016a5e1885a346997003d024db0 +90af81c08afdccd83a33f21d0dc0305898347f8bd77cc29385b9de9d2408434857044aec3b74cb72585338c122e83bb4 +80e162a7656c9ae38efa91ae93e5bd6cb903f921f9f50874694b9a9e0e2d2595411963d0e3f0c2d536b86f83b6e4d6ef +8b49fa6babe47291f9d290df35e94e83be1946784b9c7867efd8bc97a12be453013939667164b24aeb53d8950288a442 +a1df6435d718915df3da6dda61da1532a86e196dc7632703508679630f5f14d4cb44ce89eff489d7ff3fe599cc193940 +afd44c143dbb94c71acc2a309c9c88b8847ef45d98479fccce9920db9b268e8e36f8db9f02ff4ee3cff01e548f719627 +b2cf33d65d205e944b691292c2d9b0b124c9de546076dd80630742989f1ffd07102813c64d69ba2a902a928a08bce801 +b9f295e9f9eca432b2d5c77d6316186027caca40a6d6713f41356497a507b6e8716fb471faf973aaa4e856983183c269 +b3bd50c4b034473edce4b9be1171376a522899cb0c1a1ae7dc22dd2b52d20537cf4129797235084648ac4a3afc1fa854 +8ef37683d7ca37c950ba4df72564888bedaf681931d942d0ea88ead5cc90f4cbef07985a3c55686a225f76f7d90e137d +82107855b330bc9d644129cebecf2efbfab90f81792c3928279f110250e727ce12790fd5117501c895057fa76a484fc0 +816a5474c3b545fb0b58d3118cc3088a6d83aad790dbf93025ad8b94a2659cceba4fa6a6b994cb66603cc9aef683a5e3 +8f633f9b31f3bb9b0b01ea1a8830f897ecd79c28f257a6417af6a5f64e6c78b66c586cf8d26586830bd007fb6279cd35 +acb69d55a732b51693d4b11f7d14d21258d3a3af0936385a7ce61e9d7028a8fe0dd902bda09b33fb728bc8a1bc542035 +8d099582ac1f46768c17bf5a39c13015cfe145958d7fc6ddfd2876ad3b1a55a383fbe940e797db2b2b3dc8a232f545dc +97a4dd488b70bf772348ececaca4cf87bc2875d3846f29fe6ef01190c5b030219b9e4f8137d49ea0cc50ca418024c488 +b4d81148f93fa8ec0656bbfb5f9d96bbf5879fa533004a960faac9fd9f0fe541481935fdf1f9b5dd08dff38469ef81c5 +8e9b2ae4fc57b817f9465610a77966caaff013229018f6c90fa695bd734cb713b78a345b2e9254b1aff87df58c1cd512 +99eb7126e347c636e9a906e6bfdc7c8ca0c1d08580c08e6609889a5d515848c7ca0f32ab3a90c0e346f976a7883611f7 +8ca87944aa3e398492b268bda0d97917f598bc0b28584aa629dfec1c3f5729d2874db422727d82219880577267641baa +88ab0e290dc9a6878d6b4e98891ff6bfc090e8f621d966493fcbe1336cc6848fcbb958d15abcfa77091d337da4e70e74 +8956a2e1dc3ec5eb21f4f93a5e8f0600a06e409bb5ec54e062a1290dff9ce339b53fbbfc4d42b4eed21accea07b724d6 +8d22220da9dc477af2bddb85c7073c742c4d43b7afee4761eba9346cadbcd522106ed8294281a7ef2e69883c28da0685 +90dafd9a96db7e1d6bde424245305c94251d5d07e682198ae129cd77bd2907a86d34722cbde06683cc2ca67cebe54033 +b5202e62cf8ea8e145b12394bd52fd09bda9145a5f78285b52fda4628c4e2ccfc2c208ecde4951bd0a59ac03fa8bc202 +8959856793ba4acf680fb36438c9722da74d835a9fe25a08cf9e32d7800c890a8299c7d350141d2e6b9feceb2ebb636f +ab0aa23c1cd2d095825a3456861871d298043b615ae03fcd9283f388f0deef3cc76899e7fde15899e3edf362b4b4657f +9603b333cc48fe39bea8d9824cfee6ac6c4e21668c162c196ecd1ff08ef4052ace96a785c36b8f7906fdcb6bc8802ddd +93bfecbc3c7cc03c563240e109850a74948f9fa078eb903b322368cda0b50888663a17953579578ba060b14dbf053024 +b01f843b808cf7939a474de155a45462e159eb5044f00c6d77e0f7ec812720a3153209e971a971ccbf5ebee76ec4074f +b009e0567c3c75ed767247d06fa39049a4d95df3392d35a9808cb114accf934e78f765cd18a2290efef016f1918c7aeb +ad35631df8331da3a12f059813dfa343d831225a392f9c7e641c7d23a6c1ad8df8e021201c9f6afb27c1575948d6bf68 +a89c2a631d84128471c8ef3d24b6c35c97b4b9b5dad905c1a092fb9396ae0370e215a82308e13e90e7bb6ebcc455eb2a +b59c7f5fbfeb02f8f69e6cedef7ff104982551f842c890a14834f5e834b32de1148cf4b414a11809d53dd3f002b15d6a +aa6f267305b55fede2f3547bc751ba844ce189d0b4852022712b0aee474de54a257d4abcd95efe7854e33a912c774eba +afddd668f30cce70904577f49071432c49386ec27389f30a8223b5273b37e6de9db243aceb461a7dc8f1f231517463a9 +b902a09da9157b3efa1d98f644371904397019d0c84915880628a646a3ad464a9d130fdc651315098179e11da643ad2e +b05f31957364b016c6f299ae4c62eede54cab8ea3871d49534828c8bdc6adbc6a04a708df268f50107d81d1384d983ae +b4c3f7284802e614ddf1f51640f29e7139aae891467d5f62778310372071793e56fbd770837b97d501191edd0da06572 +b4eddb7c3775fb14fac7f63bb73b3cde0efa2f9a3b70e6a65d200765f6c4b466d3d76fcd4d329baee88e2aba183b8e69 +a83e7dbae5a279f0cfd1c94e9849c58a3d4cecc6d6d44bb9b17508576ca347fca52c2c81371d946b11a09d4ed76ec846 +8018ea17e2381c0233867670f9e04c8a47ace1207fdcf72dce61b6c280ba42d0a65f4b4e0b1070cc19c7bb00734974d9 +af90b541dfed22e181ff3ef4cf11f5e385fd215c1e99d988e4d247bc9dcee9f04f2182b961797c0bcc5f2aaa05c901a9 +a37046e44cf35944e8b66df80c985b8a1aa7004a2fd0b81ac251638977d2ff1465f23f93ac0ce56296f88fdc591bbdd7 +a735bd94d3be9d41fcd764ec0d8d7e732c9fc5038463f7728fd9d59321277e2c73a45990223bd571dab831545d46e7aa +94b32dcb86f5d7e83d70a5b48fe42c50f419be2f848f2d3d32ee78bf4181ab18077a7666eedb08607eece4de90f51a46 +a7f0804cafbf513293485afc1b53117f0cbfaea10919e96d9e4eb06f0c96535e87065d93f3def1bbc42044dbb00eb523 +aaaad1166d7f19f08583dd713275a71a856ab89312f84ca8078957664924bb31994b5c9a1210d0c41b085be4058ed52e +a1757aac9f64f953e68e680985a8d97c5aac8688b7d90f4db860166dd3d6119e8fca7d700a9530a2b9ba3932c5e74e33 +98cada5db4a1430c272bfc1065fb685872e664ed200d84060ee9f797d0a00864f23943e0fb84ba122a961996a73dfb14 +a5e609f716dc7729d1247f40f9368a2e4a15067e1dd6a231fece85eeefb7e7d4a5ac8918fb376debd79d95088750b2ca +b5365eb8caab8b1118619a626ff18ce6b2e717763f04f6fa8158cdca530c5779204efa440d088083f1a3685454aa0555 +a6e01b8da5f008b3d09e51a5375d3c87c1da82dff337a212223e4d0cdb2d02576d59f4eef0652d6b5f2fc806d8c8149c +ae310f613d81477d413d19084f117248ad756572c22a85b9e4c86b432e6c602c4a6db5edf2976e11f7353743d679e82a +a1f219c0b8e8bb8a9df2c6c030acbb9bbfa17ba3db0366f547da925a6abb74e1d7eb852bd5a34bae6ac61d033c37e9dc +a2087fa121c0cdd5ea495e911b4bc0e29f1d5c725aadfb497d84434d2291c350cdaa3dc8c85285f65a7d91b163789b7a +929c63c266da73d726435fa89d47041cfe39d4efa0edce7fc6eca43638740fbc82532fd44d24c7e7dd3a208536025027 +91c1051dcc5f52ad89720a368dddd2621f470e184e746f5985908ba34e1d3e8078a32e47ab7132be780bea5277afecb0 +ae089b90ba99894d5a21016b1ea0b72a6e303d87e59fb0223f12e4bb92262e4d7e64bfdbdb71055d23344bc76e7794b2 +8b69aa29a6970f9e66243494223bad07ac8f7a12845f60c19b1963e55a337171a67bdc27622153016fce9828473a3056 +95ca6b08680f951f6f05fd0d180d5805d25caf7e5bda21c218c1344e661d0c723a4dfc2493642be153793c1b3b2caaa4 +a4789dc0f2a07c794dab7708510d3c893d82ddbd1d7e7e4bbbeca7684d9e6f4520fb019b923a06c7efab0735f94aa471 +93c4f57a3cf75085f5656b08040f4cd49c40f1aab6384a1def4c5c48a9fe4c03514f8e61aabe2cfa399ff1ccac06f869 +b6c37f92c76a96b852cd41445aa46a9c371836dd40176cc92d06666f767695d2284a2780fdfd5efc34cf6b18bcfb5430 +9113e4575e4b363479daa7203be662c13d7de2debcda1c142137228aeead2c1c9bc2d06d93a226302fa63cc75b7353ec +b70addeb5b842ac78c70272137f6a1cef6b1d3a551d3dd906d9a0e023c8f49f9b6a13029010f3309d0b4c8623a329faf +b976a5132b7eb42d5b759c2d06f87927ef66ecd6c94b1a08e4c9e02a4ce7feca3ac91f9479daa1f18da3d4a168c2ba77 +8fdab795af64b16a7ddf3fad11ab7a85d10f4057cf7716784184960013baa54e7ba2050b0e036dc978ff8c9a25dc5832 +b2c982ad13be67d5cdc1b8fac555d4d1ec5d25f84e58b0553a9836f8f9e1c37582d69ad52c086a880a08b4efcccd552e +810661d9075ae6942735215f2ab46d60763412e1f6334e4e00564b6e5f479fc48cf37225512abbccf249c0ca225fc935 +a0c4bf00a20f19feff4004004f08231b4c6c86ac4ed57921eea28d7dea32034f3f4ab5b7ded7184f6c7ffbf5847232ad +b2bb5a9eea80bf067f3686a488529d9c2abd63fc9e1d4d921b1247ef86d40cd99e0a8b74f750e85c962af84e84e163a6 +887ee493c96d50f619ba190ce23acddc5f31913e7a8f1895e6339d03794ecefd29da5f177d1d25bc8df8337ae963fc7b +b7966fb07029d040f2228efa2cfcd04341e4666c4cf0b653e6e5708631aa2dd0e8c2ac1a62b50c5a1219a2737b82f4f7 +92234cfd6b07f210b82db868f585953aafbcbc9b07b02ded73ff57295104c6f44a16e2775ca7d7d8ee79babb20160626 +8d3cd7f09c6fd1072bc326ff329e19d856e552ac2a9f20274bc9752527cd3274142aa2e32b65f285fb84bc3adaaea3cc +8caed1cb90d8cd61e7f66edc132672172f4fa315e594273bb0a7f58a75c30647ec7d52eda0394c86e6477fbc352f4fe8 +ae192194b09e9e17f35d8537f947b56f905766c31224e41c632c11cd73764d22496827859c72f4c1ab5fd73e26175a5d +8b7be56aac76d053969e46882d80a254e89f55c5ab434883cbafc634a2c882375898074a57bc24be3c7b2c56401a7842 +98bc4a7a9b05ba19f6b85f3ee82b08bed0640fd7d24d4542eb7a7f7fde443e880bdb6f5499bd8cb64e1ddd7c5f529b19 +a5a41eaa5e9c1d52b00d64ab72bc9def6b9d41972d80703e9bfe080199d4e476e8833a51079c6b0155b78c3ab195a2a7 +a0823f6f66465fd9be3769c164183f8470c74e56af617f8afd99b742909d1a51f2e0f96a84397597afbd8eeaabb51996 +801da41d47207bdd280cc4c4c9753a0f0e9d655e09e0be5f89aeed4ce875a904f3da952464399bf8efc2398940d5fba2 +a719314085fd8c9beac4706c24875833d59a9a59b55bca5da339037c0a5fc03df46dbecb2b4efcfed67830942e3c4ea1 +a75dde0a56070bb7e9237b144ea79f578d413a1cbbd1821cee04f14f533638b24f46d88a7001e92831843b37ed7a709f +a6b4ef8847a4b980146e1849e1d8ab38695635e0394ca074589f900ce41fa1bb255938dc5f37027523bac6a291779bef +b26d84dfd0b7bd60bcfdbea667350462a93dca8ff5a53d6fc226214dcb765fada0f39e446a1a87f18e4e4f4a7133155f +ae7bd66cc0b72f14ac631ff329a5ca4958a80ba7597d6da049b4eb16ac3decde919ca5f6f9083e6e541b303fb336dc2f +a69306e6bfbbc10de0621cffb13c586e2fcfd1a80935e07c746c95651289aec99066126a6c33cb8eb93e87d843fc631f +a47e4815585865218d73c68ba47139568ea7ae23bfa863cb914a68454242dd79beaec760616b48eea74ceab6df2298dd +b2da3cfb07d0721cd226c9513e5f3ace98ed2bc0b198f6626b8d8582268e441fa839f5834f650e2db797655ca2afa013 +b615d0819554f1a301a704d3fc4742bd259d04ad75d50bccee3a949b6226655f7d623301703506253cca464208a56232 +85e06ed5797207f0e7ae85909e31776eb9dae8af2ec39cc7f6a42843d94ea1de8be2a3cdadfcbe779da59394d4ffeb45 +8c3529475b5fdbc636ee21d763f5ec11b8cb040a592116fb609f8e89ca9f032b4fa158dd6e9ceab9aceb28e067419544 +accddb9c341f32be82b6fa2ef258802c9ae77cd8085c16ec6a5a83db4ab88255231b73a0e100c75b7369a330bfc82e78 +93b8e4c6e7480948fa17444b59545a5b28538b8484a75ad6bc6044a1d2dbd76e7c44970757ca53188d951dc7347d6a37 +90111721d68b29209f4dc4cfb2f75ab31d15c55701922e50a5d786fb01707ab53fcec08567cd366362c898df2d6e0e93 +b60a349767df04bd15881c60be2e5cc5864d00075150d0be3ef8f6b778715bebca8be3be2aa9dbdc49f1a485aeb76cda +b8d5a967fdd3a9bcf89a774077db39ef72ca9316242f3e5f2a350202102d494b2952e4c22badecd56b72ba1eea25e64b +8499ebd860f31f44167183b29574447b37a7ee11efcc9e086d56e107b826b64646b1454f40f748ccac93883918c89a91 +99c35e529782db30f7ccab7f31c225858cf2393571690b229ece838ec421a628f678854a1ddbd83fa57103ccebd92c7f +99817660d8b00cbe03ec363bcdc5a77885586c9e8da9e01a862aca0fc69bf900c09b4e929171bc6681681eae10450541 +8055e130964c3c2ebd980d3dc327a40a416bcdbf29f480480a89a087677a1fb51c823b57392c1db72f4093597100b8d3 +877eaddef845215f8e6f9ed24060c87e3ab6b1b8fbb8037d1a57e6a1e8ed34d00e64abb98d4bf75edb5c9788cbdccbef +b5432bbff60aeae47f2438b68b123196dfb4a65cc875b8e080501a4a44f834b739e121bec58d39ac36f908881e4aa8ab +b3c3f859b7d03ff269228c0f9a023b12e1231c73aba71ad1e6d86700b92adc28dfa3757c052bbc0ba2a1d11b7fda4643 +ab8a29f7519a465f394ef4a5b3d4924d5419ca1489e4c89455b66a63ac430c8c9d121d9d2e2ed8aa1964e02cd4ebac8c +866ae1f5c2a6e159f2e9106221402d84c059f40d166fab355d970773189241cd5ee996540d7c6fc4faf6f7bcff967dce +973a63939e8f1142a82b95e699853c1e78d6e05536782b9bb178c799b884f1bc60177163a79a9d200b5ff4628beeb9e7 +a5fc84798d3e2d7632e91673e89e968f5a67b7c8bb557ea467650d6e05e7fe370e18d9f2bdd44c244978295cf312dc27 +b328fe036bcd0645b0e6a15e79d1dd8a4e2eda128401a4e0a213d9f92d07c88201416fc76193bb5b1fe4cb4203bab194 +99239606b3725695a570ae9b6fb0fb0a34ad2f468460031cfa87aa09a0d555ff606ff204be42c1596c4b3b9e124b8bd6 +af3432337ca9d6cce3574e23e5b7e4aa8eda11d306dc612918e970cc7e5c756836605a3391f090a630bac0e2c6c42e61 +8a545b3cb962ce5f494f2de3301de99286c4d551eaa93a9a1d6fef86647321834c95bf754c62ec6c77116a21494f380d +8f9b8ea4c25469c93556f1d91be583a5f0531ac828449b793ba03c0a841c9c73f251f49dd05cbb415f5d26e6f6802c99 +a87199e33628eeffd3aff114e81f53dd54fba61ba9a9a4d7efdbff64503f25bc418969ab76ef1cf9016dd344d556bb29 +a2fda05a566480602274d7ffcaefdd9e94171286e307581142974f57e1db1fa21c30be9e3c1ac4c9f2b167f92e7c7768 +a6235d6a23304b5c797efb2b476ed02cb0f93b6021a719ae5389eb1e1d032944ae4d69aec2f29fcd6cbc71a6d789a3ba +a7f4a73215f7e99e2182c6157dd0f22e71b288e696a8cff2450689a3998f540cfb82f16b143e90add01b386cb60d8a33 +922d8f9cd55423f5f6a60d26de2f8a396ac4070a6e2dc956e50c2a911906aa364d4718aea29c5b61c12603534e331e7e +96d7fdf5465f028fc28f21fbfe14c2db2061197baf26849e6a0989a4ea7d5e09ab49a15ba43a5377b9354d01e30ce860 +8f94c4255a0fc1bd0fa60e8178c17f2a8e927cac7941c5547d2f8f539e7c6ed0653cab07e9fb1f2c56cdd03bb876512a +95984c10a2917bfa6647ebce69bf5252d9e72d9d15921f79b2c6d7c15ee61342b4fb8a6d34838e07132b904f024ded04 +93e65e765a574277d3a4d1d08ca2f2ff46e9921a7806ca8ca3d8055f22d6507744a649db7c78117d9168a1cbdb3bbc61 +8d453b7364662dc6f36faf099aa7cbbe61151d79da7e432deba7c3ed8775cfe51eaf1ba7789779713829dde6828e189a +acffa3ee6c75160286090162df0a32a123afb1f9b21e17fd8b808c2c4d51a4270cab18fba06c91ef9d22e98a8dc26cdd +a5597cc458186efa1b3545a3926f6ecaaa6664784190e50eed1feac8de56631bee645c3bac1589fa9d0e85feb2be79d4 +87ba9a898df9dfa7dabc4ab7b28450e4daf6013340e329408d1a305de959415ab7315251bad40511f917dfc43974e5f0 +a598778cf01d6eef2c6aabc2678e1b5194ee8a284ebd18a2a51a3c28a64110d5117bcbf68869147934e600572a9e4c8a +84c69a4ad95861d48709f93ade5ac3800f811b177feb852ebcd056e35f5af5201f1d8a34ab318da8fe214812d0a7d964 +9638a237e4aed623d80980d91eda45e24ebf48c57a25e389c57bd5f62fa6ffa7ca3fb7ae9887faf46d3e1288af2c153b +800f975721a942a4b259d913f25404d5b7b4c5bf14d1d7e30eee106a49cb833b92058dab851a32ee41faf4ef9cb0dea4 +b9127a34a59fed9b5b56b6d912a29b0c7d3cb9581afc9bd174fc308b86fdb076f7d436f2abc8f61cef04c4e80cd47f59 +8004eda83f3263a1ccfc8617bc4f76305325c405160fb4f8efeff0662d605e98ba2510155c74840b6fe4323704e903c4 +aa857b771660d6799ff03ccad1ab8479e7f585a1624260418fc66dc3e2b8730cfa491d9e249505141103f9c52f935463 +98b21083942400f34cde9adbe1977dee45ba52743dc54d99404ad9da5d48691ddea4946f08470a2faad347e9535690c7 +a4b766b2faec600a6305d9b2f7317b46f425442da0dc407321fc5a63d4571c26336d2bccedf61097f0172ec90fb01f5f +b9736619578276f43583de1e4ed8632322ea8a351f3e1506c5977b5031d1c8ad0646fb464010e97c4ddb30499ddc3fb0 +973444ffaff75f84c17f9a4f294a13affd10e2bceed6b4b327e4a32c07595ff891b887a9f1af34d19766d8e6cb42bfd1 +b09ce4964278eff81a976fbc552488cb84fc4a102f004c87179cb912f49904d1e785ecaf5d184522a58e9035875440ef +b80c2aa3d0e52b4d8b02c0b706e54b70c3dbca80e5e5c6a354976721166ea0ca9f59c490b3e74272ef669179f53cb50d +8e52fa5096ff960c0d7da1aa4bce80e89527cdc3883eba0c21cb9a531088b9d027aa22e210d58cf7cbc82f1ec71eb44f +969f85db95f455b03114e4d3dc1f62a58996d19036513e56bee795d57bf4ed18da555722cd77a4f6e6c1a8e5efe2f5d7 +ab84b29b04a117e53caea394a9b452338364c45a0c4444e72c44132a71820b96a6754828e7c8b52282ad8dca612d7b6a +83e97e9ab3d9e453a139c9e856392f4cef3ec1c43bce0a879b49b27a0ce16f9c69063fd8e0debbe8fabafc0621bc200c +8c138ebdf3914a50be41be8aa8e2530088fb38af087fa5e873b58b4df8e8fd560e8090c7a337a5e36ef65566409ad8f3 +a56da9db2f053516a2141c1a8ed368ae278ab33a572122450249056857376d1dffc76d1b34daf89c86b6fe1ead812a0c +a3233ea249f07531f5bc6e94e08cea085fd2b2765636d75ff5851f224f41a63085510db26f3419b031eb6b5143735914 +b034bb6767ce818371c719b84066d3583087979ba405d8fbb2090b824633241e1c001b0cb0a7856b1af7a70e9a7b397e +8722803fe88877d14a4716e59b070dd2c5956bb66b7038f6b331b650e0c31230c8639c0d87ddc3c21efc005d74a4b5cc +8afe664cb202aacf3bd4810ebf820c2179c11c997f8c396692a93656aa249a0df01207c680157e851a30330a73e386b9 +a999e86319395351d2b73ff3820f49c6516285e459224f82174df57deb3c4d11822fd92cbbed4fc5a0a977d01d241b19 +9619408e1b58b6610d746b058d7b336d178e850065ba73906e08e748651e852f5e3aab17dcadcb47cc21ff61d1f02fcf +947cf9c2ed3417cd53ea498d3f8ae891efe1f1b5cd777e64cec05aba3d97526b8322b4558749f2d8a8f17836fb6e07aa +aec2fdae2009fda6852decb6f2ff24e4f8d8ca67c59f92f4b0cf7184be72602f23753ed781cf04495c3c72c5d1056ffe +8dba3d8c09df49fbfc9506f7a71579348c51c6024430121d1c181cad7c9f7e5e9313c1d151d46d4aa85fb0f68dd45573 +b6334cb2580ae33720ebf91bb616294532a1d1640568745dcda756a3a096786e004c6375728a9c2c0fb320441e7d297a +9429224c1205d5ecd115c052b701c84c390f4e3915275bb8ce6504e08c2e9b4dd67b764dd2ea99f317b4c714f345b6ff +abe421db293f0e425cfd1b806686bdfd8fdbac67a33f4490a2dc601e0ddbf69899aa9a119360dad75de78c8c688ca08b +95c78bffed9ae3fff0f12754e2bd66eb6a9b6d66a9b7faaeb7a1c112015347374c9fe6ce14bf588f8b06a78e9a98f44c +ac08f8b96b52c77d6b48999a32b337c5ad377adf197cda18dbdf6e2a50260b4ee23ca6b983f95e33f639363e11229ee4 +911a0e85815b3b9f3ba417da064f760e84af94712184faeb9957ddd2991dee71c3f17e82a1a8fbeec192b0d73f0ebce7 +aa640bd5cb9f050568a0ad37168f53b2f2b13a91e12b6980ca47ae40289cf14b5b89ddd0b4ca452ce9b1629da0ce4b5d +907486f31b4ecea0125c1827007ea0ecb1c55cadb638e65adc9810ca331e82bb2fd87e3064045f8d2c5d93dc6c2f5368 +8cbfaf4ce0bbbf89208c980ff8b7bc8f3cfef90f0fe910f463cb1c0f8e17cce18db120142d267045a00ba6b5368f0dd3 +9286f08f4e315df470d4759dec6c9f8eacef345fc0c0b533ad487bb6cfefa8c6c3821a22265c9e77d34170e0bc0d078b +94a3c088bc1a7301579a092b8ece2cefc9633671bc941904488115cd5cb01bd0e1d2deef7bdccb44553fd123201a7a53 +8f3d0114fbf85e4828f34abb6d6fddfa12789d7029d9f1bb5e28bc161c37509afdab16c32c90ec346bc6a64a0b75726f +a8ed2d774414e590ec49cb9a3a726fafd674e9595dd8a1678484f2897d6ea0eea1a2ee8525afac097b1f35e5f8b16077 +9878789ff33b11527355a317343f34f70c7c1aa9dc1eca16ca4a21e2e15960be8a050ec616ffb97c76d756ce4bce2e90 +854e47719dae1fe5673cacf583935122139cf71a1e7936cf23e4384fbf546d48e9a7f6b65c3b7bf60028e5aa1234ba85 +af74bdda2c6772fe9a02d1b95e437787effad834c91c8174720cc6e2ea1f1f6c32a9d73094fc494c0d03eef60b1a0f05 +80a3e22139029b8be32cb167d3bc9e62d16ca446a588b644e53b5846d9d8b7ab1ad921057d99179e41515df22470fb26 +86c393afd9bd3c7f42008bba5fe433ec66c790ebd7aa15d4aeaf9bb39a42af3cfaf8c677f3580932bbd7ada47f406c8c +90433c95c9bb86a2c2ddcf10adccb521532ebd93db9e072671a4220f00df014e20cd9ce70c4397567a439b24893808dc +95b2c170f08c51d187270ddc4f619300b5f079bbc89dbca0656eae23eecc6339bf27fa5bf5fd0f5565d4021105e967d2 +8e5eced897e2535199951d4cff8383be81703bca3818837333dd41a130aa8760156af60426ceadb436f5dea32af2814c +a254a460ebefbe91d6e32394e1c8f9075f3e7a2bb078430ac6922ab14d795b7f2df1397cb8062e667d809b506b0e28d4 +ac2062e8ca7b1c6afb68af0ebab31aebd56fc0a0f949ef4ea3e36baf148681619b7a908facf962441905782d26ecbdb5 +8b96af45b283b3d7ffeec0a7585fc6b077ea5fd9e208e18e9f8997221b303ab0ce3b5bafa516666591f412109ce71aa5 +afd73baada5a27e4fa3659f70083bf728d4dc5c882540638f85ea53bf2b1a45ddf50abc2458c79f91fb36d13998c7604 +a5d2fff226e80cb2e9f456099812293333d6be31dd1899546e3ad0cd72b2a8bcb45ec5986e20faa77c2564b93983210c +a8c9b8de303328fbdaccf60f4de439cf28f5360cf4104581dc2d126bc2e706f49b7281723487ff0eaf92b4cc684bc167 +a5d0d5849102bf1451f40e8261cb71fc57a49e032773cb6cd7b137f71ee32438d9e958077ffafce080a116ccc788a2d4 +80716596f502d1c727d5d2f1469ce35f15e2dbd048d2713aa4975ee757d09c38d20665326bd63303cfe7e820b6de393d +97baf29b20f3719323cc1d5de23eaa4899dc4f4e58f6c356ec4c3ad3896a89317c612d74e0d3ab623fe73370c5972e2f +b58bdc9aa5061bf6e5add99a7443d7a8c7ba8f6875b8667d1acbe96fc3ecafbdcc2b4010cb6970a3b849fff84660e588 +b6be68728776d30c8541d743b05a9affc191ad64918fdbd991d2ddd4b32b975c4d3377f9242defef3805c0bfb80fbac7 +b0cddace33333b8a358acad84b9c83382f0569d3854b4b34450fd6f757d63c5bdab090e330b0f86e578f22c934d09c36 +854bd205d6051b87f9914c8c2494075d7620e3d61421cc80f06b13cea64fd1e16c62c01f107a5987d10b8a95a8416ad9 +80351254a353132300ba73a3d23a966f4d10ce9bf6eae82aedb6cdc30d71f9d08a9dd73cb6441e02a7b2ad93ad43159c +937aae24fb1b636929453fc308f23326b74c810f5755d9a0290652c9c2932ad52cc272b1c83bd3d758ef7da257897eae +b84d51ef758058d5694ffeac6d8ce70cef8d680a7902f867269c33717f55dd2e57b25347841d3c0872ae5f0d64f64281 +a4b31bb7c878d5585193535b51f04135108134eff860f4eac941053155f053d8f85ff47f16268a986b2853480a6e75e6 +93543f0828835186a4af1c27bdf97b5dd72b6dfa91b4bf5e759ff5327eaf93b0cb55d9797149e465a6b842c02635ffe5 +afdac9e07652bf1668183664f1dd6818ef5109ee9b91827b3d7d5970f6a03e716adcc191e3e78b0c474442a18ad3fc65 +9314077b965aa2977636ae914d4a2d3ce192641a976ffa1624c116828668edbfbe5a09e3a81cb3eed0694566c62a9757 +b395ddcf5082de6e3536825a1c352802c557b3a5118b25c29f4c4e3565ecaaf4bdd543a3794d05156f91fc4ceadc0a11 +b71f774aad394c36609b8730e5be244aaebfff22e0e849acc7ee9d33bedc3ec2e787e0b8b2ffe535560fcd9e15a0897e +92e9409fa430f943a49bce3371b35ac2efb5bc09c88f70ff7120f5e7da3258a4387dfc45c8b127f2ef2668679aeb314e +8ef55bef7b71952f05e20864b10f62be45c46e2dca0ef880a092d11069b8a4aa05f2e0251726aca1d5933d7dea98f3f8 +aad3fba9e09fae885cdeef45dfafa901419f5156fb673818f92a4acc59d0e2e9870b025e711de590a63fd481164f3aa8 +b444d52af545dd3a2d3dd94e6613816b154afea0c42b96468aceb0c721395de89e53e81a25db857ca2e692dcb24ba971 +88b279fe173007e64fe58f2c4adba68a1f538dbd3d32d175aa0d026bbb05b72a0c9f5d02b8201a94adb75fe01f6aa8b2 +88494cea4260741c198640a079e584cabfea9fcfb8bcf2520c9becd2419cde469b79021e5578a00d0f7dbc25844d2683 +94f3cce58837c76584b26426b9abdb45f05fee34dd9e5914b6eae08e78b7262ed51c4317031dab1ad716f28b287f9fc2 +b8c7ed564f54df01c0fbd5a0c741beed8183ce0d7842dc3a862a1b335de518810077314aa9d6054bb939663362f496da +81c153320d85210394d48340619d5eb41304daea65e927266f0262c8a7598321aba82ad6c3f78e5104db2afd2823baca +ab6695a8d48a179e9cd32f205608359cf8f6a9aead016252a35b74287836aa395e76572f21a3839bec6a244aa49573e5 +920ed571539b3002a9cd358095b8360400e7304e9a0717cc8c85ab4a0514a8ad3b9bf5c30cb997647066f93a7e683da9 +a7ec7c194d1e5103bc976e072bf1732d9cb995984d9a8c70a8ee55ce23007f21b8549ad693f118aa974f693ed6da0291 +87a042d6e40c2951a68afc3ccf9646baf031286377f37f6ac47e37a0ec04d5ac69043757d7dff7959e7cd57742017a8d +b9f054dd8117dd41b6e5b9d3af32ee4a9eebef8e4a5c6daa9b99c30a9024eabeae850ab90dbdb188ca32fd31fd071445 +a8386da875799a84dc519af010eaf47cdbc4a511fe7e0808da844a95a3569ce94054efd32a4d3a371f6aba72c5993902 +8b3343a7cf4ffb261d5f2dbd217fb43590e00feac82510bdf73b34595b10ee51acae878a09efebc5a597465777ef4c05 +8312a5f1ea4f9e93578e0f50169286e97884a5ed17f1780275ab2b36f0a8aa1ab2e45c1de4c8bce87e99e3896af1fa45 +b461198cb7572ac04c484a9454954e157bdd4db457816698b7290f93a10268d75a7e1211e757c6190df6144bbb605d91 +9139764a099580d6f1d462c8bf7d339c537167be92c780e76acb6e638f94d3c54b40ed0892843f6532366861e85a515a +8bb70acb3c9e041b4fc20e92ba0f3f28f0d5c677bcb017af26f9171e07d28c3c0729bef72457231e3512f909455a13a2 +93301a18e5064c55fcfe8e860fab72da1b89a824ca77c8932023b7c79e4a51df93a89665d308a8d3aa145e46ebe6a0ad +ae3bca496fbd70ce44f916e2db875b2ce2e1ded84edd2cebc0503bdfdec40ec30e1d9afb4eb58c8fa23f7b44e71d88f8 +93cb3a918c95c5d973c0cb7621b66081ed81fba109b09a5e71e81ca01ec6a8bb5657410fdec453585309ef5bf10d6263 +95a50b9b85bb0fc8ff6d5f800d683f0f645e7c2404f7f63228a15b95ce85a1f8100e2e56c0acee19c36ed3346f190e87 +816cc4d9337461caca888809b746ab3713054f5b0eac823b795a1a9de9417c58e32a9f020fef807908fa530cbf35dee8 +a9c2890c2dd0d5d7aedc4cca7f92764086c50f92f0efd2642c59920d807086031bfe2d3ba574318db236c61a8f5f69c2 +ad0d5c8c80bddfe14bdaf507da96dc01dc9941aecc8ad3b64513d0a00d67c3f4b4659defb6839b8b18d8775e5344c107 +9047c9fad6ef452e0219e58e52c686b620e2eb769571021e3524bd7eac504f03b84834b16b849d42b3d75c601fd36bb7 +a04dd988fed91fb09cb747a3ac84efe639d7d355524cd7dee5477ecbcdec44d8ac1cec2c181755dcfdb77e9594fb3c5b +b0ea0c725debd1cec496ced9ce48f456f19af36e8b027094bf38fa37de9b9b2d10282363ea211a93a34a0a5387cace5d +b5fc46e2bb3e4653ea5e6884dcb3c14e401a6005685ee5a3983644b5b92300b7066289159923118df4332aac52045b8c +841fc5b26b23226e725e29802da86b35e4f5e3babc8b394f74e30fd5dec6d3840b19a9a096625ce79a4f1edae6369700 +8fd2bbbeea452451def3659bbe0ceb396120ebe8f81eee1ea848691614422c81d7c3e6a7a38032b4120b25c5ffa8f0c2 +9131ce3d25c3d418f50c0ab99e229d4190027ee162b8ba7c6670420ea821831dec1294ac00d66c50fac61c275a9e2c71 +99ec6eafe0eb869d128158cee97b984fb589e1af07699247946e4a85db772289dff3084d224a6f208005c342f32bbd73 +ac100fbbe7c2bf00cc56fcd5aa1f27181f82c150c53bbb1e15d2c18a51ed13dcfa7bccab85821b8ddddf493603e38809 +affd73a458d70c0d9d221e0c2da4348fed731f6b34c0b3e2d5711ba432e85a1ec92e40b83b246a9031b61f5bc824be47 +8ed30ed817816a817e9e07374ef1f94405a7e22dd0096aeaae54504382fc50e7d07b4f1186c1792fc25ea442cd7edc6b +a52370cfe99a35fa1405aeca9f922ad8d31905e41f390e514ea8d22ee66469637d6c2d4d3a7ee350d59af019ae5a10a4 +8d0b439741c57b82c8e4b994cf3956b5aeaee048b17e0a1edb98253a8d7256f436d8b2f36b7e12504132dbf91f3376b1 +8caac7e1a4486c35109cff63557a0f77d0e4ca94de0817e100678098a72b3787a1c5afc7244991cebcd1f468e18d91d4 +a729a8e64b7405db5ebfb478bb83b51741569331b88de80680e9e283cc8299ba0de07fcf252127750f507e273dc4c576 +a30545a050dad030db5583c768a6e593a7d832145b669ad6c01235813da749d38094a46ac3b965700230b8deacd91f82 +9207e059a9d696c46fa95bd0925983cd8e42aefd6b3fb9d5f05420a413cbc9e7c91213648554228f76f2dd757bde0492 +a83fa862ae3a8d98c1e854a8b17181c1025f4f445fbc3af265dc99e44bbd74cfa5cc25497fb63ee9a7e1f4a624c3202c +84cdfc490343b3f26b5ad9e1d4dcf2a2d373e05eb9e9c36b6b7b5de1ce29fda51383761a47dbd96deca593a441ccb28e +881a1aa0c60bb0284a58b0a44d3f9ca914d6d8fa1437315b9ad2a4351c4da3ee3e01068aa128284a8926787ea2a618d1 +aace78e497b32fbff4df81b1b2de69dbc650645e790953d543282cb8d004a59caf17d9d385673a146a9be70bf08a2279 +aa2da4760f1261615bffd1c3771c506965c17e6c8270c0f7c636d90428c0054e092247c3373eca2fb858211fdb17f143 +acb79f291b19e0aa8edb4c4476a172834009c57e0dcc544c7ce95084488c3ad0c63ffd51c2b48855e429b6e1a9555433 +814b58773a18d50a716c40317f8b80362b6c746a531776a9251c831d34fb63e9473197c899c0277838668babc4aa0ecb +b1f69522b0f7657d78bd1ee3020bcce3447116bf62c146d20684537d36cafb5a7a1531b86932b51a70e6d3ce0808a17e +8549712c251ef382f7abe5798534f8c8394aa8bcecdca9e7aa1a688dc19dc689dcd017a78b118f3bd585673514832fe4 +912a04463e3240e0293cfc5234842a88513ff930c47bd6b60f22d6bc2d8404e10270d46bf6900fee338d8ac873ebb771 +a327cb7c3fada842e5dd05c2eeedd6fcd8cf2bfb2f90c71c6a8819fb5783c97dd01bd2169018312d33078b2bc57e19f7 +b4794f71d3eceed331024a4cee246cc427a31859c257e0287f5a3507bfbd4d3486cb7781c5c9c5537af3488d389fe03e +82ffcb418d354ed01688e2e8373a8db07197a2de702272a9f589aed08468eab0c8f14e6d0b3146e2eb8908e40e8389c5 +910b73421298f1315257f19d0dfd47e79d7d2a98310fb293f704e387a4dc84909657f0f236b70b309910271b2f2b5d46 +a15466397302ea22f240eb7316e14d88376677b060c0b0ae9a1c936eb8c62af8530732fc2359cfd64a339a1c564f749b +a8091975a0d94cdc82fbaff8091d5230a70d6ea461532050abbdfee324c0743d14445cfe6efe6959c89a7c844feaa435 +a677d1af454c7b7731840326589a22c9e81efbbf2baf3fdeaf8ea3f263a522584fbca4405032c4cdf4a2a6109344dfc8 +894e6ffa897b6e0b37237e6587a42bbc7f2dd34fb09c2e8ac79e2b25b18180e158c6dc2dd26761dba0cfed1fb4eb4080 +928d31b87f4fe8fe599d2c9889b0ff837910427ba9132d2fba311685635458041321ae178a6331ed0c398efe9d7912f0 +afc1c4a31f0db24b53ee71946c3c1e1a0884bd46f66b063a238e6b65f4e8a675faa844e4270892035ef0dae1b1442aa0 +a294fcb23d87cf5b1e4237d478cac82ba570649d425b43b1e4feead6da1f031e3af0e4df115ca46689b9315268c92336 +85d12fd4a8fcfd0d61cbf09b22a9325f0b3f41fb5eb4285b327384c9056b05422d535f74d7dc804fb4bab8fb53d556bd +91b107d9b0ea65c48128e09072acd7c5949a02dd2a68a42ff1d63cf528666966f221005c2e5ca0a4f85df28459cdede6 +89aa5dc255c910f439732fcd4e21341707e8dd6689c67c60551a8b6685bd3547e3f47db4df9dfadd212405f644c4440b +8c307d6b827fa1adcf0843537f12121d68087d686e9cc283a3907b9f9f36b7b4d05625c33dab2b8e206c7f5aabd0c1e5 +843f48dadf8523d2b4b0db4e01f3c0ea721a54d821098b578fcaa6433e8557cadfea50d16e85133fa78f044a3e8c1e5b +9942eb8bd88a8afa9c0e3154b3c16554428309624169f66606bfb2814e8bac1c93825780cf68607f3e7cffe7bf9be737 +b7edb0c7637a5beb2332f2ae242ba4732837f9da0a83f00f9e9a77cf35516e6236eb013133ddc2f958ea09218fe260d3 +9655fe4910bc1e0208afbcf0ff977a2e23faded393671218fba0d9927a70d76514a0c45d473a97ecb00cf9031b9d527c +8434bc8b4c5839d9e4404ff17865ded8dd76af56ef2a24ea194c579d41b40ed3450c4e7d52219807db93e8e6f001f8da +b6c6d844860353dab49818bed2c80536dbc932425fdaa29915405324a6368277cf94d5f4ab45ea074072fc593318edff +b2887e04047660aa5c83aad3fa29b79c5555dd4d0628832c84ba7bf1f8619df4c9591fcde122c174de16ca7e5a95d5e3 +953ba5221360444b32911c8b24689078df3fbf58b53f3eec90923f53a22c0fc934db04dd9294e9ec724056076229cf42 +926917529157063e4aade647990577394c34075d1cb682da1acf600639d53a350b33df6a569d5ebb753687374b86b227 +b37894a918d6354dd28f850d723c1c5b839f2456e2a220f64ecadac88ae5c9e9cf9ab64b53aac7d77bf3c6dfa09632dc +b9d28148c2c15d50d1d13153071d1f6e83c7bb5cb5614adf3eb9edede6f707a36c0fa0eadb6a6135ead3c605dfb75bd1 +9738d73ea0b9154ed38da9e6bd3a741be789ea882d909af93e58aa097edf0df534849f3b1ba03099a61ceb6a11f34c4d +afabbecbbf73705851382902ec5f1da88b84a06b3abfb4df8d33df6a60993867f853d0d9bd324d49a808503615c7858a +a9e395ddd855b12c87ba8fdb0ea93c5bd045e4f6f57611b27a2ee1b8129efe111e484abc27cb256ed9dcace58975d311 +b501c2f3d8898934e45e456d36a8a5b0258aeea6ff7ac46f951f36da1ec01bd6d0914c4d83305eb517545f1f35e033cc +86f79688315241fe619b727b7f426dbd27bcc8f33aef043438c95c0751ada6f4cd0831b25ae3d53bcf61324d69ea01eb +83237e42fa773a4ccaa811489964f3fab100b9eea48c98bdef05fa119a61bde9efe7d0399369f87c775f4488120b4f2e +b89f437552cab77d0cd5f87aca52dd827fb6648c033351c00ab6d40ac0b1829b4fcdf8a7dad467d4408c691223987fbe +8e21061698cb1a233792976c2d8ab2eeb6e84925d59bb34434fff688be2b5b2973d737d9dda164bd407be852d48ef43f +b17a9e43aa4580f542e00c3212fbf974f1363f433c5502f034dfd5ed8c05ac88b901729d3b822bec391cca24cc9f5348 +aac6d6cda3e207006c042a4d0823770632fc677e312255b4aff5ad1598dc1022cab871234ad3aa40b61dc033a5b0930b +b25e69f17b36a30dada96a39bc75c0d5b79d63e5088da62be9fcbddfd1230d11654890caa8206711d59836d6abbc3e03 +af59fe667dd9e7e4a9863c994fc4212de4714d01149a2072e97197f311be1f39e7ad3d472e446dcc439786bf21359ede +957952988f8c777516527b63e0c717fc637d89b0fd590bcb8c72d0e8a40901598930c5b2506ff7fea371c73a1b12a9be +a46becd9b541fc37d0857811062ca1c42c96181c7d285291aa48dc2f6d115fcff5f3dfdf4490d8c619da9b5ce7878440 +87168fbd32c01a4e0be2b46fe58b74d6e6586e66bbb4a74ad94d5975ac09aa6fa48fd9d87f1919bd0d37b8ebe02c180c +895c4aa29de9601fc01298d54cfb62dd7b137e6f4f6c69b15dc3769778bfba5fc9cbd2fc57fd3fad78d6c5a3087f6576 +b9cf19416228230319265557285f8da5b3ca503de586180f68cf055407d1588ecec2e13fc38817064425134f1c92b4d5 +9302aaef005b22f7b41a0527b36d60801ff6e8aa26fe8be74685b5f3545f902012fcade71edca7aaa0560296dac5fca5 +a0ccda9883027f6b29da1aaa359d8f2890ce1063492c875d34ff6bf2e7efea917e7369d0a2b35716e5afd68278e1a93a +a086ac36beeba9c0e5921f5a8afea87167f59670e72f98e788f72f4546af1e1b581b29fbdd9a83f24f44bd3ec14aee91 +8be471bf799cab98edf179d0718c66bbc2507d3a4dac4b271c2799113ce65645082dc49b3a02a8c490e0ef69d7edbcb1 +8a7f5b50a18baf9e9121e952b65979bda5f1c32e779117e21238fb9e7f49e15008d5c878581ac9660f6f79c73358934a +b3520a194d42b45cbab66388bee79aad895a7c2503b8d65e6483867036497d3e2e905d4d51f76871d0114ec13280d82f +8e6ca8342ec64f6dbe6523dc6d87c48065cd044ea45fa74b05fff548539fd2868eb6dd038d38d19c09d81d5a96364053 +b126a0e8263a948ba8813bf5fb95d786ae7d1aa0069a63f3e847957822b5fe79a3a1afa0ce2318b9ba1025f229a92eb7 +8e4461d6708cac53441a3d23ac4b5ff2b9a835b05008c26d7d9c0562a29403847cf760b7e9d0bcb24a6f498d2a8a9dd2 +b280a761bab256dfe7a8d617863999e3b4255ddbdc11fe7fe5b3bb9633fc8f0cb4f28e594d3b5b0b649c8e7082c4666a +a3e3043bfd7461e38088ee6a165d2ca015de98350f1cb0efc8e39ed4fcdb12a717f0ede7fbf9dadb90496c47652cc0ce +a4c1f5b1b88ae3c397d171e64395afe0cd13c717677775a01dd0461d44a04ee30ec3da58a54c89a3ca77b19b5e51062c +a268638e0655b6d5a037061808619b9ae276bb883999d60c33a9f7f872c46d83d795d1f302b4820030c57604fa3686e7 +ac20176111c5c6db065668987227658c00a1572ce21fe15f25e62d816b56472c5d847dd9c781fb293c6d49cc33b1f98f +acc0e22d9b6b45c968c22fd16b4ece85e82a1b0ab72369bdd467857fee1a12b9635f5b339a9236cbd1acc791811d0e29 +b56066e522bee1f31480ff8450f4d469ace8eb32730c55b7c9e8fa160070bdec618454e665b8cbc5483bc30b6cebbfb9 +8c1772bdfacff85f174d35c36f2d2182ae7897ad5e06097511968bbb136b626c0c7e462b08a21aca70f8e456b0204bf8 +b4de3cf4a064bf589be92513b8727df58f2da4cd891580ef79635ac8c195f15a6199327bb41864e2f614c8589b24f67e +8f3c534125613f2d17bf3e5b667c203cb3eab0dbca0638e222fe552fddf24783965aa111de844e8c3595304bfc41c33b +8e445b2711987fe0bf260521cb21a5b71db41f19396822059912743bf6ca146100c755c8b6e0e74f1bf2e34c03b19db9 +87ff9adf319adb78c9393003b5bdda08421f95551d81b37520b413fe439e42acf82d47fa3b61476b53166bf4f8544f0e +83f3c00c55632e1937dcdc1857de4eccd072efa319b3953d737e1d37382b3cf8343d54a435588eb75aa05bf413b4caa0 +b4d8ee1004bac0307030b8605a2e949ca2f8d237e9c1dcf1553bd1eb9b4156e2deb8c79331e84d2936ec5f1224b8b655 +93b2812b6377622e67bf9a624898227b56ebe3c7a1d917487fc9e4941f735f83679f7ac137065eb4098ad1a4cfbc3892 +81943d9eab6dcea8a120dde5356a0a665b1466709ebb18d1cbfa5f213a31819cb3cf2634e6d293b5b13caa158a9bb30b +a9042aae02efd4535681119e67a60211fc46851319eb389b42ebadcab1229c94199091fb1652beba3434f7b98c90785f +91db52b27fd9b1715df202106b373c4e63ce8ec7db8c818c9016ace5b08ef5f8c27e67f093395937ba4ce2f16edf9aef +83cb9b7b94bd6ead3ff2a7d40394f54612c9cb80c4e0adadffea39e301d1052305eb1fe0f7467268b5aba3b423a87246 +8720fd6712a99d92dd3fdaae922743ab53fad50d183e119a59dae47cdac6fbea6064c732d02cb341eaea10723db048fa +8d40022c1254462a2ac2380a85381c370b1221e5a202d95c75bccba6d1e52972dd5585a1294a1e487bf6ae6651867167 +b7bc06e08d8c72daba143627582f4b4f34cc2234b5cb5cd83536f2ef2e058631a3920468ea4d550aea01cad221d6a8a6 +a6e1a6f70fba42d3b9ce5f04ffdcfca46fc94041840c0066a204030cf75ea9f9856113fea3a9f69ea0037d9a68e3a9d4 +8b064c350083fce9a52da2e2e17bf44c4c9643d2d83667cbd9ad650bbeba55e2c408e746ccf693e56d08826e8a6d57fc +8d304a5405a0c0696917fcddc6795dd654567ca427f007d9b16be5de98febbf8692374e93f40822f63cf6f143c4d9499 +b968db239efec353a44f20a7cf4c0d0fca4c4c2dc21e6cbb5d669e4fe624356a8341e1eec0955b70afb893f55e9a9e32 +98971f745ce4ce5f1f398b1cd25d1697ada0cc7b329cee11d34b2d171e384b07aeb06ac7896c8283664a06d6dd82ec6b +881f5a20a80f728354fad9d0a32a79ffe0ba9bed644ed9d6a2d85444cda9821018159a3fa3d3d6b4fadbf6ea97e6aff6 +b7c76cbb82919ec08cf0bd7430b868a74cb4021e43b5e291caa0495ca579798fab1b64855e2d301f3461dd4d153adeb6 +b44c8c69b3df9b4e933fe6550982a6f76e18046e050229bd2456337e02efb75efa0dfe1b297ed9f5d7fa37fec69c8374 +a5bd7781820ba857aee07e38406538b07ab5180317689a58676f77514747672dd525ea64512a0e4958896f8df85e9d4d +a8443d1dc91b4faa20a2626505b5b4ad49cc5c1fd7a240a0e65d12f52d31df1585ba52c21e604dcec65ec00b81ae21fe +a157ae42fc6302c54bcdd774e8b8bafc4f5d221717f7bf49668c620e47051b930dce262d55668e546272dd07ca7c8d3f +8732c10448b63e907ff95f53cd746f970c946fd84fcbfe4cf9ede63afbbfc66b293bbc7c470d691bbd149bb3c78bb351 +a82192f4fd9a0c33489a0486b79d0f6c797c7eccb45f91f7f1e8e1dd1924ca9944b983951025b99ab5861d31841451fe +839efc6d199ddd43f34f6729b6b63f9ee05f18859bf8fd3f181fa71f4399a48bff7dde89b36e9dc1c572f1b9b6127cca +992ef084abe57adfd5eb65f880b411d5f4ed34c1aeb0d2cfac84fff4f92a9a855c521a965ba81b5eef2268e9a9e73048 +a2518ab712fa652e6e0bd0840307ef3831094e9a18723fb8ec052adacbb87f488d33778c6ec3fd845003af62e75125d1 +b630ac3c9e71b85dd9e9f2984bb5b762e8491d8edb99cad82c541faf5a22dd96f0fddb49d9a837b1955dea2d91284f28 +8d886d1b7f818391b473deba4a9a01acce1fe2abe9152955e17ba39adc55400590c61582c4fef37a286e2151566576ed +884f100dc437639247f85e5d638fcc7583d21bf37a66ce11e05bfc12f5dbe78685b0e51b4594e10549c92bb980512e12 +806d7bac2d24cfff6090ba9513698292d411cdea02976daa3c91c352b09f5a80a092cfa31304dcfcd9356eaf5164c81b +934ed65f8579ee458b9959295f69e4c7333775eb77084db69ad7096f07ad50ad88f65e31818b1942380f5b89e8d12f1b +aaf50ca5df249f0a7caf493334b6dca1700f34bd0c33fe8844fadd4afedbb87a09673426741ac7cbbb3bf4ab73f2d0f3 +b2868642cfa0a4a8a2553691c2bef41dab9dff87a94d100eaa41645614ab4d0e839ec2f465cc998c50cd203f0c65df22 +a326513112e0b46600d52be9aa04d8e47fe84e57b3b7263e2f3cf1a2c0e73269acb9636a99eb84417f3ae374c56e99b0 +97b93efc047896ddf381e8a3003b9e1229c438cc93a6dbef174bb74be30fac47c2d7e7dc250830459bed61d950e9c924 +b45e4f0a9806e44db75dbb80edc369be45f6e305352293bcae086f2193e3f55e6a75068de08d751151fdf9ebc6094fa1 +87f2161c130e57e8b4bb15616e63fa1f20a1b44d3e1683967a285f0d4f0b810f9202e75af2efa9fc472687c007a163f7 +8f6400a45666142752580a2dce55ef974f59235a209d32d2036c229c33a6189d51435b7ea184db36f765b0db574a9c52 +a0ee079462805f91b2200417da4900227acde0d48c98e92c8011a05b01c9db78fc5c0157d15cb084b947a68588f146f4 +ab0612d9bb228b30366b48e8d6ae11026230695f6f0607c7fa7a6e427e520121ff0edea55d1f0880a7478c4a8060872d +ad65dfde48f914de69f255bb58fa095a75afe9624fc8b7b586d23eb6cf34a4905e61186bc978e71ccb2b26b0381778a6 +8c8a4847d138d221c0b6d3194879fd462fb42ed5bd99f34ebe5f5b1e1d7902903ec55e4b52c90217b8b6e65379f005a4 +a41dca4449584353337aef1496b70e751502aeed9d51202de6d9723e155ca13be2d0db059748704653685a98eaa72a07 +ae40e5450fd994d1be245a7cd176a98dd26332b78da080159295f38802a7e7c9c17cc95da78d56558d84948cf48242cd +863878fda80ad64244b7493e3578908d4a804887ad1ad2c26f84404dcad69ea2851846ad2c6f2080e1ed64fe93bbec31 +b262fb990535f162dc2b039057a1d744409a3f41dd4b70f93ff29ba41c264c11cb78a3579aad82f3fa2163b33a8ce0e1 +a7f6eb552b9a1bb7c9cb50bc93d0dda4c7ecf2d4805535f10de0b6f2b3316688c5e19199d5c9ec2968e2d9e2bd0c6205 +a50aa5869412dc7081c8d827299237910ecec3154587692548da73e71fa398ff035656972777950ba84e472f267ba475 +924c3af750afc5dfad99d5f3ed3d6bdd359492cff81abcb6505696bb4c2b4664926cb1078a55851809f630e199955eb3 +a1acffa31323ce6b9c2135fb9b5705664de8949f8235b4889803fbd1b27eb80eb3f6a81e5b7cc44e3a67b288b747cf2f +8dec9fd48db028c33c03d4d96c5eecea2b27201f2b33d22e08529e1ae06da89449fe260703ac7bb6d794be4c0c6ea432 +aa6642922ccf912d60d678612fffe22ef4f77368a3c53a206c072ed07c024aa9dcde2df068c9821b4c12e5606cfe9be2 +a16ddf02609038fcb9655031b1cb94afe30b801739e02a5743c6cd2f79b04b2524c2085ca32ec3a39df53de0280f555d +b067d48589e9d3428c6d6129e104c681e4af376a351f502840bbea6c3e11fcbfdf54dadf6f1729621720a75ff89786c3 +b14a24079de311c729750bb4dd318590df1cd7ffc544a0a4b79432c9a2903d36a0d50ecd452b923730ade6d76a75c02c +97437bac649f70464ace93e9bec49659a7f01651bba762c4e626b5b6aa5746a3f0a8c55b555b1d0dc356d1e81f84c503 +a6f4cb2ffc83564b1170e7a9a34460a58a4d6129bd514ff23371a9e38b7da6a214ac47f23181df104c1619c57dff8fe2 +896d0f31dfc440cc6c8fde8831a2181f7257ffb73e1057fd39f1b7583ea35edf942ad67502cd895a1ad6091991eabc5e +9838007f920559af0de9c07e348939dfd9afe661b3c42053b4d9f11d79768cba268a2ee83bb07a655f8c970c0ee6844b +b41b8a47e3a19cadec18bff250068e1b543434ce94a414750852709cd603fc2e57cd9e840609890c8ff69217ea1f7593 +a0fb4396646c0a2272059b5aeb95b513e84265b89e58c87d6103229f489e2e900f4414133ed2458ddf9528461cfa8342 +ae026cfa49babc1006a3e8905d6f237a56a3db9ddf7559b0e4de8d47d08c3f172bde117cdf28dfdfd7627bd47d6a3c85 +a6a3f3e7006bc67290c0c40c1680bf9367982eb8aaf17ecb484a58c8e9c2a7c24932e2caa9aacc9b4fbf4c0abd087a46 +9093e05bd814177a01a3b8d7b733db66294e1c688c56def6e1827c0f2d9a97cf202721641bf81fb837f8581ae68cb5ce +87feef4de24942044f47d193d4efc44e39a8c0f4042fba582f2491a063e3a4640cb81f69579b6f353b9208884a4f7ce6 +975f9b94e78aac55bd4755f475e171e04f6fbddb6fd3d20a89a64a6346754a3ff64ecff8c04b612a1250e1d8d8a9e048 +87cde4d0164922d654cf2dc08df009e923c62f1a2e3b905dfde30f958e9e4dd6070d9f889712acd6c658804f48f3edb1 +ae8e22e158dda90a185eec92602831b5d826e5a19aab8c6400dba38b024c7d31c4cf265eb7b206dd45834f020b3f53cd +a4475807adc28aa086e977b65bbd7c8512119318c89d2619ea03a6739a72c3fb90c9622451896c7113ad4d12a3004de6 +97f1ae1e0d258a94532c7b73fa8ebdbbd53349a4d2d0a217fe56dfdd084dd879960bc6ff45ebb61b5dbf2054642800a4 +b3c832bd3691332a658b0caaa7717db13f5b5df2b5776b38131ac334b5fd80d0b90b6993701e5d74d2b7f6b2fd1f6b9d +a4b6af590187eb1b2cb5ae2b8cffa45c5e76abdb37cec56fc9b07a457730f5af0706d9ce0a17da792bbece5056d05670 +97b99a73a0e3145bf91f9dd611a67f894d608c954e9b8f5a4c77e07574064b3db47353eba8038062cebaad06a2500bab +8e5ca5a675de6e6d3916bd9ce5898bb379372afe3f310e70ff031bc8cc8fabfb7f3bfb784f409bb7eb06fdb4511ee477 +aabbbee4da1f16b5bbe001c19debe04745932d36dfbbf023fbf1010a2b1d54eb92fa5e266ac1e9337e26e2ddba752f40 +b13447c77496825f48e35c14f9b501c5056e6d5519f397a2580cea9a383a56a96994d88926aa681142fe2f1589c03185 +b89c55db39ff0e73dde7435b61e8a4d3e10f51dd8096cbc7f678661962e6de3d16f2f17a0e729cc699234cb847f55378 +82c36b7de53698a1bafbb311fefc6007fcefa47a806ebe33a4e7e0fc1c7b6b92a40a1860702cf9295a16c6b1433e3323 +8daeec8c88543d09c494a15cc9a83c0b918d544311fd2a7d09e06cf39cdebfa0cfc0e8fc0e3b5954960b92332f98697c +b18e55a1a7ae16be3a453d2bfa7659a7ec2d283dd46bdc82decef6d3751eeafc4f86f2416a22955c7e750c0582d4f3eb +b50c743462e2915bf773848669e50a3bcdb5a9ac5f664e97eaccf568c7d64a6493d321be0225de16142ce82ce1e24f66 +af69c9643805fb860434424b1608aababc593aaebc6a75fc017f7f62bb2b1da932b0b9bd5e6dcbba328422dafc06efd8 +b5947db4f809fd0d27af838b82eef8ab4fe78687a23ebc61c09c67eb7e8d0e6a310ecb907fd257859d5a2759a07c21cc +92c7960e163ca5bdf9196c7215102f8e9d88efc718843321c6e2a6170137b8ecec4ea5d5a5ce4c28012b6cdbd777dd01 +b63f9509ed5e798add4db43b562e8f57df50d5844af6e5c7acf6c3b71637c0a2d2433f4a0627b944f0af584892208bb8 +8ef28304a9bfe5220af6a9a6a942d2589606f5dc970d708ef18bc7ed08e433161020d36fb327c525398cd8ecb57002f9 +b722e0410f896c4462d630a84a5a14e94289fc38ed6d513ca88a09005935cec334c480028efa1943c7a5e202ae8c8379 +b56b6672b488e64d4dde43571f9ceaa7e61e336b0fd55bb769a57cd894a6300e724e5f88bad39a68bc307eb7406cb832 +8bf493da411fd41502b61a47827731193652e6ce3810709e70869d9aae49e4b17a40437a7a0dcc0547dbac21f355c0da +9613b60a144c01f6a0e7d46ddde07402e2133a1fe005c049a56415ff90401765040b2fc55971d24b94c5fd69fec58941 +85e2f02b291563d8eea3768cf6a4602c0ca36568ffcf3d93795d642044196ca6b0b28991ea5898e7974ee02831a0ec70 +b08ef66703dd9ac46e0208487566fbf8d8654d08c00f03e46f112c204782ccc02a880a3f9dffd849088693cee33b7b6d +a0b19eeda6c71b0e83b1f95dffef4d370318bdea6ea31d0845695e6b48d5c428c3dbba1a0ded80964992c4a0695f12ee +b052642e5772d2ef6f49dd35c5e765c5f305006b2add3b4bee5909ca572161edf0e9c2bc3bc3bc7f56fd596360ef2201 +8261af164c768fec80d63fca6cd07d1c0449e9ca665fe60c29babdbd8a2b20cf1f556a4b24cd7341712468a731c21b32 +8a17016a1b2fc0fa0d9e3610ea80548fcf514e0a35e327f6b5f8069b425c0f0829af7e206013eab552be92b241be5ac5 +8eea25c680172696f5600271761d27ef4c8cec9ab22f01f72b2c7c313a142fafaec39e6920b96fcace858883e02eff7a +b8e0c590106e125c5bca7e7a071cc408b93629da0d8d6381f1b73fbdf17024a0cf13f679f5203a99bbbcb664b4a94e88 +b9943b29395258b7afdf1781cfaf131297a4f325540755df73401b2ec4a549f962952e9907413c39a95585c4aff38157 +8286eab4a04f8113fb3f738a9bc9c2deaf3a22bf247151515568703da4efe6450ab3970f5c74e978a2db7e8d795331b7 +a10cf383c8a7e3f0a0a5556b57532170ff46dabdcbb6a31c4617271634b99540aa575786c636d3809207cbf1d2f364d3 +a5af7eb998140d01ba24baa0e8c71625aee6bd37db4c5ff607518f907892219ba8c9a03c326b273bfd7068232809b73c +aed5f461e38fccc8b3936f1328a9747efcbceb66312f6d6eddce57c59570852767159f1a7d9998f63342515fef4ba9bf +aec3e94b029aa692bfe2b8dbc6c3b0d132b504242e5ebe0cad79c065085e2fc05550e5cdaa2353892a40ff1a062dd9eb +87c23703960129396018d0347f5dd034abdbd57232b74195b6a29af34b6197b3cd63c60ac774d525add96ae54d5c0fb4 +97964a7768216e1c84dece71ce9202cc64b6d483650aa6f6d67215f655f66cda14df0a0f251db55832c77bfd9b6316e2 +8167aaf24c8a023d0aea16b8c24d993618b9d0c63619e11a28feab8f14952bafcb0918ed322cbc0ae1b2e1786071819b +b58318bd62852ffb712fc58f368c21b641dde7b3fa7d7269974c7a7b5b3e1641569fc7b5f32ca49de22f4f993506d92d +b172e7911d5cd3f53af388af847b928947c711185aebd3328f8e6ed1106c161ae0c1b67d3d9eb237e9e66eb0672edec0 +a6834cf69b2c4433cf6e779bfbb736b12e73e71e149c38101d13dbacf6c5048db53994a6a039381df40bbd67de40fcd0 +882604aa3bb19fffd6db744b5cf4a2431b157dac06d0617e0703684a118ca90b2d22a7758a1de7732a7144e68b11b7f7 +addc128ba52bf7553b9ba49eff42004d388a02c6b6e9809abe1c0d88f467e5ff6cb0c82a8fd901b80dfc9a001f7b9997 +abf19604a3f0cffefa7a9ced81627f6aacb8d7267b52b825f25d813d9afa24af6d70da21450ed93eaff8b4d2a9b905a9 +a3c67e7bf02dbca183d86924611a7149556ee17cb3469793624da496b6c25617a9071925dd02aab9cb028739cb79043d +b1cea4284a3ac4d5b1c6f0947c6ec8365b3281ed15495bf328a907a9a02cdd186e7cb1ef080385b3399df786855985a9 +a6edb126314559e6129caf1111dc3c82ff914efce658b11f2c9b48081be1cf3f46bde482469d493379025a158d95ab1b +9843fd7dd424da1acc6f92f87fac364a8b0d4097d74b6b451386384966c85145d43fc6ecedf04271b0f963ac731fd93f +83852bedca03a97a2e63053cb102387866cbefe6707ebb6dae2d32a59c343079f1a863f299fd64d0ecbe024d0a1247d5 +a570e645a0679ebc6f0ca03cc8f7367b03c3886f3d9c787992de7f3e93360a170d3ac9ae7720999c727a887b1dc762bb +ad644c40555238f28844eed632c8972b63d2602098031d53b5599d1a874903e0d0c428e0ab12a209ea3fb31225578f1c +b64e9f92a14812ed31075f9fdd3324659a036ef2f293ef9ca6f6feb87d0c138e1ba74bc36a910afd22ff9b3c8ec7cfa5 +8f2d75a86d517dafac09b65596f4b89c4a9c0a7003632407504153fa297c9e3228e236948a5d5224b8df49a087c8e0e3 +b02d6ab9292ae336c8a74115f33765af2c9f62c331d70c087cf4c2979792bb3c2666f6699c017f8d4c6b378fd4bda86a +a923d660d2e55228b8bc74f87d966069bd77c34a776fa96f37b48539c85634482e514e2cb76cb8eb20efd85eb9c83fae +81d7ffb53090a6d512055ecfd582ca92805525a05654e39bb12653a6a8902a16e651ba7b687b36b8bea7186632c7e9e3 +83e9b33e29b57ae53d9f72bd4622ff388252333b4fa32ad360a5b00f3ffc8813b9cb8a1361454d3bb7156c01b94b6a08 +ad7d6bffe4d67eb53b58daa3fc8a5a60790c54fa42226ae12847e94c6de3b4365b3be39855a4f6a5f12e4803cdaed96b +a7709fed85abbee5a2fa49c5238582ec565da08c132d4912821491985bf83b681eb4823634bfe826abd63a6c41a64ea7 +b8fb6ed55741132a1053b6ca77bdf892e96b048488373ba4aa2f2225fae6d578724124eb6975e7518e2bf3d25d215763 +85e0c53089529a09b5bce50f5760af6aeafef9395388aa4b6144ca59953169101783347ee46264ec0163713a25fe7c63 +8f9e47a9c37b678e56c92b38d5b4dab05defc6b9c35b05e28431d54b1d69ac31878c82c1357d016f3e57ca07d82d9c16 +a81f508136ee6ec9122c48584df51637f768ccfe8a0b812af02b122a0fafa9abcc24778bf54143abb79eccebbdde2aac +931a96d2257a4714d1ef20ac0704438481632647b993467e806b1acc4a381cc5a9dec257e63239ba285deb79f92122dd +99fb0ff747bcd44b512bf8a963b3183ce3f0e825a7b92ddd179253e65942a79494a515c0c0bc9345db136b774b0a76b0 +a9dbb940b5f8ab92f2d85fc5999e982e3d990fe9df247cfc6f3a3f8934fb7b70e2d0362ba3a71edc5d0b039db2a5f705 +99011a1e2670b1b142ec68b276ff6b38c1687eed310a79e2b902065bc798618c0cdee7b2009ad49623ed7ae0aa2b5219 +9361e9f3aa859c07924c49f3d6e9b5d39a3df2fc1c10769202ec812955d7d3814c9e6982f4df3a8f3bdbfb4550cd1819 +a8aa23f177ddc1e7a7856da3eac559791d8b3f188c0b3ae7021bcb35dfb72b0f043c3699597a9188200408bc3daf6ab7 +a5a502ff673f6dab7ae4591a7b550c04ede22a45a960c6b5499644f721c62b12b9e08248e7f8b8a59a740b058d2a67e6 +ad374f80f0b52bc5a9491f79a547ce5e4a3ce4468a35d7dbca8a64083af35ab38eff9aa774ccba2e2e1e006e45cb0b85 +ab6851827125e3f869e2b7671a80e2dff3d2d01ce5bfbeb36cbaf30c3d974a2d36fd9f7c3d331bb96d24b33dbd21f307 +96658f6a2d225a82f7ccee7f7a7e476967e31a0cd6c62859d3b13ee89702bb821547f70ffd31cb46a6a0d26a93158883 +878f59ff2590bc3d44fdc674717589800748b78d543d3c0dbb50125b1d6011d6a083f10ab396e36b79f2d89b7cf51cdd +b8bdfb97829c5d973a15172bfe4cb39620af148d496900969bd7ca35de9b0e98eec87af4e20bef1022e5fb6c73952aa0 +a292a78b452743998aee099f5a0b075e88762222da7a10398761030ffcc01128138d0f32fccf3296fcbea4f07b398b5f +85da44fdd7b852a766f66ba8804ed53e1fc54d282f9a6410106c45626df5a4380cbea2b76677fdfde32446a4d313742a +84bebf036073d121e11abc6180cba440465c6eaadc9a0c0853a5f1418f534d21cccf0cfc62533eaeae4653c7b4988046 +923dec006a6af04ef675f5351afffffd2c62a17a98f4144221927c69f4553dd105e4fcc2227b5f493653d758cd7d0352 +a51eda64f4a4410a1cfa080d1f8598e23b59856436eb20a241e11106989fbbb48f14c2251f608cbf9531c7c442b30bf7 +ac6d26ae7bab22d49b7fba7fe4b8cf6d70617977008c8290787c9da1a4759c17c5e441efb3dee706d5d64d9d2ace1de5 +ab5138b94d23c1bf920b2fb54039e8a3c41960a0fe6173261a5503da11ff7b3afdb43204f84a99e99888618a017aac1b +8c85647a91e652190eee4e98a1eec13a09a33f6532926427bf09e038f487e483f7930fbe6ff7a2126ccde989690dc668 +a6026ab87cffec3e47b4c9673957d670cb48c9b968d2ad0e3d624d81c1082dcebbc70d0815cbd0325e0a900d703a6909 +ac4f6ff6baf8374a3c62bdd5a8d207d184ff993f6055bcee1e6dcc54173d756c37c24570d6462395add6f7871d60b1ae +a0dd6bc93930d0016557588f2598b7462ca48cbed637c8190be0fb4811e4576217ca9fc3c669c2a4db82e3f8bb24acaf +a67c1d79f7e7193a23e42928a5cc6a6e8e0c48b6b286607dbcfaaa0f10a7ba29ad62d1d57ca28c486794f0908bece29c +822f411bab4882202ed24e67c84e0c9a8da5b3389804ed9dfba0f672e3e1457ea76cad0cb935dbb3d7a39500fba5fe12 +8a1198572323689300a9d7db2e2bcb7c519392e5d3d33e83cd64bcf1517a7dde52318a98203727b186597702c0eed258 +8a84141b02f1d037c68d92567d71cda3a0b805d1e200b1d3fff3caf9902457cbfbaac33157b87ab0bb9e4fe3bac882c3 +8070ace16d9eef8658fdcf21bed0d6938f948f31ca9d40b8bdb97fc20432cd2a7ef78eeefc991a87eae7f8c81adf9b19 +9522e7123b733ce9ca58ab364509f308a1ead0915421ccede48071a983fd102e81e1634ffa07a9e03766f167f5c7cb5e +82cbdf97a755e952304f5a933fd4d74a3038009f242dac149595439130a815e9cc0065597c0b362130183a4c4a444173 +81e904f9b65cd7049c75f64c7261e0cbb0cc15961ffcac063d09399d0d2b0553b19e7c233aca0f209f90cf50c7f5e0b2 +8f5f6ea87429542ea04ad3eb5fc7eeb28fcf69c01c1a5d29b0de219524f6fba90c26069bfc9092379fe18cb46274393a +a4e5815481eb33b7990d2de1a3a591c1ab545b64fbeb4cff8c71b6bcb04d28940097899062bf43b27c5a8f899616703e +a7afe6066681e312882b3b181f462a1af2139d9bd2aefffae7976f3fc357bfd8fbd6ddd4e5e321412f107736e77f0cb6 +b8ab102d7ff8d46b055095d8fb0ec2f658c9e18eee523c295b148b37f8342c120798113553b8bfebf2a11f27bc704cc4 +862175ecc7e0e294c304a0352cd0f1d11b2603d326bb0e54e02b6cc8d04d01ac31c8864e9395aa1f3b90b76bc4397f5b +a4ea51ef3d82509f0e4eb6af705fa7530921cf9512cb5bf030571e69f4504a299297219a0a7e40db1b45165a5ea3a3f2 +a6fb8b573e2ba6db0e8aba53a489e99bebe533c0fcd947dbfa732e00594f03f4e8609ccc44d8215986d38bc3d4e55d48 +93fe8e0bdd5d66df2bd18be5963e864bddfcdcd3298590e7c3b11d99a070a4948fecef46453f19960bbfeada37979613 +acbc45bc55c7080b45c69a3db80cbfc0267006dcf49c47330975aeff2a8ac07b206e1b1c3a515e50866ff510739b92c0 +94a577df0983e4ee3d6b80c73d7e8e3bb78bd8390ff56fea350e51bdf5e0176b8494e7e81dc7b1d842ada961089cd1eb +81eb1fbe9e9c89f5818d0ef98e694da86e88625f0a37cfe88e6de69f90e58297e67f1d5c9d71263b523b63e42685975a +a81a2391ea4d0f65ab4325196559d67e2648b3f1e464509430b40d9948d5b0fc01c337d9b51048a93c4d62e6b73e1e8c +849a026e55ed77135138836c9df67883763e4602357d8566da2ee2505d135d44061de0c070cf333ffb9ac2e55a0894b2 +8e272cc5734374c003c7b2e6ba833eb99b6be608da04e576df471c24705b6b2a790549c53e7971df2d9f0b88d0f570c6 +b0f9e6d985064aa311d4a147f41007fdc576b7b9194aa4b8712bf59a76a71543fec2ee3db21bd3d30d4096f25babc543 +96331837f0d74e2ba6cb1bfaddf4b1fb359bf46cb6c3c664938eb030e56bc85a5ce17bcd60b7fa7b72cb0ba1f3af0b5b +a0eaab6de4b5a551896e7d26153fb5df4bc22a37833ec864090b57b5115b0f8f1279e855cea456bb844802b294b0dbb7 +955e87d3b966edff34f28137f871881c59bbbc6d69986b739867807680ca22b5e3272ced1d25854ed9700d87f133848b +9270a6db157a8ce78a1af6bfe2b5bbe7b621d56cc8f9940a03b5a5f600848b87b05d83595b2a3a315d4b7f4687c46085 +9043328f2dd4dd85e14c91237a3478dc1eed239164924b53d1de9364d76c81315afa9639b58eedb1ab2122e2ae2e7cfb +857fe9f7d00b03bce367de7f789d755911a5f85d78044f18311ecd9b955e821b4a50228347260ba1205aef61219001fe +a0f878050367a7103fddf380908da66058ef4430eae1758335c46c24f5c22fefb0753991b3a47dba5c7eaafa4d598178 +ab5959296b1af14d2878816c7da9926484cbf8896b7eeac8a99dc255013319a67a0209025e1f8266ffd8cd7d960bdc87 +abe53abc57ea46419dbe0ac1f39eee39a4feae265e58b50928eb0695e25938a16a8b00e65c1313837dc3367297e2c258 +93e3e42ed6ba9c45d4e7a4bf21c1e469efafded1f3be9931a683dbb780db2494742fd76c9ad29fd7d12da2b778ede543 +ab3e64035c488a6e63496ddb2de9648cc63a670c5d4b610c187d8ceb144fcc50b016046f50b10e93b82937ebe932ac08 +a3a8fa898f489b313d31838ad9f0c7ffe62ef7155de5da9ffe6ecd49a984fac3c6763e8cb64e675e1c4a0e45e7daf078 +8356b26aa7c9fc9734b511480dad07b164cfec1324ad98eec9839a7943f2889d37c188d465515ad4e47c23df641c18c3 +83c4476f829e0fe91da2353d5b58091e9335157941e89ca60ccab1d7fdd014bcf21bd55249805780ddc655c5c8c2536e +814f6e66505b2cb36de92c0de8004d6d094476522e66b9537787beff8f71a1381ed9f2b7d86778979ad016a7dae6cbac +b1cd7f6da4a625b82bea475442f65d1caa881b0f7ce0d37d4b12134d3f1beb3ad4c2f25f352811e618c446185486adb6 +a71b918481b9bda667de0533292d81396853a3b7e2504edd63904400511f1a29891564d0091409f1de61276d2aebc12a +a2cd3d4104ec5fb6d75f5f34762d5e7d2ff0b261bea5f40a00deec08fbdab730721231a214e4df9b47685d5bacfe37c6 +807f2d9de1399093bf284814bc4093f448f56a9bde0169407cdc0e7d2a34ff45052aef18bcb92f0ac7a0a5e54bd843e9 +abeb03010c3ac38587be2547890a8476dd166ac7b2a92c50d442f031eaf273ad97114c38e57fe76d662c3e615334ac0b +b90a688da4b0bf65ff01bcf8699f0cba995b3397fcbe472e876ae1091a294463e4b94350ae8bd5c63b8441089e0884fd +ad88db4afb177931788fb08eff187e15ad739edc7e1a14c8b777b6bf668aec69ca4749773f94250c1fdda3b59f705f7c +9886809f9ae952797c6527c6db297d2aa3d5209b360efe6a19970575a9f78aee3c21daadb8e8dfcbeeea5290238d16d9 +930f486e95d7c053c9742e6f0b31e6d4fa2187e41229e46a074b469aafb87880aa8e972719b363049fc9fe2db8f03ce2 +8d229af4fa08bd8aeb5fd9acfee47571eb03fcd2f19073b94cd27e2a6735029d31f123249d557f8d20c32ac881eae3aa +84576ed5aebe3a9c3449243a25247628993fdb2cc327072418ea2f1d11342756e56e9a82449bc3ea6e8eaecabc62e9b5 +b775cb86cbec9c46a4a93d426379c62872c85dd08bccda39b21cb471222b85b93afd34a53337b6d258f4891c6458e502 +8be1540e6b535b416b8d21e3ecf67dfb27a10fd4010f9f19426422edaeb0a4961d43ff3afd1db0994170056ce4d77aec +b9c7438e90a5501a4d05bbb8ab68d6db7e9baa8927231a5c58715ee2ab76ca1da0e94910a076958654869148d813d0e9 +aa9bed1c4d2e7cbc2e1a884c8998773f7cc6fa9d6493c8abe8b425114a48305c3a43a1abda2292177ffd39ef02db4163 +897b395356047cd86f576cfc050f7e4546ecd4df30b2c31ed8945797b81dd4ed9b9106cfbe6d7dd8bf91882e3cf1f42e +949a37e1037d9464b2ccd3ad23eda7089570d6b5ffa18025d2548a9df8829de8d62960f04a603f21eecbca5893d45284 +b8a0642f68ff169ffbcd8cd684fae75d96f9bd76949472775bf155edc55a3d9c3e6f0299ee73a6cfb96289361fdbe9ee +a1273141510fcddd89b9b92c19a268dadd1528ad85744b8174684c9b56668e6b35dabb05f2b4cc6ef5611eaea6052f27 +97c7415c82de83ecc066eb922268b8205ad7266c65b2b8f7e0aadac87f076c738cea72f9b0f069b8d28cf9d5438b8287 +b32c7005380c848f71092a74297555dc6022369fc2a4f285e586ac8f53f6bd354fbe4b1f8a4cfb406a101103bf87bb64 +91b48eeba52f02d04f536d32112038f8ba70bb34284fbb39e0f7bae2e08b3f45ad32e2f55d1beae94b949c15652d06a1 +99e24f5ea378cb816a4436af2ee7891ac78a2e37c72590be0abd619244a190fee51fc701b6c1c073611b412cb76332c9 +9465d1e73a1a0a5f7b1cd85f4fa4f5dee008b622b14d228d5cd5baeec174451e7ae93c5de688393d37cc24ce15df4139 +a6ac3986ee01debdacb5ddc1e2550cb4f039156df15c7d5752b79f333175b840bdca89c4959a523e58cf97bbd6b2039e +b7f7a5cc1b1b6145988170d619c170c130231abbe0b5143a9bccaaebeef9ceb1c16e26749bc9dc5650fe91f92fa1b79b +854cb04f1557457383a401d79a655adfd0a4b706ea2bbc6262949c8d657efcfdc9c7960cbe1a50b5eebb361c5e378f80 +8dd199dccbdc85aeca9ddcb5a78dd741a452f7a0d3ceb6546d76624bad2fce0e7e6c47ee30d60bf773f18d98503e7f9c +889e1ca9f0582be9bf5f1aede6a7312b30ea9bed45ab02d87182a013430f16007ae477ee6a823ae86c7fef7da016a0ec +892a60e63edfb3e7a6cf2d0be184413d214401fc1e6c004ca2902c3f1423728bf759a136e6e715d26d5bb229c75cc20a +a2287cd092261b39d22dcb1fa19512590b244771bb69fb62eda72f12be37d48e408b3e37a47608f68d743834edee7f15 +b3b6afb950bbec0ff631bdf18af433e68adc63d02cb479704f24329ca6b6edd9a3d1d606563dbdce6038b676b85130b9 +847da90f37b294509de51ab6521fdff12d5a1ec3cccaf730aa744da7e54b85fd9c70618787e87c0ba9947ce6c81387fb +ad872153c00bccac75bdb30d1ab7044d814f4f8655ff26421d48fea04fb21d4dc82c1900620a57d13adc45c1062a1817 +90fa5ee98fd7ec719f2a8543bbd0ff45ac69296c2416fc8666d05de3deea1017079a68aba55540a19585925803c8335d +962ba6d029e9176d0e8c80a21f2413f7322f22a9e9a32c933697a8b0e995ce25bea5264736a75718b3d330e215a58a05 +a446f9530db30c5e9c1b3844d635e5c2cd311cc4537ff277fe83dd1a0382bcfa73beb07aaa0cf5a97d24c67e688086a4 +8766b2053f16c72db387abe18b43d7b357a542916c9b8d530ee264e921c999494d6eb1e491352ecdf53758640c7a246d +83f32f511f7b0233662acfc14f30df345af99d2d6c777ce0b4bcdc4dd110533f30b45071df17230aaec392cc482355e1 +82e3521bc9519b36f0cc020225586b263e4feb57b533b38d8e89ccf8d03f301d94da90efb4902002732fbf3876697f38 +b5d1ea69c97ceaa34a720bb67af3fcf0c24293df37a5f6d06268b1eabe441531606954ac2598a1513f64231af722b3a3 +956842696b411e6221c5064e6f16739e731497e074326ef9517b095671f52a19e792d93fe1b99b5a99a5dc29782a5deb +b19b5658e55c279eb4b0c19a0807865858cbec1255acd621f6d60c7e9c50e5d3ee57da76b133580899a97c09f1dd8dac +89e6a8b916d3fcc8607790e5da7e391f6bc9eae44cc7665eb326a230b02bc4eb4ef66e608ccc6031048fc682529833d0 +b1a210bc8070ed68b79debd0ec8f24ec5241457b2d79fd651e5d12ceb7920e0136c3e0260bc75c7ff23a470da90d8de9 +85b1954278e2c69007ad3ab9be663ad23ae37c8e7fa9bc8bd64143184d51aea913a25b954471b8badc9e49078146f5ac +98bf63c7a4b200f3ce6bf99e98543925bc02659dc76dfedebe91ec5c8877d1271973a6e75dad1d56c54d5844617313e1 +b7404b6e0f320889e2a0a9c3c8238b918b5eb37bcdab6925c9c8865e22192ba9be2b7d408e1ea921a71af3f4d46806d0 +b73cbbebf1d89801aa838475be27c15b901f27d1052072d8317dcae630ab2af0986e56e755431f1c93f96cd249f2c564 +95b2027302f7f536e009f8a63018da6c91ec2b2733c07f526cc34cbcfa2f895ccfd3cc70be89f4e92c63c7ddc2a93370 +9201d9ff5d0b1222bfa2345394f88ddf4fe9282acf51bee9b18b96bb724fdf8e736d7101acc2795a34e72f9e0545c9a8 +acbff7eb160f427d8de6f29feeddfa8994674e033a0ccdc8e8c73f9243968f1a6379da670a7340f422892d50c97113c7 +97ae8d03352c3729e1623e680dd9664f303b3bcfb844ef80d21e9c773a247967d27b86c9326af29db5eefd0bd3d4fac8 +8e53ae5c22f5bfa5fe4c414dad6a10b28a3e5b82a22e24a94e50ce3b2bf41af31e7ba017d2968811c179017b78741ef0 +b5ac7dd150247eb63dfb7dd28f64b1bf14426dc3c95c941e8e92750c206c4c7f4ad1a6b89e777cfe26ecb680dbf0acb6 +99ae2e4652ea1c1c695e7ea2022fd35bd72b1a0d145c0b050da1be48ad781a413dc20fbda1b0b538881d4421e7609286 +b8abe1fb3a7443f19cd8b687a45e68364842fc8c23d5af5ec85da41d73afb6840ef4b160d022b2dad1a75456d809e80b +842619c3547e44db805127c462f5964551f296a270ed2b922e271f9dc1074fdf1c5e45bb31686cec55cb816d77853c01 +902dff769391de4e241a98c3ed759436e018e82b2c50b57147552bb94baddd1f66530915555e45404df9e7101b20e607 +82e4f2ee7c7ca1ee8f38afa295d884e0629a509c909a5464eb9ea6b2d089205478120eed7b6049b077b2df685ec8ba48 +aa21a68b0888e4a98b919002a7e71e6876b4eb42227858bf48c82daf664c3870df49e4d5f6363c05878a9a00a0bcf178 +a8420cd71b1d8edd11ebc6a52ba7fc82da87dd0a1af386d5471b8b5362c4f42718338bcbc302d53794204a0a06b0671d +98c686bd3a994668fbbd80c472eed8aedd3ab5aa730c8d3ce72e63fb70742e58525437be1f260b7ecc6d9d18a43356a0 +aca0b2df9ec8ede0b72f03b121cded5387d9f472b8c1f3a5f1badd5879fb2d5d0bbb6af1a2dd6bdebf758cfceadbe61d +93b1abd9cb41da1422d171b4dbf6fbcb5421189c48e85c9b8492d0597838f5845198494c13032e631c32456054598e1d +a246ab3a47f7dc5caedc26c6c2f0f3f303ed24188844ab67a3da1e793d64c7c7fe3e5cc46efafbd791b751e71de0614c +b9b52095ca98f1f07f3b0f568dd8462b4056c7350c449aa6ce10e5e8e313c2516ac4b303a4fc521fe51faf9bf7766ce9 +8e2e9d26036e847c2a2e4ba25706a465ac9fbb27804a243e3f1da15dd4084f184e37808661ec929479d3c735555085ee +8b8c4f4ad5c8e57e6a7c55d70ef643083d4b8dac02716ea476d02dbbb16c702a2f2d5dd5efe3aec7704d2b8cdafe3959 +a800afea30d0df333805d295bac25419b7049d70044be00c7c85a92a0503ca471001bc1e6552323f1a719eb96616fc20 +868bced4560e1495b8527058ebc82a538b7cf806f8d8fe8eeed6981aba771de4d5e9f03cbfc7157d38b9f99cdea87b96 +86b86258b0c1feb988cc79f6c4d4b458ff39428eda292f9608a5fc4c3765782c8c23c66f82d7538e78e092cd81d69a56 +9370eac15de2555824c7d48520a678316a7bb672e66f8115ad7dbc7c7b1f35a7718e8fa0c35f37e3ef2df32dfa7ca8d1 +ae200bc5be0c1c8c6ec8e9fd28b4d256c6f806c0f270766099e191e256d67b9cceda2cc2fed46dfa2d410971a7408993 +af2428c77b2b9887ecde1ea835ed53c04891547fb79fe92e92f9c6009cdfffa0cb14de390532ad0ef81348b91798bd47 +a9069eef0316a5d13d1aa4cef0cf9431518f99b916c8d734bd27b789828ae03e5870837163ea6ad0be67c69184b31e8d +b1b1ce6d529f5a8f80728173b2f873c8357f29644b00f619c15111224377ae31a2efb98f7e0c06f5f868030aab78ed52 +b89c98beef19ee7f300e1c332a91569618ef8bf2c1d3de284fc393d45f036e2335d54917c762f7c2874a03fe4f0f6926 +8264f993dceb202f8426339183157e9e0e026d4e935efe4cf957eb14cd53edcdc866305fb1334cdf0e819b69eafbaccf +aebd113f73210b11f5ac75b474f70a2005e5c349345003989175dffa19f168abd7f0e28125b18907502fff6fcc6f769b +9993ad061066ca6c2bb29fe258a645089184c5a5a2ef22c811352749a199be3a3af3a0d5ce963febf20b7d9e63508139 +97952105000c6fc6c2dcae1ebdb2feae64f578d26a5523807d88e6caf1fe944b8185e49222d06a4553b3bdb48c3267a2 +82dd955f208957d74693bed78d479c9663f7d911f68ff033929418eb4a5c5dc467589ca210c1ba3c2e37d18f04afe887 +b816fc4763d4c8a1d64a549c4ef22918e045ea25fa394272c7e8a46dcb0c84d843d323a68cc3b2ef47a5bbb11b3913bc +a7a87ba4d12a60ee459aad306309b66b935d0c6115a5d62a8738482f89e4f80d533c7bba8503e0d53e9e11a7fd5fe72b +92b36d8fa2fdee71b7eea62a5cc739be518d0ecf5056f93e30b8169c3729a6a7ed3aa44c329aa1990809142e0e5e2b15 +8835b6cf207b4499529a9034997d2d3bc2054e35937038deb9c3e2f729ebd97125f111c12816d30b716b397016133c52 +acf14cd6d978ba905cf33b9839b386958b7a262b41cbd15e0d3a9d4ef191fcc598c5ab5681cf63bc722fe8acfda25ce6 +b31302881969c5b283c6df90971f4fb2cc8b9a5da8073662da4029f7977fbb4aaa57dd95b003a9e509c817b739f964e7 +b74669e1c3fa7f435e15b5e81f40de6cfb4ad252fcdfb29862724b0a540f373d6e26c3d600471c7421b60a1d43dbeb0f +861d01615cba6ca4e4ef86b8b90f37fa9a4cc65cef25d12370f7e3313b33bb75de0953c8e69972b3c2a54fe110f2a520 +a58a56820efaf9572fd0f487542aaff37171d5db4a5d25bfb1a5c36ca975eb5df3cb3f427589e1101494abb96b5e4031 +af13d0a6869ef95cb8025367c0a12350800c6bc4ae5b5856dcb0a3ca495211d4139f30a8682d848cb7c05c14ae9f48cb +8c385767d49ba85b25a3a00026dd6a3052e09cd28809d5a1374edf4f02dc1beed367055b0dee09102c85985492b90333 +b5129fc2fec76711449f0fcb057f9cf65add01b254900c425e89b593b8d395fc53bb0a83ddbd3166acc6d2c17f7fc2a4 +86bd01b3417d192341518ad4abf1b59190d9c1829041e6f621068bce0bef77ec3b86875b7803cf84ff93c053c2e9aad1 +a74fc276f6af05348b5fabccb03179540858e55594eb8d42417788438c574784919fb6297460f698bd0da31ce84cebfc +967ed3ec9f1fc51f76f07b956e1568d597f59840ef899472a3138f8af4b4c90861e23690c56b7db536f4dd477f23add6 +b9e678206de4fc1437c62d63814d65f3496be25a7a452e53d719981d09c7e3cae75e6475f00474e7c8a589e2e0c6bfa3 +b028eaffaa4ff2b1b508886ff13c522d0b6881998e60e06b83abe2ac1b69f036eece3ded0f95e9ae721aea02efff17b6 +935f82de9be578c12de99707af6905c04c30a993a70e20c7e9dd2088c05660e361942fa3099db14f55a73097bfd32a44 +96a1cc133997d6420a45555611af8bcd09a4c7dbddf11dbe65aab7688cc5a397485596c21d67d1c60aae9d840f2d8e48 +80d117b25aa1a78e5d92ea50e8f1e932d632d8b37bebf444dcc76cc409322fb8eface74a5dddab101e793ff0a31f0a53 +893229136d5ab555dc3217fb4e8c6d785b5e97a306cdaa62f98c95bad7b5558ed43e9a62a87af39630a1563abd56ec54 +b7ec1973ec60bd61d34201a7f8f7d89d2bc468c8edc772a0ba4b886785f4dadc979e23d37b9f7ef3ff7d2101d3aa8947 +b6080ca201d99205a90953b50fc0d1bd5efd5eadbfe5014db2aeb2e1874d645ab152fb4b0ff836f691b013b98ce7c010 +b546e66ec0c39037bbaa66b2b3f4704a6a72cf1924a561550564b6fcf41fbc2930e708cd5cac1d05e12a4b8ec93ff7eb +8abeed90a01477260f4b09fff8fa00e93afe727e8eed6f111d225c872a67e6ab61d0472ab6add3fe987744e16f7c5268 +8e02342d5cc1836ed21834b9ef81686172cc730f0412479db5f590b0ff7a729a0e986ffed16d6ecafd6b83d65922ca5e +b05660605cf8e8a10c8d3c77cccbe4e7179fa27cc829571f6b722a58e65e4e44d7fe977446118e9da2d2f40af146cc2d +942a00e006baba6d025cbd99297bdb0cbf3d84cddf849b1b5a9fe9ef1745352fad81313cce5d7622d6652096a8fa065c +aace8212b3d8dbe44ac97460a5938a3b803aca9bd00d8a643a859351daf391b22d1fd2a6b3e0ff83cc9ee272a1ad7686 +965a9885a5259197a75a19707a2f040e0fd62505e00e35ebe5041d8467596752aedf0b7ec12111689eceb3e2e01ecfc8 +81d58270a4e7ee0137cb2bf559c78c4fd5b3a613468a8157b6a9c5c0b6ca20a071b87c127d59cecc3d0359237a66d890 +af92b6354fbf35674abf005cb109edc5d95845e3d84b968e6001c4b83d548715dffc6723ac754c45a5ace8cd7dd30a24 +b112caa707f9be48fdde27f1649149d9456857f928ea73e05b64bb62d597801daac0b89165fea76074f8b5770043f673 +b6e7380746da358fc429f676b3d800341e7ab3f9072c271310626ae7f67b62562ff76c63bc9f5a1dbc0e0af87752408a +a45e9e8d0931207ebc75199aa0c983134aa97f771ff546a94a3367bcedf14486f761e7f572cf112e8c412018995fdaf4 +854381128de5bfb79c67b3820f3005555f3ee6f1200046ebbfaee4b61b3b80a9cebf059c363a76b601ff574b8dbf0e6b +aa1b828a8b015d7c879669d5b729709f20a2614be6af6ff43b9c09b031f725f15b30cde63521edda6cd4cf9e4ab4b840 +8f28f6b62c744084eeddcb756eced786c33725f0f255e5999af32b81d6c6506a3f83b99a46c68fc822643339fe1b91c5 +ac584e76a74cafe4298ca4954c5189ccc0cc92840c42f557c40e65a173ea2a5cd4ae9d9f9b4211c9e3dfd6471fc03a1b +a413365df01db91e6a9933d52ab3e5ed22d7f36a5585ad6054e96753b832e363484fb388c82d808d1e4dfb77f836eab9 +8a68c51006d45bf1454a6c48a2923a6dbeb04bd78b720bb6921a3ca64c007043937498557f0a157262aac906f84f9bf8 +b93ff8b6c8c569cc90ee00cfe2fc3c23cccea2d69cbca98a4007554878311635cb3b6582f91636006c47b97e989fe53d +b9a8a44d54592511d74c92f6a64d4a8c539a1d8949916ef3773e544f6f72c19a79577de9878433bd35bb5f14d92f411d +94f066a7e49ae88d497893e4ce6d34edc2dc0b42fe03934da5d4ed264d1620d506fcc0661faa90a6cf5083e1720beaaf +b42b102adef8f42c1059b5ca90fe3524dcd633cf49893b04b4a97a1b932ca4c7f305cebd89f466d5c79e246bad9c5ced +86b560d78d3c5fb24a81317c32912b92f6ea644e9bedfdea224a2f0e069f87d59e6680b36c18b3b955c43c52f0a9d040 +a3829fa7e017c934fa999779c50618c6fb5eafb5e6dec0183f7254708a275c94ba6d2226c5ca0c0c357b2f2b053eea93 +9337dda730076da88798fd50faed1efa062f7936a8879ea4658c41d4fcf18cee7120366100d574536e71f2f11271b574 +853d09a30f4342f5a84c4758e4f55517a9c878b9b3f8f19e1362be9ae85ca0d79c2d4a1c0c14f5eff86010ad21476a7a +b0bc74cb69bdd8fdffca647979e693ad5cbf12a9f4ead139162fa3263bfebef3d085aab424ed8c6220b655228c63c6b1 +88d8dc8faf3aab12ba7180550e6a047f00d63798775b038e4a43a3b40a421a3f5f152a7e09f28ccd7198bb8cefc40c07 +88db2e3b8746415d0c3e9f5706eda69a29d0b9ee5135ad006060be7787f4f1f7069e2e2e693c5e10b7c3d5a949085ae0 +b5bd830d2f1c722188dba2690d21b7b84b92cbdd873a55aaa966f1d08d217bfc8cffe8caea68868f3850b90b4ab68439 +b5ad4be0c9626a33fce6c8501297bdde21b07b88531451912ed41971a4c48fdd1036d8a4994a99a7fbba4a5901a7095e +b0e1337a2a1772191faa91302f1e562e7cdc69ba5b25139e7728ce778a68a7fa9817f852ec8e04a159122cff62992ec6 +b4fd4a4c1be8bc7e4e2bfd45404c35d65b75f45fb19ce55c213a8035b41f1ccbce9766f3df687c0d7cd6cdfc1abb00a5 +814bf565ece6e9e2a094ffbd101f0b9fea7f315a2f4917abe2bf7d070ed8c64a2987bd288385a42fd336ed0a70a9d132 +af860af861dc80894ed69f29c8601d986917ec4add3d3f7c933a5e9d540bc8ff8e4e79d0bb01bbc08fa19ef062f2890c +b66d33fcf3cd28f15111960ffc6ed032c3b33d4bb53d035ab460cc5fa7ce78872f0476d0bb13f1d38f2672347d2d6c4d +89603ae1a5dd7c526936b86a3b69b7b1d0bdf79ba3cc9cc2e542ec801a6126d1514c075d6ad119fe6b6e95544ffe7fbe +8a1b097f46a62d85cff354d1e38df19a9619875aad055cc6313fdb17e2866d8f837a369a9ee56d4f57995e2b0a94310e +8dc165d86c7f80b0fcd4b6f90d96cd11dc62e61d4aae27594e661d5b08ef6c91156c749de8948adfaf3265b1d13e21cf +98e3173772c3b083b728040b8e0ee01dc717b74c48b79669dd9d2f7da207af64ccd7e9244bc21438a5d4ac79b88e9822 +924d168099b6952d6fe615355851f2b474f6edfcd6a4bd3ad2972e6e45c31bf0a7fb6f7fca5879a0de3ea99830cfb5bc +95452f0b7efda93c9e7a99348e13f356bad4350f60fcd246a8f2aa5f595a9505d05ec9f88b1fe01b90ecd781027b9856 +b95e8af516bb0941fc0767ecd651ada2bc64cc3e5c67a1f70048c634260c0f2c0e55ed22948e1870c54590b36683a977 +82f7feb71e746d5ca24455e3f3e57e4eade92669ab043e877b836612efd3de82009f0555e5d8811bff9f2b75fc57a01d +87623c02caf590ea84cf4a84d1be501f89262e26eb463f2f94a2d3042889c051b058823c3367a989498e46ff25edab16 +b88da847b1ef74c66f923773ce8c920ca89751335fde17b3a98c0603862069a2afbf35b1552b43ad64dccea69f040ff8 +96b734758c823e5ce5b44625c252957e16fa09f87f869baac195956052dc92f933f377b288c7f63b8028751cbbdca609 +a23cc5fbbe5cb7c1d33d433cec4e502f6548412e2374e285d307f75e98280b0c0af4f46bba18015be88cdf7db8b1239c +8bd5bbe04bc929ca8f546e673803ec79602f66ec24298d3e3b6bf6f2c25180fc0032ea6f86c38a6e0ec20ff4eaafc7a1 +b95768ca113e5d57ad887a1cb5ef84ce89007ce34c3156cd80b9aa891f3ebaa52b74c0cb42919cfbcf0cb8bafa8085f9 +a117f99045f65e88acc5a14fc944f8363f466e4a64057eb8fc64569da5dd022a01f2860c8e21b16aff98aebdf89461b7 +895cda6503907c98c43477eaf71dfd26759032523691659f13662ca3a967d93bbc5be342d168223cef7e8a333987d6a0 +a084d77d913d3ec0586ad5df2647610c7ed1f592e06a4993a5914f41994a29c4a8492d9dce2e14d8130c872d20722920 +84a328b73c64137bb97a0a289b56b12060fa186ce178f46fe96648402f1b6a97d1c6c7b75321e4b546046c726add5a08 +b7c35087b2c95127ce1470d97bceb8d873a7ad11a8034cc1cba7b60d56f7e882fc06796048435a9586eab25880787804 +ab05e3394375ee617c39c25c0ec76e8a7f2381954650c94fbcd11063ea6772c1823c693d2d9dd18bd540a130d7b92855 +82ba5907051d84b37fd9d28f8b9abebc41fc4aaa334570516ca2e848846644016356d40fa9314543017d4f710d193901 +9170517b6e23ee2b87ff7c930cb02b3e6bd8e2ae446107b5b19e269bf88f08de5ded3d81a2ff71b632ca8b8f933253a0 +93dc0e3f6234b756cdbb3fe473b9214e970972e6bf70803f4e2bf25b195b60075177a1a16382f1dee612a4758aa076ee +b4b49fac49cdfccda33db991994a8e26ab97366545166cc7140aef3d965529f96a5dac14d038191af4fb9beb020ff6d5 +b826537670acdf7a8a45ef4a422d5ae5a1b5416ad0b938307518d103cc7ba78e495ea200adc5941414a70158a366e8a2 +8ae3588b1fbecbc769c761f0390d888e34773cf521d976ee335f6c813bf06dad38850871ac8a8e16528684f1e093d0c1 +ad9c00b8dccdb545315fbf26849135699c6aa3735f89581244281154c906aba80d20c1e7f18f41acc61e0565f8015a33 +954ce68146c05fc1c9e536add3d4f702335d93c1650b8c1fad893722a81f915eee2d38275dad00ce87f3f5bc90ef7341 +8243feaeff9a12f5aeb782e3dd68609ce04ecde897c90fd8a19c9c5dace3cf43bd5bc0f1624bf7fd2607ca0d71adbba8 +a8a1be55259cd27898d9d60a61998d8da2bf2d439ba6eedb61d6d16dacc4a81ec706b9196dfa080ba20701d2cd9fa1f4 +b0eac6212c7a62ef6062c30875fbe24b8e1a9d88854c035686f849a9eed4d17fbc9af27429eb7c3fd60b47a5e29f6783 +878561a88412e95f19f1cb8894be9d0ea4a2cdd44f343387f87dd37445e5777bceb643cebc68c910acb5e588c509cd2e +a57b6c347955d8b0057a87494223148ff9ff12b88e79dbd9d0aae352fe55e15ea57fcfb9add3d5d269ee0001d8660f20 +a07fa66340d4082585e4d72c77510c59b272e7a3345f4b1de6be7ff4a11ea95d712d035a7355fc8d2e571fa65fe8236f +b9d84a627462438e8ede6c453e3367bfaf81cff199d3e5157ef2bc582d358b28b5ccc3bc27bb73af98ef45179ea79caf +b14f26ea7ca558761cb19508e5940fbf5dcf2ad8555c5a03e8ff92481994072f523b1ab6b7176f698e2cfd83d4f8caad +800cca1cbb14e1fc230c7b420ff06864a934b082321bbf5b71f37340383923f23183d4fdc8fa2913928722b8892db28e +94790c950b92e971ec39e9396c3f32dee32a8275d78e6ea28a47130651bddc86a189ef404c5e8c210bd291186dee0df4 +ad7b3b3e377df64023b8726d43a7b6ec81e5a5e8c0943c5bebe5ab5ddd6597255f434a205c14ba90e9e5e3c462a1fe0c +86ff8156cc857a416e735009cf656b89da59b766b4c4e5a0c0165282b530c10657cc28cf5cb847696725c37ac48b69d7 +89cb64cf9294f68f01533660a2af2aec0ec34cc0b4a0cc36a128f2e0efb3da244981f69aede962f50590faeeb9a5da01 +a2ea5a94a524bb8e6f767017246cd1af9d87c9abb9894e91c4e90c34c5161be6179b49dafcab9cff877a522c76beb145 +b5d9abf29ed6030a1e0f9dc19be416c45ba8cb5ed21aff5492233e114035715d77405d574cd62f2716285e49f79b9c99 +ac441cf6104473420babdfb74c76459cbea901f56938723de7ad3c2d3fadb0c47f19c8d9cb15a3ff374e01480b78a813 +abea34bd2d36c5c15f6f1cdd906eb887f0dd89726279925dbe20546609178afd7c37676c1db9687bc7c7ea794516af03 +8140abfd0ec5ca60ef21ad1f9aabbb41c4198bac0198cb4d220e8d26864eedb77af438349a89ca4c3ff0f732709d41a9 +a5a25abf69f3acd7745facb275d85df23e0f1f4104e7a3d2d533c0b98af80477a26ac3cf5a73117db8954d08f9c67222 +b45ac8d221a7e726ad2233ba66f46e83ed7d84dbe68182a00a0cf10020b6d4872f3707d90a6da85f6440c093914c4efa +80f586dfd0ceaa8844441c3337195ba5392c1c655403a1d6375f441e89d86ce678b207be5698c120166999576611b157 +b8ce52089e687d77408d69f2d1e4f160a640778466489d93b0ec4281db68564b544ec1228b5ab03e518a12a365915e49 +8990f80bae5f61542cc07cb625d988800954aa6d3b2af1997415f35bd12d3602071503b9483c27db4197f0f1f84a97ac +8329858a37285249d37225b44b68e4e70efeef45f889d2d62de4e60bd89dde32e98e40e2422f7908e244f5bd4ffc9fe2 +8d70c66ea780c68735283ed8832dc10b99d3daeb18329c8a44a99611a3f49542e215bf4066ff4232d36ad72f1a17ccc3 +a3b2676cc8cdf4cc9e38c6cb8482c088e5e422163357da3b7586a3768030f851ad2a138eeb31584845be9ffb8067fc00 +95b1fa74e9f429c26d84a8e3c500c943c585ad8df3ce3aea1f6ab3d6c5d0ed8bb8fa5c2e50dd395fa8d4d40e30f26947 +b1185f2ac7ada67b63a06d2aa42c4970ca8ef4233d4f87c8ffa14a712a211b1ffde0752916bfafdfa739be30e39af15d +8705a8f86db7c4ecd3fd8cc42dd8c9844eab06b27d66809dc1e893ece07186c57b615eab957a623a7cf3283ddc880107 +af6356b372f0280658744c355051f38ff086f5563491fc1b3b1c22cfec41d5c42b47762baeb9ee6c2d9be59efd21d2b7 +86bdd4527b6fe79872740d399bc2ebf6c92c423f629cdfcd5ece58e8ed86e797378a2485ead87cbb5e2f91ba7b3fbda1 +a900f0be1785b7f1fda90b8aedd17172d389c55907f01c2dfb9da07c4dc4743cb385e94f1b0fc907dd0fedb6c52e0979 +a9f59f79829a9e3d9a591e4408eaec68782c30bc148d16eb6ae2efccb0e5478830bbdaa4ae6eac1f1088e7de2a60f542 +99cf54a69ad5e8c8ec2c67880900e0202bcc90c9815531d66de8866c0a06489ea750745cc3e3aa1c4d5cb55dcd1e88f7 +8676246a4710d6d73066f23078e09b3fa19411af067258e0b8790456525c02081727b585d6f428c8be285da4aa775a4b +b596c7014fe9214529c8e6b7602f501f796b545b8c70dbf3d47acc88e2f5afd65dccef2ef01010df31f03653566b16df +a12205c6c1780fc8aebdd98611e12180005b57750d40210b9eff0396d06023bd4ff7e45f36777123ff8bed7c5f52e7a3 +ae7dbd435bba81685d5eab9abc806e620253da83e56b4170952852d442648a5d8743f494a4b0fc9d606574f87895b0d6 +9786257b1726b7cdc85219ca9eec415f98f5a11e78027c67c7b38f36f29fe7a56443570fdfedc1d9293a50e4c89d89f6 +aaf0515070d1ca92aacdf5fac84193d98473d8eb2592381f391b8599bcd7503dbf23055324399d84f75b4278a601c8b2 +b31654dbf62fbbe24db4055f750f43b47f199a2f03c4d5b7155645276b2e456a218ca133743fb29d6f1a711977323f6e +8f4d39106ecdca55c1122346bdaaac7f3589d0cf0897a6b4b69e14b4d60550fd017876399401ce7c5d35f27da95f50be +8a7bfdb48cd47afe94aff705fac65f260b3a3359223cff159b4135565c04b544dd889f6c9a6686f417e6081ad01e0685 +967ba91111e5e08f9befcbaad031c4fb193776320989f8ede4018254be0e94586254432d3dbae1455014f3a2f2549d01 +a9db52352feeb76715a35c8bed49fb3a8774c9c8e58838febf800285fd6c4938ec162eb8457029e6984d8397dc79ea19 +811794e6bfe2539e8f6d5397c6058876e9e30763ad20dad942bb5dbcab2f16d51718ce52bfb4de17889ba91da1b85bcd +a6db0f65a6dc8b8cc2312a3e0146d8daf520255bb12f74874c05693914e64e92be0cd53d479c72cb2591e7725dfaf8b0 +918d21bfa06d166e9eb5b7875c600663a0f19cc88c8e14412319d7aa982e3365f2dff79c09c915fc45013f6b3a21200d +9894852b7d5d7f8d335dd5f0f3d455b98f1525ad896fdd54c020eeaf52824cc0277ecbfa242001070dc83368e219b76d +ad00acc47080c31fcc17566b29b9f1f19ccaae9e85a312a8dcc0340965c4db17e6c8bd085b327eaf867f72966bf61452 +965e74649e35696744ecc8bed1589700bae9ca83978966f602cf4d9518074a9aa7c29bc81d36e868a0161293f5a96e95 +961e29a239c2e0e0999b834e430b8edfe481eb024cc54ffaffd14edaf4b8522e6350dc32039465badfff90dcb2ba31cc +943dda8fa8237418a07e311efde8353c56dd8ec0bfa04889ccdd7faa3dee527e316fdc60d433a3b75a3e36ca2aa9d441 +a0ed4c102e3f1d6ebf52e85a2bc863c1af2f55dc48eb94e40066f96964e4d37fff86db2cff55a8d43d517e47d49b5bd7 +9045770ad4e81345bc6d9a10853ee131232bf5634ef4931b0e4ba56161585b4286876bc8a49b7b1f458d768718cb8ebf +b0dd430295ff28f81895fde7e96809630d1360009bbe555e3ac10962de217d93ead55a99fd4f84d8cadd1e8d86d7b7ef +95ced48419b870ea4d478a2c8db699b94292f03303f1bf4560b5b1e49ca9b47e7008514fe0a9cf785717f3824567e1b2 +a7986e0e389e8aef6aac4a7a95e2440a9af877ae2bc5ad4c5f29d198ec66aa0db1d58c451e76ae70275a2e44c3d3fa68 +85a8490faf32d15de12d6794c47cc48e02428af1e32205e0742f8299ea96b64bcd6d3b4655272afa595eec74ecbb047c +b790d7fb1307aacc2d303d9b6753a9773252b66c6b67763cf8841c690cbccc4866ffb5fec1c068b97601a7953fe0f7e8 +afcc4011f8c53f10d63c29b74d9779cd75c861e01974c28a4ec2cbb909b67a1b2287ead175231343c936ad75dfa416ff +918058bffdecc1ae8779dccf1d874bb9e28edbe34c8b5954a8da64a848858d2f0776437b423baf4e731f3f5fa05a2841 +ab554db549aa36dfa9f966a5ed6be8267e3aa9ced348695f3dafc96333c6dbb48ef031693aafd59d1b746ecd11a89c51 +ac4ecf746b46b26a7af49cc9cc1d381e1e49b538dbd7fb773ce6b1df63ae31c916693cca8a90fb89f1e7ec5e0e8dd467 +a8de66d48f16b016f780a25ba25bd6338fd8895a1909aabcfb6e70f04ff66f9866e6e2a339bcbfa4bfba4070a6a8db26 +b4b49374eff6dac622e49b0e9c0e334ecbec513a96297f6369696ad39e5ec0de81a1417f6544be866c9f60957a9ba09a +b8023968549ebab6c1e7a8e82954a5b213bec50bbf35b36697a8d4fd75f9e12d510b365962aace4c9978c5b04da974a7 +8d4bc016026dd19e4059d1c5784897cefa47f7ae2ed6dfa2b3c14a852fff2b64abc09549d106584e0daed861a2d6d6c2 +85e26f433d0b657a53da4c1353485e0c2efa092484c5b8adb3f63dc72ee00be79197ebef7937b37a6a006571641cd6af +abb37a917301e68328032ff4715abc0fee32e5f5be68232ca8bf7ffb8732bc47504e75b40bcc0a7c7720b71496fa80af +9837c8d2660522c0357f5222777559d40321a1377f89ca1717215195bad4a348a14764bd87fa75f08e1f6263e9d08982 +97e06f971b4c56408ed5f1de621d233e6a91c797f96ec912737be29352760a58831aaf1f64e377c3ed9f2f4dc8ad1adb +a12d211304da7b91101513d57a557b2504069b4383db8ecb88aa91e9e66e46e8139dadc1270620c0982103bc89666215 +aab74ba48991c728ba65213e8c769e6824c594a31a9b73804e53d0fda9429403ff3d9f6ea5ef60884585d46356c87390 +92f19be2b7adf031f73611282ad33e462852f778c5e072f689dd0e9458fa6ebccfae02f2b2dc021802c9225035862468 +953bb843c48d722604576cef297123755cef8daa648c30c3a678eada8718dfdb16e71cc3e042a51fedc80577235c2563 +86f509e3c1b9ee9a3b95e6da8516b47feb8c8a83403984228f4903c7ee1ee4f03addcb8fe86283af1196a54b36b9470c +903d793a377e98e2562c49de33e3fbf84bf99211925e7002a4f688470db655884e1efe92782bf970ffa55d9c418ef3b5 +a41b65681ed7f10987a7bfdf9e56b010d53683819d845d880fc21b2d525540605c5823e75c434f17b5a0d08a091c1564 +971be802de51cfc0d10a96be7977c037873f19334ed4ed4904b7675aec8bfa1f8956cd0150b07064caf18229ffd1ccd9 +b253ebe4f82cdbefbc3ef816d40c497fe426a9f0f0f170e783fa4a05ae6dabdfa8c448817a24e723a314b43e76a7c422 +86f397c95025489929ce9230b1466b5c330ec7c58a3c7e3153d6d05bcb8348a13398908e192590b8812f5c5ff09c133a +a0713983a3dc9f10b3833687cd2575de2fc63c4ad8d2f54ff85c6db23dd308daefef1bd1e51eec26732f77c1f37ba793 +8249a1d53ec92f311f4fa77e777800d777f3e9d4d452df740fc767fa7b0f36c8dce603d6e6e25f464c0399b8d0b93c30 +a73d0a206a62922f07b928501940d415e5a95716ee23bf6625b01ff2cd303f777adfa373d70279ba8a30fbb4c99a6f1f +b1106b407ecf234e73b95ff58ac9fdf6709ad2e763b58f0aacc5d41790226d441b5d41405ac03a0641f577848a4f5e8e +b009963ccc7b2d42792f09ab7cb0e929503dd1438f33b953104b4de43274ca3ce051554d10d7b37041b6f47d7a2dab6f +b744512a1b3c7ef9180b095c6a0c5bc16086a50020cf20dc2216bbff24d91ca99b95cb73070444dafc3ab45c3598960d +a0209669ffeddc074d35cc6aa2dac53acac8e870f8a8a5118e734482245b70c3175f760652e792118fdddac028642259 +8ddd3e0d313da17292fdcc1bbc6e9d81189bb1d768411c6fe99801975eddb48dbf76699dcf785cac20ab2d48e392c8fd +8392aa285b8b734aa7a6e0f5a1850b631ddf6315922e39314916e627e7078065d705ff63adbc85e281d214ec7567863e +b655a1fff4dba544a068bf944e9de35eaaa6c9a0672d193c23926776c82bebed8aa6c07c074b352882136b17abdab04b +af5095f40d1e345b3d37bebee3eb48c5d7b0547f12c030d5bfe8c0285943e0a7a53a186f33f791decba6a416cba0c5c9 +8223527f9eb3c8ff52708613cd2ee47e64c0da039cea3a0189b211dc25e9bfa3d5367a137f024abe94f98722e5c14b67 +afdb106d279273edc1ee43b4eead697f73cb0d291388f7e3fc70f0dd06513e20cc88b32056567dcc9d05364cb9ca8c58 +9319eac79ff22a2d538dcd451d69bca8aa8e639979b0d1b60d494809dbd184a60e92ad03b889037a1ac29a5547423070 +b79191ce22dbd356044e1777b6373b2d9d55d02b2cc23167642bc26d5f29fd9e2fb67dce5bd5cf81a602c3243bedd55c +988e0da1e96188ffd7c5460ecdf2321f07bc539d61c74a3292c34cb8c56dbafbca23eb4471a61e8e64e9a771a49fd967 +b0792b6cf4b10f8af89d3401c91c9833736616bb9fe1367b5f561c09d8911fb5a43b7a4fd808927b33ab06e82dd37a28 +862f68ea55206023ca470dbd08b69f0f785fcbabb575a1306ff3453c98ffcad5fd6ead42e8a1f9edf14c6fd165ffd63a +815ff0898b1330ac70610180c0f909561877888ff10def749a1e65edf9f4f7cea710a757c85241dfb13d0031efb5e54b +aa6e6ce21776ea4507d452ccdaf43a161a63687aae1cb009d340c9200e5646e9c2de4104dfd66b8e55dfa6de6ee83e4a +8e8f3d3403e0256ecc254b9b1464edca199cad3f3348002d744721c345a1a3c7f257c3587d2229774cd395e26693d1ba +90483e28985e4a0f7a3cb4bc5e865b9d408b94cd2146c04aed00b48a7ab80a28deb05efec320817d63578d4f953bd137 +84fb2a762ba29193b07f1dd84b3f69153cedb679b66ad04f8a4adf01c14f115163a107e6db23aaf0f0c9687824ded197 +b4a23922bf4302cc9a6583f252a1afa026c87c132b9ae44cc1f75a972cb6ae473447c500827906f9b677617ddd6fb473 +809bb9edbbe3a2769165f029f2a48b6e10e833eb55d8f9107c4a09ca71f0986dc28f3bf4ead9cab498086eb54c626bbf +a0459dbb08db4155d16301933ec03df77c4f835db2aa3f9697eeb2bb6fcd03337fab45fa43372a469fecc9a8be2e3119 +a638eaace7f21854de49f4db6e4ea83d2983751645e0fb200c5e56561f599fd37dac70bdbd36566fdd10d4114fbb9c2f +a3a27bc2728390643a524521bf8ef3b6437cfba6febfd8bb54f2b6ecbafafb96196d3dea279ce782efd97b212f364ef5 +b86693b3ea23ea6b2c4d52554f61ef39c0ef57e514ff6da80c6e54395df8376e2e96b9d50e4ec301c59e022c5c5610db +af4d7cd678d79e67ae19789d43331dff99346cd18efff7bab68f6170c111598d32837372e3afe3e881fd1e984648483e +b8735a555ba7fe294e7adc471145276b6525de31cda8c75aae39182915129025fb572ed10c51392e93c114f3a71bd0be +b1dfb6dbda4e0faaa90fe0154f4ddaf68ee7da19b03daad1356a8550fca78a7354a58e00adeecb364e2fd475f8242c24 +9044b73c1bd19cd8bb46d778214d047f5dd89b99b42466431b661279220af5c50c0cffecebd2b64c3d0847a9c7a8b1ec +891f0d162651a0aa0d68fb1cc39fa8d77fd9f41ff98b5d6c056c969c4bac05ba8c52cbfa7fbb6ef9adfe44543a6ec416 +8920ae1d5ac05bf4be6aba843e9fc1bc5b109817381cdd9aa13df53cabea319a34ee122dcb32086d880b20900ff28239 +abb14023142876cbc9301336dced18c7878daa830070b5515ff4ac87b7bf358aa7ff129ebbf6fb78e827570a4142661f +a74b15e178cf91cde56eab0332e62d5ff84c05fcc849b86f45f94d7978bf9c0fc72a04f24d092a9d795ca3d976467f46 +806829621a908ca9b6433f04557a305814a95d91c13152dca221e4c56bfaa3473d8bb1bacd66e5095a53070f85954278 +b09a3c185e93869aa266a0593456a5d70587712bca81983dbc9eebbb0bd4b9108a38ae1643020ecf60c39c55bb3ac062 +b2bbe8f5361a3ecdb19598dd02e85a4c4c87e009f66fee980b4819a75d61f0a5c5e0bdc882830606cb89554ef1f90ead +825e16cb54fc2e378187aedae84a037e32903467ac022deb302cf4142da3eda3ead5b9f3e188d44f004824a3b5d94fbe +8b39d4a11d9b8ba885d36bcdb6446b41da12cfd66cb22705be05ab86936464716954360cc403f8a0fd3db6d8b301cb59 +ac19d453106c9121b856c4b327ddb3e3112b3af04793df13f02d760842b93d1b1fbdff5734edc38e53103a6e429a1d1f +b1cacbb965ec563f9e07d669ffc5e84d4149f1fb9fcfbc505788c073578c8f67956fb8f603e0b9a9d65e2d41803038ce +b7612d9e7dc930bff29191d1503feb2d6451b368b69fa8ecb06353c959967daccdc262a963f01c7fb95496f1bd50d92e +93f8fceb65ea9ef2052fa8113fb6720c94f0fed3432d89014ee5ad16260aeb428aadea0d1f1e002d2f670612ba565da3 +b3eb9213752156ed1fced3bca151fd0c630554215c808b9a0938b55fed42b6b89f9b76bc698f3e37c3c348d2395dbed1 +b46ab3553ef172ae40fc21c51d1d7eab8599a67f2f89a32a971aa52c2f031664e268b976dd2f7dc2195458fcf4bf3860 +8fb66f2c67ca5b6fb371c7d04592385a15df0c343857ba8037fe2aa9f2a5d4abc1058323ff9652653261b1c7db0edc24 +a7dfdbbf0b14e4af70fdb017875cdc36ad2108f90deb30bfca49301c92cbf821645a00ade1d1ee59a1a55a346675c904 +856199cad25ec80ee0327869077f272e33d59bf2af66c972e4a5839ec3b2a689e16f7fd0a03a3138bec458fcff8edbea +a2842ac5a715c2f48394988c6f84a6644c567673806feaa575838e906138c1b25d699e1b6ffdfc9be850b15da34077e4 +814b448ada88f769de33054c3c19f988226317797acacdbe55ed2485b52cd259ac5bcbee13f9de057eee33930a7fa0c0 +b49de8dd90da916ed374ca42665464b6abe89ff4453168921f5a7e5ddd3dcfa69422782e389e586e531fd78a1f236a8b +851f9d942b4c8ffc020c02c7fbee0f65ef42b1ab210ab4668a3db6aa0f8ab9eedb16f6fd739a542cc7e3cc03172b565b +a5128c155b8062d7fa0117412f43a6fdc2de98fa5628e1f5fc1175de0fa49fc52d015ec0aff228f060628268359e299c +b0765849127cc4ce1a1668011556367d22ce46027aa3056f741c7869287abcaccf0da726a5781a03964a9ded1febf67d +984562c64f3338ffe82f840c6a98a3dc958113f7ed28ee085af6890bbc0cd025723543a126df86f379e9c4771bb69c17 +8087fe60a9a22a4333f6fbe7d070b372c428d8c5df3804bb874b6035e5602c0693757fb30a9cd5a86684b5bca6737106 +a15e195b5850f7d45674cdc3bd74f972768b46fe9473182498263edc401745a8716fc532df8fc8c1375e39e391019226 +858ec10208c14a67c4156ea9c147f36d36c4fa0a232195b647e976ba82c8e16262b2b68d31e3b4702070c3dc701bccb5 +84bf3fb83c003380ee1158e2d6b1dca75cd14c7b2a32aec89d901f0d79e1475aa0827cb07cba1784a6bb0d37f6ca5cd4 +91e69f5392648e7f7c698059a0fc4b8478ab8af166d3842fb382ec5c396daa082ee3b2cb0192da3c9d90f6523c4c039d +8f7299f451c5e641d6fd961946b7a6ba4755685b2a40164e6276c25aefc66715b92492097a191813d39bb4405dc5da36 +ade2cf04ff6c94c1019bfa1e0e8f580696230fa6ee9695c4772e5a44501b2fffdd765ec7cc71ba14b83559ad62cc0fc5 +85fc98ecf469d6f98c8b3e441680816f764de39001a249bc7162f990c5a5354683e849164d4fc9287ee516780cdcd436 +928d118188120d038c37abdbe66c05adaa87f1cf9957dee2783b09fa91c4c43a7b0d0b2b6c5f4dea57e3ec8af230e84f +8025f71cf8d3085d6ea5104dddea8fa66cdb8527e40db01472469be021632daf22721f4acf1a8698a53439fe2f82596c +83266fffb12b3c795a6b551ac2aa7d9a29c183f861e78768c11286a04e22bd423bba05a68775bd77273e3ca316a4318e +95fd0c69c2d9df4e795c7ba71ed71a9d9f2878cd7e3a64be7b671d9611649fd41d29f8bdab642ba19cbd3db660d6a7e7 +92a912cb4d5ef4b639876daf4289500c4ebdbd80aff07fd93dc3eea645f084f910e5c02c10492a37f16acaa7e646d073 +b3d2622c987189a0873932aaea8b92ebb6e9e67ff46e91a96bf733c3b84175fffe950f8f4622cc4fa50f116321c5537f +a98f9a40054b31023a8f7549a44cae853b379bbfe673c815b8726e43ecd11a96db40b20369d712cbf72ffab064ecfac5 +b4e9a38e371fc21f4b8a3d7ad173c9ffad0554530dc053365d9555ddb60f5c9063c72ff4c65d78b091af631a9e1ee430 +875a31aee4ba19e09f8c2754fab0b5530ec283c7861a4858b239a12432f09ef155a35fedb0bc33eac2117c7e62f1c7ee +95edd0d1a6e94af718590756b5c5f5492f1c3441ecc7fa22f4e37f4ec256b9fffd2fda4c11fc1a7c220daee096eb1ff8 +b35fdc435adc73e15c5aaf4e2eea795f9e590d3e3ee4066cafa9c489ee5917466c2a4c897a186b2d27b848c8a65fa8a8 +94a5ce56f8d72ec4d0f480cb8f03e52b22f7d43f949a4b50d4a688a928ffd2c9074ecbab37733c0c30759204a54f9a6a +987562d78ef42228c56074193f80de1b5a9ed625dd7c4c7df3bf5096e7d7b08e2ee864bd12d2ea563e24fa20ad4d30ef +95a8218405038c991ace2f45980dbb1efa9e4ad0d8153486b0213a89e4d7e3cac6d607100660784627c74f90a8e55482 +b6a29d566f5a924355b7f7912f55140e1b5f99f983c614b8a92814ce261f2750e8db178866651ea3b461fb8f92890b14 +afdacc0a13da0446a92455f57a42b3ba27ba707f24171727aa974d05143fae219de9e2eb7c857235dd9c7568f43be5a8 +862a7dc25f7cfa4a09aeca0ed2c9c5ee66189e119e226720b19344e231981504e37bca179aa7cad238ee3ab1386aa722 +a336364e76635f188e544613a47a85978073f1686e4ee7a8987f54da91c4193540ac448b91d07d1fc5c7a8538b1f1688 +8f1ddca9638decd8247c1ce49c1e6cf494d03d91c4f33e48a84452d12b6736e8bd18c157068dfeff3a90977af19e5b1e +96ae91b9aaf00e437c18ddfc1aef2113ee278153ba090aedeb3f48f1e66feb8897bb1ac7f5ffeffc3be29376dd51e498 +8230b5bd9067efb6089e50213f1cc84da892e6faf0b79d5e4768c29303a80b1b754cb09d17a21933aba4c5f32070878a +a79dfe217faec7b4d3cf97d8363949efbc6f3d2c6bbc25df2c7bb8b7fd2521e6d3fa76672bfc06de6f426290d0b3cc45 +8290bd36552609d6b3ac9ccb57ff8668fc8290548eecdcee9a231f1125298c20bd8e60f033214dfbd42cd3c8642c699b +8945db9e8ec437c5145add028d25936ee8823ceb300a959402d262232ae0cbd9a64c1f0a1be6aed15ff152202ea9a70c +949e232b48adeaf57bd38eacb035267d3e78333c6b4524cab86651a428a730baf9c27ff42cb172526d925de863132e82 +98917e7a5073a9c93a526399bb74af71c76958a74619caccf47949f8fd25962810a19e399b4efcba0c550c371bea3676 +b5b144e0707aefc853ea5570bd78dedc4e690cf29edc9413080f28335ac78022139bfe7f7d6986eb1f76872bb91e82ad +949945072a08de6fd5838e9d2c3dc3200d048b5d21183020240fa13e71a1a8d30e6bfee4e6895e91d87b92f1444d0589 +b351a03c7c98506ee92d7fb9476065839baa8ed8ac1dc250f5a095c0d4c8abcfab62690d29d001f0862672da29721f16 +a82d81c136bc5e418d1fba614cb40a11f39dc526e66a8b1d7609f42fea4c02b63196315014400084f31f62c24b177cbd +87d51c907fdcdf528d01291b28adfee1e5b6221c6da68fd92ab66126247cd8086a6bcffff0ea17e7b57b0ba8d01bb95d +a2a9a1a91dfd918f36c1bfeeca705ea8e926ee012f8c18d633e50ec6e50f68f3380ef2ee839e5a43cf80fbb75bfb5304 +86f22616caed13c9e9cd5568175b6b0a6a463f9a15c301b8766feca593efa6e5ee4c7066e1cd61b407c0be12b3d8236a +b57e0a2c42790d2fd0207ef6476a433fca0cf213d70840c4af1ad45833f23fca082d21a484f78af447a19a0b068ea55c +8ae9bda5d85e6e3600dde26379b7270abd088678098506b72196ac8f9ce5b0173bc9c7ff245c95cbab5b5b967bcb043b +95c7d11f6c874f59ba632b63ce07a7a9d917a74d0b89cefa043f52aa1a7fe2e81c38dea0b20378264b5b4f64039932bc +ac7dee7479f50722526ea1c9d4e2f1a4578d1b5cce2092a07722069c96bb4da295de1c4f16e21005276e3b3f1624ac5a +89b8aaa49bd18b09f78fc5a1f3dd85d69b5dfcff28fc6d5a92b1520bc54107b8b71bb71fd6e0bde10e0a5809c633e5d2 +8982cb43fe4d3488c55e8c08b935e6c8d31bb57e4f2aeb76d6319470cce99ebf7dc2f116ac15b9d845ab1bc16aa6a583 +a12c63f48e27b1a1c83a32992642f37fb5b89851a35e80f6d1f9bc483cb25acd0e12b1dcf68781ae0cc861f002368bcb +aa6da92a4b4fa229afc8007abca257ce0ff5fad3b1ccfe5d836b9b52ff6b72575a0b915a759403b993733b16a47fdb15 +8bf706a92fe54f15d633b9463926b874dd43e28aaeca3fe2353fb58ad7753c8a293c56b0e94176070e8a9ec7401073a1 +b81e86de4bb5c1046e40cca79585c5b98c8673626fd3a28e563c5a3296256c2f7086522ae95cbabfaa8f1a8f7eae6272 +ad10f895b05d35cb251f78cc042d3f0969a8b6b3f289ddb4b016e0b8e06bfffc3a3e1afa9b0cc548f8c092832bb766bc +ad993aceb68d5217cfb07f862956cde83d05dec5060fc7a8fbfd37c6bfd5429ba69bdaf478b6cd01c323a06793dcd9fa +83da9c9a8fcb2775df0777aceabe90642a2df1c6abc646566e954f42d6e43455b00b101ec5ef58850c8d4b3100222ca1 +b55484f339fe7c7d107e70432601f4a34e1cc02ae4de5d18b99e5aa995f7b3710fc745769b85c1af803d457491dd8ce3 +8009d80593e82f3e751cec9e7e495fd29ad6f45f8d3ae513bec998b43c49fed74c44229c6f27c421e80c65413b897644 +9868081bbcc71192f7ff8dcf99a91dcd40f96556fbd6f285bdbfdfc785f604d8bf75c368c59db5ac8cdcc663087db53a +a04b1e91af025b4387ee0a2d790a1afb842e46f4c3717e355578efd1f84fea78782c6f7944b4961268de7f1ac71fb92b +a7b6301ddb9738b89b28a36d29d5323264a78d93d369f57ddab4cea399c36018a1fcc2cc1bfadf956a775124ae2925bd +a6cdb469014b33c590a07a728ce48f15f17c027eb92055e1858a1f9805c8deb58491a471aaa765de86a6bda62a18aef4 +828a23280ec67384a8846376378896037bd0cb5a6927ff9422fca266ee10a6fde5b95d963a4acfa92efbb0309cdb17b4 +b498ec16bcdb50091647ae02d199d70c783d7c91348a1354661b1c42bc1266e5a5309b542ef5fdf5281d426819a671cb +806533fb603e78b63598ff390375eebe5b68380640f5e020e89a5430037db2e519ab8ae5d0d0ad3fa041921c098448e1 +9104ad119681c54cdee19f0db92ebfe1da2fa6bef4177f5a383df84512d1b0af5cbe7baf6a93ad4b89138cd51c7c5838 +ac695cde30d021d9f4f295109890c4013f7e213d2150c9d5c85a36d4abfdca4cdc88faee9891e927a82fc204b988dcd9 +a311c244df546d5dc76eccb91fe4c47055fc9d222d310b974d4c067923a29e7a7f6d5a88bfef72fd6d317471f80d5c82 +89e4518335240479ad041a0915fc4f1afaab660bd4033c5d09c6707f0cc963eb2e6872cabc4a02169893943be7f847d4 +a8ad395b784c83aacf133de50d6b23bd63b4f245bb9e180c11f568faca4c897f8dbda73335ef0f80a8cb548a0c3c48fc 93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8 99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d 88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659 @@ -4160,4 +4160,4 @@ b89584da22237e3061d991b1a55a5e55dc637b8b671130d304587729348138ef87885180310efe9f a0a9e5503d9afe0027891dab890c687fd5f5fac5741418490c64d7c15f59533dd603a50163c79402afa61bd02de486761983c94501da17e6bbe78c497f2122210071602f578adc0ebe7a4679f87fe77e09c8c122de69105f13455fea25f08e6f 9811487283ad620cd7c9b303ae2f348d0e6f5ee17b504baaa817ae207adb912a00d3cc36dbf48745eb899e6b6e22f09f0f9ba29d949ecd7350fbbfe87a8c7cdd5d0e687fc807751d07634aaf7c38baf3b24a0670c38fa6ccd7431436fc95525f 8a13aa5071c526e560def7d8583393942f07d88c9d8d26c98738fd65f57af2e3326dbb1edff0f39fe98eda4a13ed4fd71844254b954690154c4804e1c4a53df9dc4643f4b7b09d0860070f6b2318d0d63d28fb56bf5b6ff456a18dfc72fdfbbe -b9c90ff6bff5dd97d90aee27ea1c61c1afe64b054c258b097709561fe00710e9e616773fc4bdedcbf91fbd1a6cf139bf14d20db07297418694c12c6c9b801638eeb537cb3741584a686d69532e3b6c12d8a376837f712032421987f1e770c258 \ No newline at end of file +b9c90ff6bff5dd97d90aee27ea1c61c1afe64b054c258b097709561fe00710e9e616773fc4bdedcbf91fbd1a6cf139bf14d20db07297418694c12c6c9b801638eeb537cb3741584a686d69532e3b6c12d8a376837f712032421987f1e770c258 diff --git a/build.gradle b/build.gradle index eeedeafb772..5a24037154f 100644 --- a/build.gradle +++ b/build.gradle @@ -559,7 +559,7 @@ task evmToolStartScripts(type: CreateStartScripts) { mainClass = 'org.hyperledger.besu.evmtool.EvmTool' classpath = startScripts.classpath outputDir = startScripts.outputDir - applicationName = 'evm' + applicationName = 'evmtool' defaultJvmOpts = [ "-Dsecp256k1.randomize=false" ] @@ -586,10 +586,10 @@ task autocomplete(type: JavaExec) { } } -installDist { dependsOn checkLicenses } +installDist { dependsOn checkLicenses, evmToolStartScripts } distTar { - dependsOn checkLicenses, autocomplete + dependsOn checkLicenses, autocomplete, evmToolStartScripts doFirst { delete fileTree(dir: 'build/distributions', include: '*.tar.gz') } @@ -598,7 +598,7 @@ distTar { } distZip { - dependsOn checkLicenses, autocomplete + dependsOn checkLicenses, autocomplete, evmToolStartScripts doFirst { delete fileTree(dir: 'build/distributions', include: '*.zip') } @@ -1021,6 +1021,7 @@ tasks.register("verifyDistributions") { dependencies { implementation project(':besu') + implementation project(':ethereum:evmtool') errorprone 'com.google.errorprone:error_prone_core' } diff --git a/config/build.gradle b/config/build.gradle index 842bf9e1322..acfbc83f43f 100644 --- a/config/build.gradle +++ b/config/build.gradle @@ -36,8 +36,8 @@ dependencies { implementation 'com.fasterxml.jackson.core:jackson-databind' implementation 'com.google.guava:guava' implementation 'info.picocli:picocli' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-units' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-units' testImplementation project(':testutil') diff --git a/config/src/main/java/org/hyperledger/besu/config/BftConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/BftConfigOptions.java index 4dd5b3d0f91..c94752b598d 100644 --- a/config/src/main/java/org/hyperledger/besu/config/BftConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/BftConfigOptions.java @@ -24,7 +24,7 @@ public interface BftConfigOptions { /** - * Gets epoch length. + * The number of blocks in an epoch. * * @return the epoch length */ diff --git a/config/src/main/java/org/hyperledger/besu/config/CliqueConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/CliqueConfigOptions.java index b4d3b6e6d77..66acf03e558 100644 --- a/config/src/main/java/org/hyperledger/besu/config/CliqueConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/CliqueConfigOptions.java @@ -41,7 +41,7 @@ public class CliqueConfigOptions { } /** - * Gets epoch length. + * The number of blocks in an epoch. * * @return the epoch length */ diff --git a/config/src/main/java/org/hyperledger/besu/config/GenesisConfigFile.java b/config/src/main/java/org/hyperledger/besu/config/GenesisConfigFile.java index 73d7174303e..ad4be0c9f21 100644 --- a/config/src/main/java/org/hyperledger/besu/config/GenesisConfigFile.java +++ b/config/src/main/java/org/hyperledger/besu/config/GenesisConfigFile.java @@ -247,6 +247,24 @@ public String getNonce() { return JsonUtil.getValueAsString(configRoot, "nonce", "0x0"); } + /** + * Gets excess blob gas. + * + * @return the excess blob gas + */ + public String getExcessBlobGas() { + return JsonUtil.getValueAsString(configRoot, "excessblobgas", "0x0"); + } + + /** + * Gets blob gas used. + * + * @return the blob gas used + */ + public String getBlobGasUsed() { + return JsonUtil.getValueAsString(configRoot, "blobgasused", "0x0"); + } + /** * Gets coinbase. * diff --git a/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java index caf339f42cd..f583d7384c1 100644 --- a/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java @@ -65,6 +65,13 @@ public interface GenesisConfigOptions { */ boolean isClique(); + /** + * Is a Proof of Authority network. + * + * @return the boolean + */ + boolean isPoa(); + /** * Is consensus migration boolean. * @@ -461,21 +468,6 @@ default boolean isConsensusMigration() { */ TransitionsConfigOptions getTransitions(); - /** - * Set Besu in Quorum-compatibility mode - * - * @return true, if Besu is running on Quorum-compatibility mode, false, otherwise. - */ - boolean isQuorum(); - - /** - * Block number to activate Quorum Permissioning. This option is used on Quorum-compatibility - * mode. - * - * @return block number to activate Quorum Permissioning - */ - OptionalLong getQip714BlockNumber(); - /** * The PoW algorithm associated with the genesis file. * diff --git a/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java index 6a8a3568a4a..7ecb31c9d19 100644 --- a/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java @@ -146,6 +146,11 @@ public boolean isQbft() { return configRoot.has(QBFT_CONFIG_KEY); } + @Override + public boolean isPoa() { + return isQbft() || isClique() || isIbft2() || isIbftLegacy(); + } + @Override public BftConfigOptions getBftConfigOptions() { final String fieldKey = isIbft2() ? IBFT2_CONFIG_KEY : QBFT_CONFIG_KEY; @@ -400,16 +405,6 @@ public OptionalLong getEcip1017EraRounds() { return getOptionalLong("ecip1017erarounds"); } - @Override - public boolean isQuorum() { - return getOptionalBoolean("isquorum").orElse(false); - } - - @Override - public OptionalLong getQip714BlockNumber() { - return getOptionalLong("qip714block"); - } - @Override public PowAlgorithm getPowAlgorithm() { return isEthHash() ? PowAlgorithm.ETHASH : PowAlgorithm.UNSUPPORTED; @@ -490,11 +485,6 @@ public Map asMap() { builder.put("qbft", getQbftConfigOptions().asMap()); } - if (isQuorum()) { - builder.put("isQuorum", true); - getQip714BlockNumber().ifPresent(blockNumber -> builder.put("qip714block", blockNumber)); - } - if (isZeroBaseFee()) { builder.put("zeroBaseFee", true); } diff --git a/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java index 3b7135d56de..09219156209 100644 --- a/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java @@ -117,6 +117,11 @@ public boolean isQbft() { return false; } + @Override + public boolean isPoa() { + return false; + } + @Override public CheckpointConfigOptions getCheckpointOptions() { return CheckpointConfigOptions.DEFAULT; @@ -396,16 +401,6 @@ public TransitionsConfigOptions getTransitions() { return transitions; } - @Override - public boolean isQuorum() { - return false; - } - - @Override - public OptionalLong getQip714BlockNumber() { - return OptionalLong.empty(); - } - @Override public PowAlgorithm getPowAlgorithm() { return isEthHash() ? PowAlgorithm.ETHASH : PowAlgorithm.UNSUPPORTED; diff --git a/config/src/main/resources/kzg-trusted-setups/mainnet.txt b/config/src/main/resources/kzg-trusted-setups/mainnet.txt index 92f11f0286f..26612cb8876 100644 --- a/config/src/main/resources/kzg-trusted-setups/mainnet.txt +++ b/config/src/main/resources/kzg-trusted-setups/mainnet.txt @@ -1,4163 +1,4163 @@ 4096 65 -97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb -92a72fc2d2d7888d95bd8b479fd66555908ef365b31d181c6aae60b1cbbcc21110f057dd13f9b694b2b260cda1bcb516 -934c3d60d8a31e9cd617427b842dbd49d7dcc5c8949d932773f0a0d752786f229d7017c592b3303dc5f631d2c01d5c08 -a895d8f7f4f160ab3837d80b5f6aa743b28d22ed22116269f3857130709df107867ba7e0db0d5e171492fab0db2a635f -82d3d5a542a525646953cf68517013508bf9aec3cd7faf0a311fb0970f07697c8efc6943fb7fb8e9ff208a30ce4e8027 -95e3d50c2686c92568f46c8aa3a0e7cb3d456cc532c4ea0d07d47dbbed678fca2976b0b28009a360a2fa3dcd2716a7dd -b7b60fc315983545150f0b6545509ffe3f38b5562574e640dd9c61d1a5db441855df9b0cab10096fbca09024fe076602 -86836a32ca078c51b9e9012fd37cf6647bc4bc2b8331b8c51f0958aed321de1fe44c2ff374d34eba13fcac18f3061a63 -b50bd23db7116d7cdf19bb3bbf38d946f345c2b80e31bd3ac566efcb302561d3727df398ba913d7f3436b82003337c0c -83298b2de8fc1e36765903cb94d1b3e45ea5a09f5e0468dd4978ccd9577f81e2985f98f7294a3233d822f54d8d3f35e7 -89c74ab72d45bce23aa7b71d063f0e24e03353909570ce9459e8da7f872880c0267774699a10e88ca8d169b7f906da30 -a6bafa458bad96b879b771a1173aadf9a6ab07b62525642554a9e8c62587af476925e0bbc853d745fde3c77433cc05fb -8ef8070be49300c4a428b0cf1383608d4bbd0d7831e47cc210ae00f16193c4768b01c630dad6029f760fb8e22d1863ef -972bc1b58ee7f483c768fbb64af19c87cc69c5f14f9268dd4cc6ff99c8f1a49e872030d840f46b8c18d39395693d1ef2 -a1243cd5fa37c1ac9c8a5ce77357f99a190204ba8a87acda038efd7a5e298afe7c645f88d38d2d52f56c85afebbac06e -8f7e3506cb4608555759e84094654a7b725057b737efd9553c4a00531d54bfde9fa0dbed7bed84b20d34b88b3eb59112 -994b2a83f893d793c942781188ad76518beacce4a77cae5d9ed7f7dd47d12721f8c799ba8180e16acb3da06aa3788dbf -b63d24f3dd00314b4d58ea119d1ea3e10303827e23f90dec00aa3723e8380bf8d16450cffb16631c887741834e3e9f3f -8ab4e03e2d86abbe5dd0401744ca4bbc915b787a8a11b2ba0ad580b53f04d47809948c47345439c3cdc5ea47bcf705cb -a505e73b25aee781f49df4b0d8f8e2456d6da95cf30eb58ec1e8bfcfebc80221ea2f988b7a7087bb6ceef6c96fbb294e -9185b078e755a7ec66f503484bd8e75680670f99be8bfc0dd5f05ef50bd1f3da15c23671bd7146ba2919e6fa62b3f423 -a4b4eabf6621d9db591ab635bb50f60c54cac033eea827f2d3b0e5e6b60479127edcd07ee797e6eaf6135353b28ce5b1 -979230aa42f260e1993189932d93bc47d3d775283689492cee54c115ff7109f5362466040508de3dba2c9bfa1d08b216 -84793398dd6643bb8cfd62c14eb52aa6e1fd7735fedeb4ea49fb42fbdcf804f0b9d26e89a6ce4b0e4e70e8578b779be1 -b5af00da65a02da4791954598b465cd68d14a3e31b788b0e4d6cf63231c52d57f06781ab24390685c8f3e2690394ff97 -82a8cf6a5b252ba991b216b83138c7a2a473234fdbcfc8b9d630969e3beae91c3021e61184019ace7f0ca7171e33b589 -b58678c9a81684d9c88a8c639a98aba71e994543737e4fe6fc882641194f1190105358aa2294d61a7a610e03d4c9e72b -97ebca7442c1328d8cd839aed48de80e10e41eaa482ea00351302cce0a29f8a8e70b75495ed43e041eb5c6829afec3a8 -91f3ef06c5be53d9fb26792c60390216493129a332a845fe58227627f67971fcb8b4bb6b8de3cd31fbe5fd63fe144721 -b2b42d9c7069f4cbb6b084c9088aa0025c4d7badeda1ca753e4a132641740bcb4728c7a4b61a1ea6fb6af67062b74bf3 -965fb54d9133351fcacf688195092c8c3507de2087f17e122c4ff778a1e6097ef754316f1591188ca1185b83a02877db -8e9285aa4b559558f147c74e8aa491faffa7d09ef9d63ca928a0e1a1a0d1613c5e9fd4961a775333e89acf6a1d9d60e2 -969a42314a9c871f409a04d9260c160644df40ec3eae18c839dafb6b58afce77c869d6f88cbc0ff10513219ef16475e2 -a42b1d86ba0d0e09301fd6939540e01d5cd45a9c10a9220e4779dd93cf9a0b3618fccb81f6a27f56e437fcf3df493ea0 -96da42f72efc3cf2539cdfacb1feeedc0ddf2e739d00a07df341b0112a11ca76235f9bb9e317225fbe3c062da7eed1bd -ae40e5146b9a3b1cd0b459043b3b438794b74acff9862fd00ae34324b1c7b6958763dc22f20dcdb0b5f6886aa5244a2e -a3a9c0cc707cfd6586e8aa10fb4d3165686d8e63ce4ac8ca1e64879913870e7514fee5665d10b84e9b9aae01a96726cb -8111811dc2ec713a14cfebff119b14dde24af1b2c2b0fddcb49542fa4a8e6b7cb0bcc31c81ed91d6c1da7738566881e0 -953ca02b2c059bb62138ba7f7134503a26e429f539a2854209c68d5507bc6574d71ba82cb34008175c88793feb981ea1 -a4c45e01365a5d601adf202d27c0a1ef61bfe6d6623847976f128c8f2a5d27a0931a5ba24980c186a6df24096733aff7 -85115bdeb44d8fc4b85607565169be934d4e7a5ed13e67f47ab4fab11dc99f1e5710601b76271a25af6c045b3cfcbe02 -871a84023c11a5f2f3bd6e7a40b41601e8aabbd8fd07b9a08a7dcd84d31875bc35e8e7c26505b5f829c1bef47fae2396 -977b3104c766bea6ef33075a7ce162c717fca7125eab518b83f9ab0d400d1fb9bd59a588a458ea9f7743c07409499a7f -b80c65a8bf253c75e1d13e57252e941a3ba241d1ed8b560c0a8ebd89cf00192befdd0c3c23cae5eb1f26cfa6d17ff358 -aeed5438dffbc3af5dc6be921bc7a32af72a796e34719f4b376d797a127e5ccc500ca0e7e8eefc6568d6187f09bbfd08 -b67c9a8d0c1d38e40d7f5f84a80ca3d87532751de8527a2e99ce88c4b46b504f8b01b25f16e2816099497fcb13d3aeca -8a285c6492874e340018a8d526eaac3be7e7e901be26206012ee88ce6b5d14ad3e6dd1949ffb10ce80da0b9ee18b71c2 -a29db630a03d4d2aa3d9d6f7484b027ad6c8426636c5b90bd15f333c33d7efcd306f794085154d5419aafc194c21ca74 -a8dd50311e524b87ca522b8cf2b008245736fc6f1f12ccb68bcf42e7e00b87658d858cdf005153574c424b945372213c -b1da29d2978a5edb2c7db84e6848a63c311601f4a3c0597cffdb51aa59f8d0dad04965159bf5cc05e5d19ee0f1f51b4d -b7f7ea74eb18c6434bd2d4a23ac5ae276299e6c6ecae09cc65c0baffadd79be32f34c1745b9fc89fb41e9a0b2f7f6c43 -81194eb94fe80325534f48058ecc85beb3d8ca45e4a17c03d513fcb3ef73e2ba9edeca47037bbe4b8a16bbe0be0b1ab2 -a8d7dd39a1122c6b7219af94fa818aec1a320b46c7d46595a97c786181302b362cf9a69ec019851b908ca637e4a9eb7d -a0aa50fe56a96db810d7f757df69e77e9a60e805840f484635c96438711cf0092f344cc5c7615b32da036b639182a546 -ac0b94c25058d3eb5c1d1dfee8cda07d6f124840464f6571ecf6fba2604d95c16b6abc54f67d41265d534d67b39b3648 -a9c64c88c1413d1e7275fe769c77f0b5ef4ee80341a945839e029c3f96e8aab8b027008e0cb51d9cc5be28c2d1c6ff29 -a05dcbb9ead38d761a7f5e30e561e71d94d386333656b696e4b46c828db0c50c5c048621666fba4df562d3f915dcad1d -894c40bb12acb7d45f3d38bc3f200b7dcaba14e804f0d3671e84b64dd650ba6a7928066f168c87334eb3c220d98b823a -877179a5eb49cdffcf99afa0d39bae5b0d1b248580817f03c0440cd9ffb0a4c6388af364d2ec4d552996f85eadf8c80e -a8760e2ac3a45072aea6000507cdd59fa51a9c60c29666d400db9219d72a2ea3123b7585f2e743fc2ed6777d63576d60 -8752882dab9f576f497504721e5f28e7153cf913d5acd4a22b831b43717bff078ea1b0dc3b2c0b53a169f6406dd2a77c -b2e8c488b91d70df1423ad48b17af13d2ec4158ecb88f54ab7307d9b31dbb0f3152bce30c0b0879bf503e8fcafe41f2f -81ac4644e831620ebea149a4e4fbc1e89c4868fa5e616467415c5557872f872336045e1fc230269469e19b36e4855c17 -a6a234e1f9299913a05146e2d4e09b00bf2ef91246c4a8232f65bac5b202991eefe1aa227af6b5f5bbd0a666363b88d4 -b0869efd9ce419e4c9cdcdbd81f62764a4e84f83628b06a74ff554b7f812695f52d9b2253f1e476919f515ceaa046be0 -91f374e120a16e21bc3b18d390d798a13194f7e7fc63a13853a7986fdeb1c67d6300f925d4251dfb81fce7ed3a5fdf36 -aec7525b13f52580e10d5dbbf08903f14f369a713e2f59e77ed21ce659965351c50dafdd0f3928b8ba4d21a0dd8e5b49 -b47e08d8c07f6cb4f1f0ee4c6e118d3d4d873b7140e0416654f0861a4dc011346af708db29280d15d2ee994a95557bd7 -8360037c6cf909812189421e61bf320a254485756434ce48e7c6bf681c9e0d52dcdb6027d3565892a4ffca5d8dd6c4bb -b4a3b391f471228de19e589f478bbc6f6f6889a457679980d58575f8899120c94cce7db00253060979741924dbfd042f -8852803515447255d950af8e74768c0786eea5b6404517ce600ba35a759728c3d257eca22507b1c2b4e42d220dee5617 -977292fe648a6166a85e57f1bc91b7ccc7d28cd3642715572db31c4efd1850b937fb7854d0d66aa925b930a072d2fe7f -b56905a1da8011043bd759a61d0052b738bba0b6985c0b6e73e4055b72a6d704bcf2a496d410f999483c6c46d1aaac4b -adc7ca377682ae3eb10338bac5fef01f5f99b31d2af06c7e03f0c10d3de464ba2f7a470803d73650a2a070d733344645 -a99c017f93ddc02e829b59ea6835b80604784f5c8caf32d28532abc67c7f8a13abf7eff8fca5a41fb176037c3b1e169a -836eb0850e6b06f2ce31d0d6a5f48f7ec7ad926c3b69af797b1931001d5478b39d806fafc3e2c0a36e560fae0fcf6612 -8323c7d361d89635f2e61474fd9bdb43c79e140e0d196a80088740372382a6b7812930baf481a47e2336ada828ad3ae6 -8b2e185d19a44f666015898544fa48744d1352decebbf987605378cda0a31a21f45ac86897510e348572b62d44363858 -9865078f2d46334b99fdfe228f9c54236af4feb2ddc27597814e3e6ee217f668ada24ee3cf4de87866e67f23def4ee4d -969e3ff317524ac96ba5de1b50d6c5933ab6cffbf7e9ceeb62ab58fc6a032a07dfd34b3f174b0aa8ad9a96513a9315a3 -a58c7cdc0912f6a78ca9660b3e44c8b19f36931fc4228ff04e5402ba468a64323126917cdb9eb65d9564e3eb101d0b87 -b97200d4fdda197a209a85243f530d92a0a8bd1da7f338a3c9f8f58f2b0a20330aa7e5671f48356b41076cf3207b508b -ad3c167108b7254b25c5c28349ada82a134d333eeab895b226ecf1b66da637ea6143d5e97be4023efe02b7eeadf2db42 -ad96a77f490429faf562082e46372eeb9fb4688e4b1e2ae7086d338b51e03ca5ad3985800e9e123c99ad9912b76cd3d7 -90ba6dd740c76f7a98846e9ed4bddc3f85a34539d962a78f10e84bd322145a84e6cd3fb92afdd3dd4adb16b25b342786 -a7085652d463810b040163d775a90a911c2945b0b142b457c22e6be8b89b4840980572b271c8547eca317ff52282c491 -a92cf28cfa29dd9c803527daf06c23ed9e91bf8b5c3926879c4c9a80967ac418d1382ce21a06ceb684466bf856bab304 -8c0626c19b6d8bd9d56f2b038c6200083976da0cd4ae5d3c3a71d73cd789fbd99b3ef414657079e6d7365ba968c43ef8 -ae212cfe8f5927dc7441d4ce5e2b72182aeea2857c35c42f8a370d0aecc2a1c718d47d1130e3ef10ae1c917d1cd752e0 -a5280d4b30cc1989ceecab7bf81acaa39bffaada1bf5f41ed0def755840e929c2fa3e2b83640dc5d0d86e8670aab37ba -93d4685a00d9f9d2023af38efae02ffe55291dff5506334bbc98399223891880b58d037c205f7768ea3d53b7de23ea26 -a0fd5e9691551ac479f91d496373940d0ddcf3563468c1be35722f746de52d1c9b9397fdde2eec33ccdbe39dc93c1027 -90d2a08f2a23a3455f73a2c3f9c8d686143e01d1b0c7cf833768efd936cd6a49d292aa1207aaefc42b75f00b70ac67a1 -b1a55052b853c1169006f8f81a3210f8d2096d483475c1ba4d641d960c0a63265d6db88037dd025bf683fd4555ac81bc -ae1724431b6d0439e0b44168b1f62278ce7e21e3b2e7da664d0cef67a246b090afcc35244fdf50ff1cee87e406cb0c35 -a029df7b00a2b57d7bf6791000333c5bb2e416a06e019394617e92055e7c78d8bf29777143765ad6b389dbb0cd53a6a1 -a7fb942f2b95eefd7986e08f7a59c6f45f0a1c51be0e3f6e33ad67cf8dbf1e243632d001c52f7b441447b1fd03b51a63 -a76f84feba16773b55f23d2d66037e5c1a9c85647c8986a98200585ec2f9cb28158ef842fa61beb4c86a85c229692c20 -b5e605081999c80ce61b53408d71a892ac1d6f1b177ab2dc7a18b03ab612d14c51bd990e5f4826f2ba4c0310e332a9d3 -98e3d5a7bad4eb817838cadb18a7c2efc5d586a402f0b54b894366855018f316518eb2d0744e439ea0f40a83176eaf46 -93dd180318c952ea846f2e9f8eb780ce5549f03b7b17de14c6d59be19419969bec74b472e34eed67f57c32be0b8c12db -963396aee89d4d7c5d54d0277a6763f8e1edd9dd608112afe9644d17b3c8c033f6c81b162dfc474c3c0a5adabb449f73 -8bf25f8b181f5f7fdaf6eaeb7016bd4e4680a011b244bdb717ceb8a99ea5f18479cf98ee247bcc76402760280b116248 -85084d95ae492f26c7b1fedb9077e9e65964e5ead9bb13bc7f1aa8cd7b8c0ee2b9c0663840c1702fdd27742ac462d5a0 -b78657254e839f00d4a9353470b2a83a782f7d8df5575e7fb9fcce85e4c8d7cde72419bacf874c57ec124dce174bcbe2 -87f2adf781f2f57c37be008947baf78d22d9daa228ea61369cf52c5f03b4e7f4d994b1269f77d315a0de3cc54f8dde14 -8b6ee9d824109ca2196e3061c821d2026c8b839d58993745076de76ed960132715678f226b289d20018fc4200d5330ad -8d76f7a41c492e403de6bfd36e44fdd564606b6ffc9a6b90ec45c0dc5594860dbfeb20b07562ad14902363e121351417 -93d86f0a70396da3daf76da707d0373378082242bff6cafd9a0e36475745896c30ca40a03e5833cca69ed76d203429f6 -b443d71684a8d105d6504637a4bf93089154e713cd54553723665a9d5c15c460976c108f79b0200c90d55edaebd4294f -a577dcb11f615cf70444675d4745dc5fa800334730c86112c05c525948e4106481b743b4b36ab12fa3144a245e9ac7ea -b16116160db122d39f939485aac8070bd63be9750ce989fbed075163af12b5570f918009037dbf71800708a8d16ef3e3 -9245e9f5da5118c404b8bdaa9f9f158bd29d38f8b7ce5d67e9ad970aaf147cacc2487a2ff07cb2f3bbcc29f8492a7fc7 -b170d0caeb6a6a29d4157e058d077518b74cde13d0c918d5d2ee76914a483e77deba9ff4d298b14af64f53b6c8883cbc -810f6c955d025d9d4b19b122e3616feb42565b8ccd914f9e91807a7d172ba3bbe4771f5ffea065d84c9200e62b9151a8 -902d496e263e8894c59493706b3d83b241040cdd4da44884872585658db410256b2f082b870cfa90c1a82bd70495707e -80c1b7cc6d570b620edbdc7c0a4583b1f4dee1669bf56bf460bddbf8e653e25c835a935c464e5cdf29a81c58c943518f -a9aa69f94b15bc7e128f9dde1632f02cf95258b99daa93b73d8c2afc060a55e9636e767b6b99efe262ae915ffd57b455 -b9b61931f1543db289aa5adab4234e48524de52e0227bc926d4365624d50a5001af70d9bd35b5a04ee57e764852684fe -901be2ac33470af7876834faad7c7474399296a9c81787b49998d6216edb4686f4acf57d15d1626edc1e5e675911e577 -8a780304feff9563014aeeb51221fb88c75b22b8facb45718bb6d249610d19101b73e48ec8f77a243429aa9cbb4a4300 -9274a29e25b0a504ed37f894838859a0687883919a9c8c966989ff651207e6f4b98c27bf397e0cf4ee63846569904f38 -acd56e40a1e25a363144a5bdd04a2d68c411ef0d992023cc8270cef5ffb3a80219af80fd2926472846f5a7f68245d9e0 -9505c0985abf67e40c7dd2bd707ff9bc3fc9d26302bc25b61c21c0cf0e52299253176ebd73b754b496410805767ffb04 -8f827fe86bfdb18e698c96f2127841ac3a20b65fafa0c7c62a9195570e6e36dbd0fe29b70313b8a9818dcb9faf95b9ce -b4289e96bd8426bba9ad67266d12e804d1452f013765db9134645d8cc2ed6979e57bb73069886e3cf688b0c294a2cf4e -926163b50d645b27e75ffcea90a733207005457de284461d9bb8e6e4a5f7042fb02553175e33b5fcfe5da906b60a9edf -ad634ee62af65d073e32662de6ca0f3d296904048ee07205100808faa1abd0bf29f53a69dcec076ddbd322bfb14c9816 -ad77be98757851ebba0c35a9be67333394819e9a65493f039e75c4c9705a88064fa3842f35441362f0d3d8002eb4b3df -b281fbbb165a7ad0d4707d219ca4806f781a2b185a09a0f649cd68cf5533e4a5d205bb36a669ee51e831a4706af3f1ed -b7834ffbe76ec1177f4dd72c5032998260c85b110f5b57a699301fa47eadc94a564075472770bb06ae2b98b973b20a07 -a5f402ea96f21ea35deb2907501f1157a649cd80a76e5a42e6c2e22b2f273098aa694cdd9fa24280c2dea82dc43efb51 -81cf72ade9fe586f7fb4f8389cc416fe691452fc2bf1cde708052f005572c098a8494c86edaca29abe456cc75d97362e -aa3a68cb71acd5c501795201daaa21a35e3b8ad5c5cc4cc9c6d19279c439985caf25c29012915a9828b47844aa5c32f2 -ad7a6d1e27d888b4de3cf74893066fffa0b7028b9cad86caa0ab9dbebfc0b28a169ca3f6ea5e247266b1377746402bab -b8cd1f7b160e8f018566c7b2bd42658dabc213004bece6ce2ebd6241882115a1a9d92db2e7ea5be85505c7054e493b80 -b040e163e22bd8f09e1aee245bc752266788b0a1d4bd731663a747286a5bea9813e9ca5d18acf50246738f130d488e21 -92780fd0e0866d4d88c809b344017e76110a2a94e6b83f885205db0634668a880cf589010e51394f16aa571e474def9a -81ff76c79855652e4a4fe8edd473e65e3b0a3ab54917db2c520ae2f43d36fb02fdb32c7e06303490f167171e58a3a9de -ad76067d73f590d68b6ed37388378b05ab5c052fee76c5832cf0cd7d12c150ecd225bdc0075c1fd98c1689c9bcb0e286 -836d5606167c62ef0bd7867d4d52c289e6bcba3d663d50d6749768edb0115be8a62168ac4e961904d7cbac8341b3c736 -b765e7d00c489029d8cc4206c4636a26fb011d28fc045875aaf81672678f8c9ec7ee27a98e5e181407a135f9d494d336 -ab782b686a3c7c8e66331ddaebf426ce649b11fb52569255ec8dbf5b6e1155208a34bd6376fa5413302b367eb9ea36c1 -a579e2d93b17576fad3a9607d40b92150d2ca88209724184aff9ebb524938f1d7889ea3b7a7e927519e3430b4bd04aed -89e1db4b574e3b4493319f4ab3cc1d2a81d130f0c7aad00b70adfe2eaa8eec90eb5133561ce3202ff6bd3f718e68c67e -b317b29982a28e865dbcd5076f0b70fbb6a389990dee3b2bbdbf2aaaaef07c363a56f263a77f6dbf180bc9610fc6afbe -a8e36630d5836a7677bb537e2765c0a97087de716b26882e83c7329412bd9b4211f3a3d317f6af06d7aa9b9305c3c936 -935e77c8a17a99766bca67aca48e4f856e402f747f42678f092ed4a954858a21b8f478c9a9e0bbc9516fe5ab63a527b2 -a4aa13a9225a61df7096c3de4c38a525e5f8daa2e9f76adffb9634e69d995fe2869cb3a322073be9d1ba15eb70684437 -b9927830424ddc42769ef94377c7643e3168eedd7944bd27d4b95cd741e159cde1799200fa33d86484d54a6e1ea2a03b -b315e14dd739b242855d7cd16b2bc98c669f51b91e387747ea1a612ebf481fb1b6aed8a0837ce27b9c9408a815f9322b -a9be82a9e77e1c101330aaee739266e6ea30249d1d294bdba30d3921681acfe48ff0405d2596f1d323951420333a5aae -97b46484207597cb28dbaa73605ea9c3c7397bff15c06176674cc2ad92746a32199e345cd21ec2d7a54f7a134d29505e -859ec9284ddcd80f711fcd43d7d91614b435c85cfc500753c5ad0cc4ed4229258c1c2c45ded6771949f02ac0558faca1 -916e6a36204e3645e524b830839e2f0cb3ff277cc49102f446b6f46c3ae29a4b003824012d2c5513d07cc402a4a737e7 -8d2bd263d30b15a9c2c3eafea17d85502c6618c5f37496dc91728f09ed2dcbc616c6936281536077522858123ed8ed0f -873272487ceab7dd687676352ca2f9da14d5ed453cf4c8c92f8bbd85341b77ea19230f78ae80b04712d53985b6f234c4 -88cc85af6d12f937078497df03c70abdca11d73a5421b9416f2a67ced7591d70b5a0e7ad562e55e0e337354bcd9818dd -b01cdc53d317c93a4b504a33fa467f5def6a681ec1d5b98f94f0ba7fa9984d568cc859d0595b65049be3b127e7197ebe -b352ad93c95e956388f33ec43e45b626f959f67d915e00c96bbb887a65a7abaefe462f9e90e4691bb71d22213a5da4b8 -b81fb507deb084d4392cbd8e527ef580d4281d462a2e46ab73d4bd9b8ca9579d2df7faf93aaf9008280a4c6a7cd0a56d -ab4a6c890d9df128c68078a55eb5aff7047455923842d9e97dd62fcf24934749ca426929a0bce4e19830bccbc569936e -8a7bd53db8401f92bf6a7633efffd0be80f92efa4845d7d1c3903fd63e54d71219cc8641f5f046267b045c584a53d934 -a8ea87452ead85ab9434a2d8ea7e47c56bdc6fe6246786cb048a5720da4274fcf007b9a35821bd2471ffe2cfd255a01e -9355bce0ea787beb264148b9a0fc51e6bec0d392ffcf21ea580ad20ef0c60fa7fbb7e045f056ac16d2f0bfcd04e140cd -ae8d7acb166734ca9ef8613222f4f0720a235a1559d77568fd4a449ad6b3b924b38b0c5852f144adea348bfdc9662450 -8e001807f943401cf12ec6d57a30c73cc7883a6a3f4bd16ee7298bb53f1187c6f45d2381ff321d57e993f339b4ba96cf -912807db0e7fcf1a1adc594c3c6b283f219e835baaef2165928e3a3dfa73d3ea520ccd978efaf73dd685659493435914 -8530a95089ec2f2b86ba752f11bef5bbf62b29ee5735f6ae6a2ee4d64d75072089d17a27966a3648baddcb70b7aa7a95 -b15b3bd6d3a5c5ac39dede41ba2c86c99237c5711126ad184b90588d95cec3d39d8ef7b1049480817d7b4bd4e3c4c8f9 -a1ee1d1c8e7a9db20ce9394a297af7f70012aea33e85e0f33dc99d83a86c72f682c93b19e8bb645d741d18b3e9ac7d27 -b3e02bc2f4f1eb39dc18978b6d6c842a5e2d4aace2b39565b4178ff250053085a1d71af33c38704a9d16b68eadbdae4c -989e460723c841a43563e12a62f16c7c8b1e59f961aebd1948df513654171dc321d72db988db819d4c5446cbb2b87279 -b3966e52b48072cdb4e9cb3392f2bb8e5b688f96f1d6782b937b3eb59c86023726090b2c33a6495071ed2f410e4a4b84 -86cf60512976a04efe244bad0c1882f94436afe1c0dc05fc2752947b413f33766556452fb7389cf80177183a4025a17d -98e79f4c3ec507e0ac6d2366abb1b26e58cbd6c10bfd7bcc92c88a46684944a6d49f530f255682383ee9c294016a80f3 -95360d1a2d224271bea707dc27322e01ab38f1b2c396dd65d30a2397d89a80b74ab19fd99171732be64d1b0838314b16 -adf86841174a64726e7fb2bf576e3be5c57c1429c26ee8b7686543f9a09dc377b8db4a95e3d0ff5acb8335d039c003b5 -a6f36d08de9c01cd8ff59c9f78bbd2a09712116d6733e2a8397dea86b3dc5612b83386ed375a2291ce5a29e579ce5d68 -a81de0c93cc8459f75391bd05b217b26673f9f3126706f2f4d863f0550284092470224f61d78cdb2c744f527f874938c -8a717a43e341495e244a4f33320cdbba4042f1e379db93394f1e6bbcd5bac41b873444ac466b75330e2f8f3b17db0a08 -b190346b2f98da03629ad3972971f9c7210474bcc48bbe76c75062c19e1fe12727596dcc2d5f921692644e99d1e2d3bd -8c64dd862c70f72c80deb4ef0a000d7b2af2840a655ad466b62cadb9254b36b985dfec22888ea8ec4a19f4075ff2c584 -b428b84394436c48e511bfde561b8d9414429b0905e1450daf0ed4c75459be3acd321fc616f3c7d4b21207274ce9af38 -96037562c455863af9447f366cd0bc2fbc10aa95eef21cbf93c8b5bb3c7c62e88c8316a857322f7de2aa17328f98bb68 -81bec7f699758d6b762f2ad1bfb5520af698f052e8c0e43c48744dd8a7d125a563ffa1f1daafd50df6da03fc0d369222 -90ec28210b98edc7c2b108646a2b207bb710779564b528dce4caab378fd67a03173696439e512daa0f4fb0e2f5036af1 -b9a1b0f959f0126dcca0c526f1f778ffad81e9725747d24f05afc5673ff02ebdb1d58c85be3141a2e02699a582ed5875 -97cb98c9b00c4143807053bb1de5cfd21e5980fbc0f6f6901fd7191f97e3a5c1cb0687ff624f97b2e4a3a90808683406 -9097c23078c3cb4dd0ea432d0790ce9adf1e7dfe23b6121ed5126f0be62c4eff59e6d58dc955c95809d97fd9938f2553 -a1e43c5a9b046b5ebde6a0c45b947319079f5d23b2b7272dd8bbf2f40c16c8b238a7c7296b63d929f069a571c1d7ca6b -8ae773c22c585927b7f29e2779463302859ad28a485dacca2cd40ab866313e73d6b6de08ef7476fc3c56941a34200d19 -8ffa098e8ef62e056508d144792b1faec04e869836375a78e1f62c5a39842507a62667984ca748c7a503d3f471372966 -83eccf75345f5d162aae2af1abc0f12a048484743f79675ec16d1146b85495ce3664ca9d88d8c8d9e8b90add6521aea3 -94ccd346b8f9e431cc0dc9b7996e24c3bec7270716cd46cde7b0ea86469809695089a39cc72ca25c33f77803b9d87529 -83b55069f117ce178400db1af5974696350a1be374934487ee28b311ce9052ad4ad8f9979931a7b36c71af00dec6b7c9 -960b626529f3c455acd5b9cf092bee0a39aba03cd09d8687d22c1c304fd27e6e28c25f030639ef75ae7e3f152b28fce0 -8d3c5247b21bb6d5af2631bf2d595343521192e8545f057e02a7a2c3e49a8e3fc752047f69eec04db386ed60002e1f44 -8d4fe310440cc3a9e7bfe60e060eaa5782b08d71619e7f2680142c95dd5353388b58ede30545f386ab16b3756bc412be -927a2afbc50ac10466e917665a63d4d6d24e642b1869502c06d4dce3f5e6acdd7c0c0f1ee8d4e6789140ad4189356543 -a0ed782c624d7420509abd6103ff44417b7e29f991a38141068dc2c1bfe6568640854f2ec847e5bb8e5393fe83ede2ee -a3ff9f2e62d86b3b82955efb19f8f1d617c2077b22e9d055bf2383499ed666a33e57148a4817448eb2e50b18cc8cb1bb -ae219dc824129eb4ed674e59511d84f66b461ef77abd45ee752a8eadbef865c1243505a24a1bf6f73863340d2c69a121 -8327b02b7729afaa54b39cc12581a5324a0a14ee47a696cea2e8b8164f22cd8fb4385bfd00256dde2c32f89f0ef47c41 -abaac567c0235bc0feaba0665255ef120d6138bec713f1eab9812c8daf37b5ff97d4c4e4138c4052cb37a26b0becded8 -9110b96093c679df191daaf092187a937864e59c885c4814d08ea9fe0d5c5d2ef5bf29a5e821a4f95e7f27f9d1867662 -8e4e5e3448be3be0b22ee1b0b561d9031c836b6292ebdfa6785fe78a8f97a8e5f38e0388e932fe05cbacddbed3fe1a46 -a55d6708f2f2854a5f95fb9fad7c14a43ffb8b48b5e1051a954a5ca7ef229637532762f0db30f2e1da88f994f412e0a5 -a6f23f2f52228c46ab79acca79ac440ed895c8a1d0924b14c2ecc65cc61684847dad75e26534d57539452e128f22fa7b -b0e1e5def6fc240556325ca345aa31f05515670b3bad6745cc9f19b109e16bdbcfa4b008e4aec200c56e093db1097c10 -8c0392a11e7109dad2358a5e034b1bac37066b50a34eaff7d2e692419feb9ef40a01909cce984d862c96c1460b474340 -a224ed90684d79d3496197aaf6430b8ae215ce56bf98f199f365daac20cfba59196ee9959665b18c5236d40b993940ad -b955fbd63a3ccd1efa7bdefbe01ebf1e3e3cb44fbd04c5c6f25459ec8f4ff679bee4de9dd6806d29964a4ba053df6e86 -acffc3f12f69bea09afc14cfb5f63d44c2ae4143977d2aaa06ff74d0ed5c137443caf98bbb1691b49bad1e4522a118be -959546657e459049397eabe338b7fcda8603f2f9e717c60cfcfa6af0cf5774d192b3687da34838bc7ef8cd0c5c59ed88 -a46d7ac7808410e35b3603662a9a8d2bd0de24150bed7c28df86bc137ae9f3711727f1178a0d20558f1e39e3c3698fef -b156f79f65296e5efea35234c68b776f8eb0d1ccb79b7c951b57bc22712f72e8aea0ffe30d2a97ea8aae0f62e2e4a3d8 -8f816ce4e779207dba556f9b5fee19407ce873ed6d0a856b9ad472c183cbaf43243caed57e0065ac10869fde15ac84ef -b5cc4b1870d4125307c7e1354243bd4c6aef88a268037208e1d1cf207fd16864486b1ca9b58bb5ec1152b62672afcf47 -88fe2321bb635558ac9f712566ac3297579aea00b67e2c2b6857e82f8c092886b3b11d1787acc19de14f393dafebc273 -8fe0ddd4f9c5a5cbb8d1120cbb698a8da1ea36179f87c8933146ddee1b2a635e0e54e45cda841645dafa55a242e6f33a -b15837b03d304d324507776a5030a5f3d3b6b69c771a7e144763c2432df9acd1f2d3dc9936f59961d49be5117484820a -9136b21549b7919c8575c90e8339f0ba2b6997a858a450194aa296e3cec838049b52270aa97506f872958427dace6a74 -acfcb0b69264e8800f7b8f00e0b8498fcb36f95122c7087f0e5f5ea8d6371248c68ce610d0b66c464759291fc603516c -904f6dc6a143a40102d89557c6211e60a28d7a423c25e54033552b83ff68bfc93a384e66f771c4ac640a5de3070fcd72 -8e1c87da2af5c01302723dc7091f4d11c715ebcba43d038659a99a12d54e03a08b2868c1e837c1d60c3431603a879ef0 -9336bcee2029ab84b889eebf3cbf3e52ddf22482f4cc069d40796ac849167b18479d79642afb6df09fbb12be85a2e4b1 -b2679f9e7d2f5cd62aca4f123106e39d8aa0ee5ef5136d1c194491ad0a4e8257ca55b53fafeda9c1508a85863d2ad395 -b092d8e72d338e9d0b9c3776479223b0788325f60ec7f561faf637e604f6ce29342e7520765797b52793333dac9d04eb -8a7aaf02d9e702b894a65c22e7440590d1739aee7f2ac967cfbf3ca950fe0c4ec04a0eb8e445547239605c0998f5564b -b90b3f7eb407464cec7dcee507e1b3f361de225d0f5326c61a11e94a173f345debaa12e01784252aa1996d4700d1cfbe -88664ecf12b67cf1d584e7b8b878cdc4ead8eb81b213dfe6914055a422563ea149626080f0ea1898308f466eeb4373c2 -9455063fc9535ec9feb3f05c282d5ef3da39ecd4b7a38a0983d1546e007a47ee3c23b6c8635192bb866cf92af60fb592 -99898733e4218076a729232fed49646275e08647b7b441aa84e019703f4fc18fb656b356fbbf97548d6f293a763317be -99b5cee4527b689d6513e4a05ffa4ed78817645df53f4a0849e8162ed867c412e47208eba5489a1065cd5c73f14ebe78 -a90800759a3270d577d4159be6dcf08021586434bf931d88fbcc26ddbb0bde0ce402241cad87cf0eee35d4fc846d3dfb -8e9466a5e11b611ca0edc0e6af0eeb77b2eed9e570fb0ec2692654de90d1d73c2dcf42f281128c9ade0473fe87543b69 -817607875e14440d1f7ee44a9987ceab26e47eecb8960f0ab2e3a98505bdeb3afbf2c92346a5f2564f32611af35eea20 -a497c02335c02b2527a0314da2ffb15d24df06ee396de5d9921ac6557d9f0acbb19c4bac457bd0ab3941b2881ce3e536 -86da85c393f8f291d7d7f5d0b8d98bc7179a951f79d7cd6fd0067383a002dcedeaa71264849284132f9fd69592f59f95 -b602c85dd940c1bff27b3ab7b93cc1981a1ee74966910baf698fe6f1c6be86f3d824cb5e4a8959df223e674738e71e03 -b4786f67b8f7799422fdeb4b4a6d649cc0bdc877487670056fedd8836c298984863986ba1365bcf9acaf29ef1eff990c -afd123e4d2cebaa8319fe0f4e2f7b80432d58c164e1247228285d30d8bb47ddd610bd57e4ed2d54a287764cb3ee90cb8 -b988cee812c7c6387a814298bb3b39be19f793bfd0deadde4bf47e7ab7dc1db1d55c56fb19ce034f466e1fee6cebf084 -9993e7e2629b7d9ed90b169a8cc41cd7f153356b92a1527eb7b9518138898980c090bfb4d0938bf57f2af519b7fd51bf -9096ef9a2ce7d5e94d62fd736a3743ecd8ddb9c5152975141714a263bb71ff57b9f8f39c6b15b968c920a53e2039683e -85462eb8184f23b1d89c24b7d222905bccaba3c2665545d57548173abb60ae2c317b26de99fbf7a576e771566fb3531c -87cc549572b2287b78c5a28c77ce42cd1eb46ba7413f827403efb8bf554d735f5366a49c1d146cd8398a123144b52ee6 -a6f0a427b8ec9cbc3cfa7cbf5b3f98ad5eec34824620c9215ff6ab7b933231ba1534a53141aaa59031470a3a994e75f3 -91c8bd19b39190f4b8916eec2d33b13f6b3605da7b511d41ed3dd5cf790caa755565224308b266c237999ed396699ffb -b2614c5953e37f613a1489bc7745bed65264377758de39239b27372018b52d45ddaa174be167781908b59c0f389f9bfd -8453d03b0a7f7d092354c51901c35fb09bc9c3a1d13a64d944ffaf309d1a8c453e586b481c25037e711976207073e89d -86126ac6b68429356547d340cc9bf5225e851540eb4e59d2823a753129c1c98a14a89cf497af8cafbe6f233b59494193 -b526157f26068a35af48f3b182d5b04cc3ad352b33e19797dc9f9baed69a71140e1638b639a376ccac978e8be297a04a -b7f97c6355782783a0df6c9a751d2a06fefd0dc0380deaed494393d559178355558ab10630dd4c23fdcf31455504eacf -86cb6421bf1e4ab8bce161a6eaac0981506b1089ac537ceeb5d3f6926f5ff45e75cc9b7dbf3c2d01de97635096c3b909 -aa70c056a180509e9b02c5224f63a61abb87f649e28ef4cd33890ff2e49d76acecd0628c4b7edae410ce100d8cd3db7a -839cfe9ea5543611c1218233dec1c0fb85499b5d9bc5dda58889bd6ab67defe96a66466185a33de8afa4d9340c01741f -96f908d55d5d249822f9338018b4bb610e01fdb98f690d6dc886a238fff034b534c04e3da28565fcd785c42f127cc792 -b702a0775554e716dc53dc2c2001ce8d69df29dca24ecba72a31f3b76ba6e03cae7a57a359b21d56d2b1fa3a034d24bd -acb79273bd0b0814c017894dedfca3bf1136754cfcdcbbca4490ad24c034f4f12d48318c33add943b4057036fb7242e9 -8e6ac189af56c52fc3b0bbc1f62b98904769d0bdca1c7d8895653f68ed0e3da7556ee691fe1196bcf9f944a2f2795f97 -ac21009993cb2e327dba835b714356db25199c7892b49f9b764db494e8c079f96d7c5d6b751fb75767eae6f87b7696cd -b14365e06ebf557eb184c7146f7df72f07674419e31839f995c3c655c326ce886ee909a60a922f3e6d468f446a798eb8 -94d33c2a087c7e33a7bd25fc3bfec4990c8872c897ccc77bd324a4cd7efa87c9611e8005452ad101e3350f9de9dd4c35 -962d7a29f61eb82ef4444f6e114fd4d52b3b9bcd7ad8a96bd0fe5f4483530479a037852b8a34c6702a298d6d76d78d35 -84017833344df747ee5791266abf96431b678c8820dc01cbdbda980db0b314ea581af095d7971db6d7d0867002533d2b -a45f6d37885e268172dcf59aea6dc997f261184e6acea2135d2a89d7b4646392238993a124da7432b22c801b6e847fb3 -96317db6195d8ab076203f9457db5f38359c5221ad365b31838139add58038893308742ba74cdca5160e00659da5985e -91c35ac95b6ac02e9b900da3ab881fd98ad0df5f95da23d61a2833c79d9d49af29c511faa02ff6d3bcafc001e9d02282 -83da2069734885b03b6ee13d001f9ff59d7e98cce7e996b5e6abdc7991d99b6578b0ef47b72d676e311424f942d21d3d -b4c04bec1e45e4e8e33fc447bd08ab55dc9b7cc8b5b0e8ae4fddb80adffa44467628f14a8b0afb9de6ee62b5a5324da1 -81854bc7236732ed97b8743dc2791ca0fc8c93478732832d3a3881cd1173350953cd194bd72885eeffd409d43795c962 -a9534d30a2f9d2b445049cd78c54db5443b4249ebdc45454f3d3508765f7d5419af696fc335a1ecefde473c63309c9bc -a495a716801e2c7bcdaaf5358db667502ba41e4e82c236574cd4a093f694ee3749b968bfe150cf77e4189af052f6c0aa -833b994fe58b52a9b3790bd0eecefcd77f146b5d8b5d29c84ec92b578450da8af63b1c02c94fa5b272d6e4c9c17be911 -904bcd0853ae8d33f58c208655d08d3d7788cc732012324d7108436e4201d6e02e86ef1681b013e18089e2cba8b0f955 -a67ed5e0c20d6a599c6acd1507d6921522e461a61fe80af4917ca653a2d71ac4cb63fcd37dd30df9344e79943ed07194 -8639af3e148c36fb0a47f89a5f1cacd8620cad81e0b506f4376af406e0ee86d59698c207ef1fe3eb0ff3f7930d92fff9 -93b85275f836797f4415321affc642614c2545c25589cf2250390fde618174a9fbb7b9f71c2fcfeb2c467c96b4a20fd2 -b653c967b7902b87cecc877a5743e546e599ff287571f92c07c29ed3399573eeec51d34bb9792c37e24d4e9ada810ce1 -b37842a364a50583b2b3dedaf06849c325dc4af676e974b923df3183725549fbf653713945376d67fb87a5f338a05c1f -94f9122fbbe19ece712ac29a992adebce028f98c63f7d6f6e25e0f0971b301246f0282fafb6f586726776e8b00856e4b -b3138d0a2cc2a902e6bf9eec98f2981c9257dfb53d9c8f31a0797706d3181a4ccd9b9e777792af1226e41c1ada736f76 -8774a599a9ff5b5e16d4bd807fadbba136f1c8705753163481dbe2ebd12eb298e200acab03a9a72358b8ff462ae17d92 -aa802d6e9dbbc659af0c3319310cde2d28d2a7244f11e10c4cb6290ffb75975d5ca05e6ee0504ca11b8b11c4e926f24e -90132466d59ce7321c81d21428b573926fd5e1d29abd1808ead82504cc1507ab2d4346adf74280f828a5b8451eab0224 -b9d4104865f1e1b6bf694c3139f623597ccb17a97f75ef029d4ce26aae8704be3351e0363d23f77ad592227bcc64eec6 -885b0dae9c1a051b6b056a4b2ba10b49ea7e141685e63c7bf6423e1b2bf733e88caef28799a29e5d193fd0cb3c5081e6 -819f3a31608f7d5fdcf2987670ad635c3dc0c4807ba28cad9a1c04ee4ea04890bd261a52b0e07b0b7044a4ad008cbc98 -8e710bc738938aedb8defdecac2f92369ee32c0bd54354111b29924b8eeac56422812639a83d6b3187de14b406c88d5b -86e8af697ae305e0d422c6529d343d7ff251b7730127d5461b9bd015f3837ddacaf58dac220d8b1e3c80c1b7e9cee747 -aa2e8338e14d36082225b81a816d225cc68b6e2e8cfdebcd98815b45f9569b2e7f2b43737205956a110b20dc22dce6ae -88a2441e958fe2d2f45da8ada6e04781e06cab662385cc0cee0dbc50e9c0a4c47df6dd89b59036c394e0a5a209b18484 -a6eaf0ec69d2b2f2f907759ab1e5e99c35c69a7a1614646478d82e25956af1cf0a347c150a4f963adfb8215e9b296c2e -a04d223e9733544b08e6ce1a80d7f276d825396b97e87423a808e1b80c1c08b02a4425a766e5e30a156207bad583e225 -b35f6e3d218833156f84746f7e5254a22be8f2cb57df5a518fb24c9c5d232ceea2a2037fa38da923f32ac43c5e6a70a6 -b3034ba8a0a28b967e53acf96ed8b3839c3f4f29e87a42506cb3c797e4e43ab6f67c78220925b063302b25e4b8c0a7cd -90067fa4ac5813d8f9f4e21efaeba0492b4c1709a0aa9e83095437d77bc5f506c8823f6e659acb68a1a3c9dc13046040 -b4e12f0e4f85e27546b5e534bcea5754fa943aaea35a5658d9c810cdb4808e0a824a902fba89dfeb0af86220c3b4f6d4 -a7dbf474a2e82c9289e850fac5a5e6c95e1888067521ada0995d472c79581fc04665e2ea98ff1d47d704974a52578920 -a01a417c5da6f036c89c1e797d5cf1fe985cfeb16171c629dfa65feb0030894f3799dda25fde4f7c2d9ac260c4a62f34 -93d3a10c0db4c82c18321a2e68dddbd93b92884a27feb756b09d382fe30707df2605d12f8a938dfc84be45876a8e702b -83a5e28541109205f9934f43ae640e4d363c677583cec6f5e1e3211fc82233f2fc33c8ed4c661d66bcfccaa822b65159 -80c9285c0b12dc605392e883d49376d87186b221a0b0247d1a4cc259fd15783b2c62d7fa7bf996fdc72779fa8bfcb56e -91e838584d27c75c15a3af2465abb57b3b208f36e2e3b62ab6cc3e7a1d2a1924c3d35cb0a3ef76c86824efc6a0257d46 -85606ae7e00e8425365714b4d443e478256454402662de71b270b94eed43d9ed734b15f615fe6d2747afe0325771d89d -a4c0337b50a3152198b00b0dcbc76ecff544b86932a4ceec981639bebaead6fa2422457950b9d81bf0865f8c735cd7b2 -a976f5d40d82658ba686aad9a4d139ecafc13c45e5256aba224f6fc3971e5bb63d3337f837eb23dde4af92244da3f4d4 -8ec5174814056e77d82b353e51036305bc35e42b5185d6c621e1e19ec6b3d8bad74695622f7fa04d86785cb8e11c5e15 -947f2505f807e6293b991880602960b459b7ff602cc1ee73ec9ed343ad353758d09bde973f2247a8bb4ead425db191cf -b509b1d00ab53d57b6229e97cb5d5c426931560ae7f3dda8686f31974f7236833dba7e9aae014ddb1ca70f8a841fa0ad -81776e3655bea83556ba387494230539ec5514aa460c66a75391e6bcae251e4a4855d466b5100dc611f638487b56e43b -8dd0a988409285fca7913c1a503a304cdae2cf5d1d6577f907501b7fe7f6bc3794cad18620bcf8de071f6c78e6f76536 -b74538e28f5f74eded6a402adac2d4fadabc5a7ca0ef6580ee8663794c204b4496a634460087c53412627525063fc31b -b43a027b5421058910b178f47f00846161d054007d771a224941e170ee07c2fff7415aa15b3ab76f0769dd09a09ab48f -88fadf53da7b8ced103186d76be327d7f18a7e81078cba8ed0b509dc03be4f6c68a94315c4192a88ec4b568de67801aa -8522ffce27b6ccef18c7cc2d2ee34c3cd584592e8a60df8f22a4bde6b8376ed56d42686e279701ba71e9e6f342abfea1 -b38d2f77014acaf060385d151e6c6a9abca0a30d0200bbec8a4da3ad33b7b4cbbb02f245ed8811779ad1472492a82b50 -8beaae22fc5a8d6d097250da9f2a71ae415a441dc7d2a90d2a34c2cf395b15016fba401c8badba7423bdd52328b96047 -824740663edcdd144c828ccea625122c10f2607bc7a1dac8fc1aa22d21feb635adc509cec6ca4f511dba89a48dc7812e -8b108e890f01db768ce75f281fca63c2d0ad51a93a12cd5b224c5669db87c960c409bbe563b419134279f5bf218623d9 -8ee995ec787f81681001808d54bc0f4b59c43acc8582448f44ef8e6532c1679ddeaeb9a59471a32b068de3039f3cf1e4 -84913420e365aa1ea5d6bddaa0529efdafda33da30e53ad453057bec865780f0e8e7f710cec7d82922885e36458f5ce2 -a8c198ed2794f4478595bcb26ea008cd586118dfe618aac0d9066b6554d01a40aa80ceb6f26c87990d5cf1fc4eee577e -85dd4cc4688242e1e2096ae5d1ea3316ad3b2a866e77a079f52b194bd5adcd21cd24dc29cc29996831d4c73cd2978322 -a01f2dab073ee2c94e2a93d6132fcd9a11f4a7ead2a77198415a6fd2f3acf6f72c7c049c8241a5367fdd41dbb4e8b16c -99e5d15bd8d4e01621472cdc813b864014edcdecbf2d50236cfb27d8033c014e38e0ee86d55356879b941a5074b2d2dd -b4fe24fbf81158136be6db8e32c326b4710045c36b2b360c1e1cdf9b7f3e3224591d88c7556ac34f1cf3648b45e0023e -a30c202b71b6d441f684fa7ef3f9cb582ec916f9e2c3f06f214c989153978f4fb3c131bea4fec793c3cb6b8a0316ff5e -8c0966533478e5d416cc7ac1f7e071122d66cca29ca7283da8d8f8fa2d42483798a7b45df8a2f9a0b976b77ec861220c -8bffc2bb9a5b14f466b12b2620b31de959ac758799e8ccde00134ad91d037a582170b69231e4a6f349624e110a8914a6 -84a3ef37749eabe783283dc905b641ca3acd9651a0b7358ae212566329765fe8a0eb3d7d02c8cf84ac9f89cc7c1f092f -a2dd434b8a2cde06e5acfe45734588b4fcb7d8a8ad7dd20101e6a96ad7621ab42a943c7fbf6151f3ec8082bdcbea1056 -a38a4c9a144770338a976b81ea5dc8782228a25064024e5fdb8a6ee0b79aaaea9a45cccf8f2776e731f69cc0bcb53a9d -b382264fd466a88db982d8b83d8c6a21807c10afc213735d9a06bb5a08bfe9404613cd9c036deef03b65453dfa1b598a -855cd6bdb77f86aa9e04aa8c93bc4c898d217314f850d0e55e2e435d213871fd4e2b73e46321b4373872678671a2efd2 -b00a43842982205eddf499473deefc3645ba52bf8e606d02c5a2b0528d1ad76f0c18f4c733acf301e05f5854e8cf1cd6 -a791723e8e9d2469077870cc29b096c9bb1afeb9c6d55f0fd0ef41eb4bce532dc2e10cf13c3fcab3ff7f1f22fff5515c -98f26fa5ff80441af2abef79b9ee3d9785152088bc6212bba7f2aa500a5377839a307e3c42cc34a1966bfb5cdab90968 -a3d28d62217d1b8b5474af055a7605a2cf60d512f85d3ae70b34a31096d58868b110451636ab15707a8cf0078a7591c7 -8cffa106eebc653ee9e35a184035c130e52c1d9a72fb8b1af014075c327ad16f0110f7d1f5a146935565449ea9e61d34 -939cdc45529672571f6eb942855c156a4cb95252bd12fe16e082cee8bd4b8b33aef1307648c340420c013125366ac52f -a0ef4b5f97a4f7e0ad95e6fc765584a18400be9bc71896772e304e7fc12b2a8ce89dedbfe3a3094f6a9b622216ddf909 -8e040266960e5629f8673314b93646990ddd95467d95a440087199930956594027c952e18cda1ab61205dd4c39da47f4 -98cc4fba2d6375589d6062e19f82f79a5d34d420edf626f512ddc68fc715381e675bb13ee30e3b9d9d810a246b6c8aeb -97c72db6b896d1e5ada574515813fc6b1833e7b5bc8aa2b853cc580de0829d2bb87322f8becfe42c346f6faa8de9690f -82e8d494f4b75ece8b882d2bb25fed514571b98971b87ac240f7d6d748477cfab2aee904e796c45502c04053da9cfef6 -a0d1699bb87bd6733fcd510e1e028640109fc389d7581685889e9521b9e5ee3ad25136025b23e783820a86743cb38db5 -8666c2200deef3b6b9330e21b2e342740264b069c58e46bee95984992e632c94723a53624bb30a0681acff0417e2f6a0 -aae412abf586079adc9025f7deceba6cb15cd85830b25fe568144fa6f4e6ae6ba3562f6c6e6c60b4cfb7c7873dbe7d4e -86b796f30c0447bd08a6d01dba09801e480059fde0c53607d786ecae07beb18a560dcbb0676bc193ee3b69126f7b3de5 -a886596045fde66b9910e9fe065451ae635bf65b2ffa4bb6569d14e06eee48fb3806765188f4ab3cabc18eae2595f6ae -84fdb7c6f688fb8f1d0f078aef13c448683562dcae1aac49d4b8cb691c96984fe4c47c44802e973e8a59014eee657f17 -8145d34f2bf14596a435469536210ad92c309dd5dc25550c27b4cc4e699b4456eecd95e28319486f36af2f3c77804804 -a07e27baee9073962df0cf1788da98775d98baa274dcd976e301f8706c97332280b525dda993208e35dfe834ee048bec -aaedc7e5448a2b4ae0ba18c3946c4055b5026516f10b4cc245d9e9109d48ad097c4897fdee3ab394cb64fa1659056cae -8a66b3e259ff237a619af1f5f04606475a5d02cb0435fd4cbc76326ff0c882e2e22212a261f07ae169ca454fcaaa433e -a4840bdb2d5a23fdad5ea27ab2e80a5bfedde1a203a45c6e0babb6d417e7434a320aba2058c7bc80f98690e0ce147d77 -922114ecb80b6b7dbf568f92f4d1c3df5bb3247565830f7e5237572ce4f297b907d22cb934743ea8a6f709dd77239429 -82f979e27bd6586fbad02178f74698f30c60d938f55c10efc8a6108c1d231ecaa4077e31f783e2d87e7c125c6ba95827 -a3d7526008816caeed32cc4910834757bcc2a26b6d0edb21eb23c951cf096cd7cbfa0aee0c4837e26310352d755ce37f -897369d1414d1809c676ec821fb1ac02a4b31c2a7a2b70117bfcda241288fe3c237866c4133fe362299ef902669cad7e -b60af88a59213d0d649be2851d43babd85745c8c0326980459905d7d448752dc62b092df1b1de6640d578dcedaf21b49 -a1ae360b6111efa07d49dca10943d31e1754490306f9d0e5f1015a1c943a882176014bc2acd8d0cb5494ca92fdbaebad -aea9be1f403daabdb0166cdb5f24444375a6523ad829d7cf3af3d95d0bd68b93e10bac514518c82aea1377e7fafe1930 -b88a4d22ebc820baaf83559f12a0bb19a0fff4bd9d7832abd3285ec5574095f44f84f1c9ba88931d2db94870f7a1aebe -abed568d06b6a4364c1e1351ae89cc2918908d99a4462894e8b23f5bcc19fd1300228643b88645e536190e70a271f069 -8f21c94582b716227d120a7c39f3601e8d2b97821fc55ed8c757cdc5929300dbd06a0f41ac6ac2ff2580d797da569e0b -8f37e8cfede6496384ddb09610c716097f26a601f42efc62456aa18939eb51eddffdc36a8b613a05df2982b68d5a9a5a -aac43a69bab717ba1f2f9614797d79680bebf6910d682d1e548f67b086fa4b9e3dddc8d600e7846f2aa196721386d6ee -915503f707c16759f12c953668cb3e6767d05a690f8fdaf717f5ad845f587f4e6e5b8ef1c1db905c7c490ec3c93f4925 -8d9f6b0761f045b69d110f533c6cc358c98237787e6e52997210e16089d3bfa03371421a40e524a003412e2a58166e27 -a8e602ffb00c2cfca33467ba5e63abec1ea4e7a037822173444362a1bc62317b23ce1ac37bd7e66bc7fb65fddb7430d0 -8f498b87a637f7064b0fb3ccf08cdfafd4ebb497c60bd1ef77440da832f9ff54cf7f8cad2c4147a86d4135ae50fcb2ef -b0993bf9679567b3a1b554274b6b21c24404da8a0b4f38cbe864b4e1980d334919d3bea6b4446569f86a89853b1b1387 -a19026f8e776b678cd359d8b7815575685e654e01d7ad867edb7a001f6cd6d8e3d058088942a1a4aea0654d600d44306 -b4ad341f90c8285b2806e51efff2f6d957f8665605e0aa9c0a3e178864bb1f39e41c07d0397dcd6a058d4d78e8a46973 -97e740c4f9e48c16cdaa1360e5c36110438418b4c4b0ca433660f3e6d0e155470b09d11803ade72eaed5f56aef8f3ad8 -a7845ee3cbe37e88cb1da48d8c0fff7e60b26d9a31af3319abc51975d8df9db4cebb2e4c25716a9ac0729fe31fa36071 -b75df19efd2630425cb696ce8d12915b929922a97d5504c2ccf14d2f80c33c75aea0662fd41f0829ad54a1c3dce26f26 -88b9f09e41dd9db76a136031ed51e60a8eaf07546ccf394696bf9be77d323fbc85de55a435a453905f50d179385c37af -a592c37bcdc9588c2c0442a8e04f7e396b169cc611b04f140754a5bfbd6feb5ab9d58c262ae0e7e1fbf2d019186565df -94961f4255df80792cdb9e714f5ff2d57496d50d1542584f29c058a3b53883d0dc7cdb61c9b1dcc6ab4aa58062fbbc23 -a66404ced470420ebc6c6129e32b2cf40181c6e985cbe75a0c958c6b4cce246d9c02142d1a4cdb71b73273ee82e7d32b -aa76b3bea6f14e21adea4b4e19ef905d2789e51e98425b7ed72c22d9011add2142789e4e86a758cd53ec884f4e861052 -91251420ec91bea38dd63418d3a395605b8929b3ef0c09eda606bd47b6dd9b8b5d99d18d5b99a2031e8c31fd01a184a6 -9887afcfff36dd9ac5aa45911b1513ad9d38d903eef6e43101df9d85e88a6d1b18c95834c5214151eee459d9f57cc7e7 -841e9ac3ab1a2042b91d9bc4b1ce36cada72d9e6196c097272306593696e74977ff7f07f9786e8ccc7e47b964428719a -8f81c9bb13c6d3ea5927e187a78eea9bfa3f8bef55b821e476eea8a244fb54e4c8e6cddd7a5072bf4072a05375160ce1 -877a822a1bede0a012b15437c12e8e930429a325ea837579bc865443cecc7abcdbe2412d3a9fa22701460c7bb03879e8 -868b5bb9bed16a705f54bbba34316929e30ce6902031b1cb498d846e7a00887a662d2f17ee5e303ac80d4656e67af0ac -97d5a1841f5ee52b3d09cbfc3a43d7e0606ad94fa81172577a7f5ad5d453bb2bac41e5266894b37e66fb3d157d1bfb3b -b566a622e5b07c19fed347e55beede22ef5400c1928ee54298288919230e991f217cffc4701b314b9f48b7a5a447cad8 -87cfc897472cca7a8bf04f24e796b688cb2680a20b408113a1a0e7bb4bc2645f1a3e1c68c784a043244dfc0f08933763 -99b8cda2633b72d2277bc157abcd43b80db3895dff3a109c4e1c795a8eccc5ac47030d89500a1fec17474a893ed1dd65 -afda6bedfd1786c738b38f6934f9bd0bcc9717c008b854fca68827cb72691ed8e39e00ebab284595ca7af86b5ec6a032 -b4927edbdeaa0441dce64ad8650fed09ff2e32053f7f71df2da3550d5d8889745c1c11834f6436dba76c6799c681c40a -94d1c187d7bab9738219f986994fed546ff6fb3e26bc1acdb2bbc76107defb06dee1b04ecf2d32cd71161919e05dde0e -80d7f3b7be748695b607767640e65955376b79d1188fafedf866c0b98ad7f49a9cae34678513d523467194c89f3c4d3d -a6c1503ec3208f573fa9a4589bda0bc533678f6d127af369248c4468ff2717278e5aa2ebd1eb570d303cee34a7119df3 -8ce7b9340ea4f0220ba13b5d75c0489f1c5f5f5f5ac9b5b0b546b4bbf191aa77ca7693b6e5fe2000ac9a530d863f356b -b9ad6de16e650e06b23163fbdacf92badb1f74922492481c3da21699d38e3effc6cbcccbdff3085dd7f81c99366a7c51 -a3a4ad6425ecce4b3274aa107de052195b39dca47c771c128717fab88333d21bce6c96ee4c08f6abb3a2bac21eb24c02 -b8c7f52d9aeb9b60e9f465206f1b1fd6fb031f1724fd54aa95ea5e983311cf0b137db1e59453458ec36ea07302737c0e -a282d4756e5dbbbbeca8e28dd419d31a9df41368ccf638caa285533318f593fda941a4c5871af05f7f6c65183c89e14b -8763ee2cd57012aa44f787642bdca5045cea22ddc0b0bbed4e61473b58b1a5c7726121539d6766b32ee1428057da8b0d -a89939dcb2c05e5fe223deec52f422965184698da2748874b5bb564b5c2eed3e7a5f7a78e76b44e2cf4ab670dac1494c -a05f25876987243fdd2736902a268c122f2a7047320165d6003e6ca7c68ca828507e7bb9505e691ad2f83967c0a8e9e0 -b934f865aede261b639d63d6765cf9bcc4d85cf8cb84391930a4c2ddd6de0eb03a24b4c90b061694e9fad2aba38e6f61 -92cec5861d7fafdf3c9273a072835114d6e4a0331e13f7af88145f2bb523f30106361be3f46064284cbd4cc1b2f40c6c -adac0093eea20db8eba318a3bf55f9b87164532c81aa9214a8d897a9e7a7e9cd232d97fd9ca7e30efd5932576ed96686 -a31eb8031d0f068339f3caeb1a6d845d3ecbcc0bdfb8986467e96d0a16d5c9491661dc8b07b7c8c378b84c153138bc98 -b485a3bd930e39eb4e5d0dc572114fea50150148541d10dd927618389c5a2da6da3353922354a7b908707a7f2b09d5bf -91d1a5ff047845bf25aed4c11f33e02b4bb9041e856f1df75484be24d853f6db663c4a72157eac8575b337d589407dfc -b4780a9d0eb818571953c1579b4c93532c7fbc63adbc736f5279cf10d42badde0c06c2b1a9afe6bf1e0052839e611154 -8868dc369edb68fe200d3287112775c88e9fff005b143da172b4e3536c06cb90b6b425f78b59d9fda2bb157ffdba3955 -997c280d7bde64752488f7d06fc3f5a887ec7b05504763cd087970f2ecddfc46635b7c6ee03779583092a0f999e9fb39 -aa2c842bfa8658eb65add3bd92bad2c1382162cb648819390b2c9d64d3c0e62d559a20e6ffb30bd77cbff2db202ee75c -b3b6048daf1a92f85cf037638dc8a2efab333eadd1acccfb2ced33dfca0e85b522b0c5fd27c49ed56012f7aac20c7829 -a568b95e286c7cf960592feaef01956bf8836397e2c707eaf8efd6b4c2027bfa1b0dc7f25ba7b9697255e44fe46f5648 -abb3f268fe89490dde4ae1e62b8855d55a99404aa94c666477c57a64ddca6907bd8b90541979248dc1fbec33a0ad3248 -82ed0c36ae784b264c4e0cab543daa1b1bd8a3f733f409ac19099683a0fd82239f566f3e0cf884505ef9fe89352244e5 -8afade0bf744472146e48d1f9a8b5e9e1cb7b4dd6adad865bbdb5fd486be40c403d9776f29e0e955000aa799e1d5da6e -8ee8d222245bd33e7bb7b08066a4161e4fdae131247b8227fbf5cdf25cea9dd9f06ced44a9b402b1cd55b36575eebdc1 -a3f166bfd953d398febe9330e7949d8cea96655dc89e435a7eabb77f6e574c62f7900b5184b99c8afb370e9e70b5ad08 -a3e7aa63d063f2e85e3fc69222c50ea247ca003f2f2ff3a68eb740c8d5fc520e423af63bc406db568a48f54b9a4c3d2a -98baa3a8a39229c25eafcb621ec7621345f744cd4278a148bf871bfc4033c56554f519e658c2076bb5656f9b77011899 -94713808a25efc5dc1e2769836da6af30809f9a1bb084de0747365af029d614d01a0881966ecd7d694ed782bb4508246 -b1145e097d1ad7a8d304688dcdd593599285854142bc797a27f44a43ce544c5321c01f790c07976d29e8160f47b2886f -989af1d1c28396a2f23aec1437c23350d8c406a6106ad7dea0268430c333375b772cd71665025ecc44265b993197a8cf -a27c1730483212902364b627f84dfde5c4edbaf8e27673f73b053cdd03a44b1d9f0a62c3770bf12b1c6c999a44f647c9 -865fa094ae0dbc4da9a959cb9d0124469cabb80d2cae2cbd4f59674db08fcb2cca2c28f5cb1a0965eae6281f82392fed -a285815f6f9b38f2fe0ae3d5783cab60757598a84a6a8691a3f22da6dfdb00ab7b65a162c2714acf370ab45784ebdd5c -8736bd2c51fd32a3a45d6fa12b5a48c23753a8efa58056217ae3ae8d7d925cc4735286134f4fc9c45b647f2f31d828b1 -b4a8f5469337ffbbc4960f2b02afe25127b27aa2ac073b3d94f1d0b7e6fa1ef141f2713069c5934995f8e37eba5d148b -a1dc3f7483b170e92edcd14234afbd0405eaec19150b64d0987d128d7c436eee8d353fdec7b784b179d74dc5e6bc1f26 -b8fda1dfe383756dc96383705f95d8573514c6395e0dc6b675ae9df4e58a8fcf42a1cfeec9d13b4c17ca511e49a4bb3e -a8e52ba9f89dfb4c4d6c6e006376c1e3af2067101414c0d4770614115a16bca52b09b1615a5c9491e498fa692adbf1bc -b04bc497383a3ee06109278c4ec584e5377da2b16773d84d5196e550fbda1a15d78b2b99c8163334714d2ff834445a08 -8a6b259f9ebee71ccdf673a6a8775bd088f6b2054f3d91819c7271272a684a16f51140a48bc62f86167b8c403c8909f1 -85f4142236cfa3b2957d064c31c5401a14d09474a85144429700efddf0c50b8729e322bd8f61ed4b44d09afe1cdab23c -85c470febd2a084e5b14c2b339b40b1ee767e9f04e862ea16470d170d1d9bf429dfed415cec0e931df3787412ada3773 -9603f798791ef0365e334c6418f40a18e8d2b0c53ce1fa214d42212c223c583a75edba8e7e15aa74dc492256b695b700 -a2e348bf2a2b84a560318a67717d9c33dbe5a465c131ec804a051fa482d089352bd74aa37873b00e3509651ce7a9f44c -b26d61fa3b9eada68ecd44fc338fe04eb7adad1066919da6c0ac1147b5f9b4e38d4314fc73f35701452127161880d367 -865a0c480fbf8154a1a4170be713e5d26deeeee6b2858a8095f3e3f2e613dfb7d01486097f9262663c381e2183dae367 -90e3a891f089e7c131a0e3ba2ac506e165bac8581e9b56043714c019798db2a9c10100768eb3be3b10d0c99ca1edf69a -900dcbde25b6258b82ec686e2b046037e3b8db16c0bac92c14da5653e3fac2f6b78206584a8beca3b4a39a49a4c8c3b1 -8d0b05a7342f8ab9e80f6b4e532d1d12a805194fe3e06d54962b264e77e71cd52ed8f500e6febb8967b8fdfbd2577754 -b4d0b53897f983b87ae22f4fd32a27dfb15768170053188fbc1f27cd300ed425af46ee522eec54ec9fa9feee6cb07133 -94196112213d65ecd4996bab0cf14916959db441b73f033c88b9f477f130ad845f468f932d781a2a357d9ee25121d914 -99e8c44e69076500b0a0318d23c0edd3f6d4a43edfa93b7d3bba5bfe7aeecd3ee12b19be71a5731ecfad4843f5dd68e3 -b702798904d7f271576d2295dbf90a6d2a45848eb6ac703eefde92b0c303089e5294e35129fa15c157d023ea4a3cd52e -8428458b24892c6ed694a8f8876ecb2c2db05419d6e7040cff3518989db12a49c20bd08a97a67a0376f8f05e0c9ceaa6 -90fbf15dcd3ba8ee1693392ef8796bea18170a887bd212650f9804b3b0f4dbf0b723269bb16a5d78244e0974b5c68a21 -a723cc2375f0728f38d8fa1a8784f41ea4210616e3ec0dbc1b236dfd8ba6f24911fb558dfd3220b8f1c5da2c5151e2fa -916b2f94f6f4f4a9a0211d87acd7e4dc712701e78d8e45e100e2f955059d0f882a246e766722135bfb377b17e0b46478 -92726d28ddd3da02d9e88fbc622efda082a7c5e60e6c0ad83679517e83b5b58497fa1c6208748bdbe2b9751c30a6bf18 -82e2c93e563f097dcb52966743cd052b96ccea9ca2b831878416128688caf7dd92dce67a17f89f9ef7bc1e2a65d99f04 -837a9c2d03f5071410c274da522044d2e655cbdcec3d300270590029da6e7d6879390247ed595400492421767caca7a4 -8660f329f70b3dd6e08a212e0ec91be5a05e8c92316b5ac875fcc008bb9aa343887a98257e7fac99737a7ea027bc0449 -aabcd1baae69dfc37bc8550657e554ab68c92c9daf4a6f56ce0c9d7c388dbf83dbcfd911b64d51dfae0758346451eb3e -96856362d4974ddea8195d03ed6b3fe7949930882e2943b38f828d959105a1e87de41f793dc5fcdce12a0e2209ef8bb6 -b39ff1047058b29823f824aa3dba5fbeaf5ea11576114c0c843db8ee3382df1092c11779104aa2c9d203f87b0ad46cfc -a792d491221238f7b3c0ab5fad58a408f5e991738ed5b3be2864f2c5f638c32b8d44a9ad13816cd80a67c64143ca2bd8 -8a3b31488835be700004ac8acd6b680cf3704277e5ca781dbb72efca2e65f33fdc9ace3444334c85f206f3c162ee81b8 -945dbcddce9c048f9e6f1a2ec8f9564d77e9b4dfb21475cf6c535bcd1cdf5ccace63e3efaed1006cbb49f0717c2ff272 -816380ced8d65af4ba614b3bb6012d00bc2cf7cc1e990a4188a4f0003d93227aaae6ee75ac3202f828f8255030ff8a25 -ac844b97083ea7c4cd4a9a4998698c85ee21fc8fa5fea6e57a0bfb5e4bcb592585529ba4e2a95309eca8e1d644e56eb8 -b44ac2e0e07f64916ee0334f57a9b1bf0599cf4b75e17cf0e83832cf375aabad761ed06e8fd887f8e479c80a033e9174 -a6fca2bb2075f9cf375632d20618b830268ad55ba5c7235b039cd1030a7a7291e68d78bc0d7b847de53ecd7de9aff204 -8407f91ae41c93e9a2f7a5fd5f7db8723522f55bf95ebc53281b08c592fa832a893da65b8319a46a8683d75a9a9f8103 -8d16b3202958f22d26488194bf93f861d0b87e3bb29f2e0d05ae3863634df19338bd38945f81b6dd0bdd2a10a5a5971e -94e3caee1c0fc176a3818a55f80e80fb1cab6fef21fad6c46dfb766a925749f9f4e3fa5c697c05d53efad50782059f9b -8076e3edfdb34f679ef0fe178b1b1f1cc855753d9e60ad005f000a9ddf34e314e7b16863a9b52a1c8c234368e1afbe93 -94e1bcbf57598bc3eb0c392dd1293be99d0dce2f4c929228f5f2000096e1f2f3217ab28c0812c7f5b27f477b1ad2bc42 -87b120c919d9cd0ee1965479a8b4e63deb5f3a63e6a7665485fafdc77bf4f7f8862687b18aaa985409897a545765bb09 -a4b57758925e89fa455d8e145ba5cc28d2a5779b0aaac06d789c9d7ed31e91f6992cb9fac2b41949e3897ed21ac85423 -b0f7bde0fcff1ed5db0952e90de209991a1df965a838259eceb1ac38c93bb8fe37fe8b5c0758fbd3822e32354b4d12f4 -b499c556930cca080076b49d83aa0068d23aa18a0f6c8c5e5cf575c33e9e6d53253d728fd60c90d39e01625e40549a9d -a4bc31a9b9e3530621183b3c0fd85b097999e7d278259cb1c71258d517b33ddd0a5f04e9ab70a854cc5b64308ebd08f2 -b5049a4787992f6a4b23d31ca07265d19f0e0dd1cfb814db01945eccd14eff717d9d7824089b3578c09e13d11e69bf19 -918051ff8e2635cd6a82f348463eb2bdfccfd83497d86418d59ad5843d3e5e6ee162682f67388de70f8096552c9bcf5d -b35d2b22f74fdec716a5256296047aba7ea84b56ba3de0b3d276e48b6a980cf7beb296daca7bd9666f9c69d41793401c -8da84fba90af2039006970d2f6f7d8f59e1bb4d714b3986951eda33c2b4c9154cdd7ce1861e3572da435a2b3307566fd -898e0017c6ec8d2794ba2891f27e84917482e8db68a4ce3b4383b7fa1518ca38995d8e4e5c53712632058e9c7bf2e2ca -a11853fe3ac63a7cd7c07876508cdb98ef6db35fe4b30a5e6a262a80d663ba5241c3e12d6b5cc904b6eaf9dbd3cb8f7b -97b14c124f78711080c6b960478832cd87652464b36c30688676c03291783dc48f22399aaedf1d221149f8da5e036033 -8b547b1a9aa8735d902a7d7c92990101f4bd7c67839f6baab60b27447743fb739b62bd57cbf6c082e008a2eeaca025a9 -95ea9ced78849aa2c5eff42ec9ce6dc2a66c943e7b5d84d57e4b2ff29cd3711cfc86e5469590c46c33028f7767dfc0ce -b6bdbd5f65ad8554632d89d367dec89acbdea3f58edccb8cad3cf5fd0bbe4c16639665b72bfdc7840a1e0fd254b8e482 -abfaf074f570631962a9ff24fcd844250e462d4eae858436c30fea63e59f7f3d36e038896d6cf3d5814c214709082c2f -b1b9d5f71d924470b94da6f0f9ca122c1035b06bb8e0ae446061a0a5b831a5d6014094cf1577bf18c9e9fe5968d043b7 -89e6855457dc0d9c5df64a85d44fc9c4470def8bbd8b8b8da609f3b9ff8c1bbd248831a8da6900895158153ac9679a92 -8a178ca8bea61e15e3342777be250e23d7f55ce098203a75bb8e9f494adddf28bc3f39cbdd415d3be2812653e7a6427f -8dccccd65fe3629a0e8d022b85259eab4ae0acb62b8d4513469960d5f035e46dbe47d2759a42b0f734636dfd4c7d0d57 -b4baeb5d03c45f2526201fc336d092f54b5d15288dd0be2b100ab09ca0e64a26f3da98a1e4b0a7c1218a65341dc8728a -b89fa0ddb60aaa0bd07cb2ffdf50b1b150791cfdbf9f8dfb0a8726c330736ae8c3efc0032032513e3fa3d19f8e337129 -934ba52ebbef233b103377837141729d5382e62055bd58bc466908ac7597e97ae3be5418393ccb73e40602862f738281 -ae08ce01c61fee7237727945423851b57d056b7af398828d22c5108eca4ca66d0852493c0d8cdfa9aaed0d94d0e9307b -ae793d07a722ec96ca96b95fe60499ab439b7af941a2ee3d8320570a27a226e42d80edb4d333704e82762ef7b97771a6 -889e34367f6bf78fa313ca8dd158a6aafc8c87ce12c72d804e3629d58bd26c4a78852d33544004c10637a45ed4f3be11 -af17544ed8d986d2ceb6600ca01c9f4cc46e974933cae13b6c2498c003f2b8a719a328332845bce498deef3b6fb31ee7 -8a8dff10b65e9b6941c368313398c1e83b0afc77e98dd5928367158aa288cbd970be7923a676ca190f55fe4cf50e901e -b70b32577846656e156b7043155c460f7afcde96d0ffe527eb114a11e4e403e86c0e2f1f93f8a3fd23ebccfa8fc3f749 -98538a16e4955721765f1182d20d9866096d5161d361774f22ff18f01663a1eb4adf76073959cf2c8d26387d4d555047 -aac37c44436b1f356ab11d85a74da9804fc541bc8efcbad92c285723fa67c25f5a3f00e857b100c297d4f6249dcb788a -a0fe9caa24c3b4a2324dbfeffaf1ff20dd58bc817b0298cfd45df1b724e7d6c6197e72ba3c7c5c8293005bdaf9524b0d -a4afe4c7863120653a4c5b86a6827e05f33b6069a02416ccc985eb155c8f719b2a455ade7cd0e2aeddbe22070fac59d6 -b5912a91226464c3887e77f9fc3d3b4ee648c693fdb43174d877f0dd23dba87b79c4fcb06986e85e169248e7aaa6eff3 -a47f4fe084cd3524befe88347df98ca67996866081a0779dd46ba5f7118ed02217d533ccefc330e1d7f61b26004ed828 -aae526538a297fd939d4a2e0e0d98125c1c41cfdde376a9adc23a93073cd4b5148e40140f0ca15f767e5b63791bc923c -b9f13b35604dfc07ed24895ab35ad68fbed971966926ca2149640d332b71489000f614db6cc1323be508364e6d66fbe3 -b0d1708df1b2b85493de242571f32086a1720192ccffd40431e6445b0b846c0dc3374d41a9eb15f127fe998d5eff15c3 -b38374d96539b82380073117d7de43dde45931aa2ef83b18fa8103b98d364869c8d71f08f325cf4839f75ad874f8e108 -af40b95922b72182751ac0f7b3587b5c8bb374347f03f55980861d2f0ae18251732712bece56ef4589e4473ff9cf43c3 -8a674ef81fbd4bedfc4ade661edea0350be4c2eb3b7c9a42964c9ebcf42f33b92351248c9adca894cc4bf8b77559b39c -8a4783f35ee15be0f025ccb668559066b946d65bd756fe90c7a1252b9a80dad8357aee6668c1f0444f47e7739b459a9b -a772693d76b6f4257890215c018511f9384c112097e51cdf44af40b47a02ebc88d83e93abc0977ba6a6c1afa901af088 -8d0919756ba58fca2747aebd729a817b7243cdc68ebb76137cb76734024e50e7544016f9483f2de15c4729d09b179ae2 -94b3a4d8188d2ce221734431af354ba133daf747cc75f59cb7baf819d50c45758eabee3aee178c9aea425028f938dcbf -a31198be2203ec2a2eae7ab96116606ad6d1c6fd3ee180246f222bc308ac7dcceb60fbe55481c6594fd432932b210aa6 -885071ebb57c819740bb28b6c004d41a2d415373c174a5b952761888130a4e387aed90a8fd149ab1bb677cb550134ae7 -a8c100deaab7b7dc042ae6fbb3643eb2d3b6bda5803b69904d22f031d6ccbbd36836eb6ed650822cb2c4cda3d9408f57 -ae9c2ef68353eba0cbb39bea6de0e3ae4423d1abbb8c44739e1f1676fab8c8a2b45ae1a223526e6e46469575d1cc4900 -8dd30843f14a20ef1d3ceca1c3292186d53c7062eba073f4c38a6eed505b2786fc83ffab0211b76a8e06ac79616588d0 -92f6593f4043e5a15a2dc28a5359b5f3b8e51e02d66236907b00a30847b1b52a968cad17da1e83cc8154557a2e12879f -b3c0daa751dcd9fdfdbd604ddc3a0767ce094c1226f325c8658b6d8d2af878bbc9551718ea96ecab3d7400ed553d963c -900d9d5581dba88569d271c909424b4c9b6ad0246c1b0197c1aed58d04be4c8cc84fbbdc43f0ba2e48442ac2772e6280 -85031027b897b6308bdc22c22637f6cbf4b1e10771ae62d530038025249ebd2f777cf55399ce483ad59f31b65270c319 -912933196c27a5a5d5a5c99284369cd8bc9dc6ef2331c2c0e07d77c096aab0e231ea7c569e581550ee79d1377280e4a0 -a9642d96638270ff5c2699f8a0e3fd68dba37ec7528e892fc423da2e45d145d116b9ddb8c8c0fa034e1d5c062127ac43 -b7072eae6cb69bad41246ce431a8871fdd2b2042d28e116bdc2d37c233f17f4a7f08e199b190e2708d3742c2bcaa3050 -822c2bea46dc6aef170728e3d090af0f5106652865e4b7538c8aeec23cbd24b6a19712e46a729d3a49dedf41e42b782d -b35bfe75f420d966822ee379f204c075f7ef97501f657a3b674dc639ac6fc70fdf70ceebc7953e5853fdcaa39b47666a -98c9dd539bd14dcf639812ad0ca1a410d2394077fcb9cac3de65da9df0217d635f319de4c7bdff161ec58ffdaae17599 -8913516fd792a83819dd6cf54ab6c5754cc48a1b280a0c1f4854db02a690de4ae11c4b3c7ea74f8d4cbe373ee24742c3 -b7c84396e9f09e225e28f3b5484223f75372d38610a5f9801e09d5a7f41da29f0cf8a0ec075ad82aca9049b610289307 -a3eff696057ea98e56250a4b97c8cdd9acf68e44a96429d405fc60857e417c9ecbf4256abaa282c0cde17c3262eaafa3 -967314e8888eb67be45271336bf0976c77fa43c6dab2bbf8d0520ca5f85d0fcadd411e3c75d239c76585d4c4d6074b77 -80d7881e09b7b2637410145a604a07508e8bc03731372790095a5f0619c99a04e5e60753609c9a8eb431db1162737990 -8d4915d0c384060db69a956b13dff66ed4b5e4807eab322682994cd13f6f04e7e821cf05e4e6ca8c95fa15f91c70364a -8aff910ad97099ece8b9df612794bb4a36953c8650ac70b97b1f0f4a57e5444fb9f830c4f794335c262afb0eeb88a68f -8d51cfa1739d7e2342c63c43e950d1d929e42a777859aa5f01b2da6d440c4f656535f65113bd5aecfda8ba91999c41fc -82f958a1e5a90d0372bda16a08a3b9dcf229d1da6943ca824781dd7d9d30e870510c027b8f6ed3a4cd09f19995ac5c5f -ae0bdbb5f00915163a17908eddceedace34a14d6448f03f5910e6525a81c2f052642cf022740073d3b7a9950c53d6623 -8edbb4a5dc20cb3098af25edacb904d1f8104be53bd8c4eaa5f914ad71f9a3db1eb372ceda55f14a0067f92e20ff736a -a342cc738143533f8f42982d517eba9d4a7a835def785a7fd1570cdfb5b36485e48d1ff425709a857a0cfe7f20f43a53 -90a5454dd703e8fbe88d28e7eb13807bfdbfd4bc9ec22b6658826018b244f17f58fcd8658614570b6e987447a569e7df -a0e5aa66ef2c1ff33da963432f5effba31c9193573f860ddd36228e4a29e3b465dd44cf5ced67ce0e93eb3189120187d -a19d00adf091a680e3dc91b9b7db02d3e027bf100acc28c08b931afac704d4117f5a9d37187e91b5258cca1040c51470 -88e5c4092929262568216ce66bec60adbaacabd367394fb43c8ff06b572ae7933536303323083837e54381d32ea3ce10 -8afa2df203defe6515f63a00ff80fc2264830aaea02cdbe34292d83f516d4af9e5945f43eb2e6d25445cb6a63037e6f4 -8114179272947f23fa4f6a5a4871561c03f3ed3f6ded5451c8a04ecd2deb987bf35773338c579090e54225d0718859e1 -aa9321f29a00330a5ef053126c84d9ebfb2130dd58617816edb3b8db91414872fd919357260bece160c74240cc2daae9 -8f75fa14ffc34b507113c3a0b8fa540a68ea9f39e900d11b75446038ea331fafdad76ac0dee3a453cce49ac826361187 -a4cebe77db731bc145e6b7023ea66b84b257725e38852e9e445a5214f7d0fc6e6d1129a696d0fc93f72718e904e686c7 -a016c639d479fa0cba5ffceb95635dd5ad22f793dd75e96fd98afe77a549dbef728920013f223c3985e5aa85e736d917 -ada22fa02e2aa41df77ac4f0b59efc6dfd7d23228d172587f8493ce5971d5c39840095a15add87fbb440145cde005286 -b08724f88274b73b3436b055c34a36fd62e4b853aaa28064054705f5eee192e863dd8882e500201b2a5ac0b3d265bf27 -af68227287a7016c3eb8379bd6cc689014c05f24b6a2fd80be48fe2cd295fea3adf597e983a4f2f8672eb536ca3eafde -8f9d34524ed5588359d8eb4701748684568d6a5a385606fc2765fc622697bcaabb26ed06a574c4dd994855ba31d6853c -91ff3dbc0ebc0209dec4a37cc9a4078cc3747ff380814e328a0e783d9a30a7add848011f64d706a962300c82d902d09e -84e4e93ea0822c09f7fd2ab20fdb0d9ee2212df51fb54f79c0c04e510165f6674f4e061a8293edbbe357e72d2a74d44b -a3ef6b1dcb6c81f3413a9606f64f71bcead3da1621cab8c4de702cff3ea8bc6968a966519311fb3b04f6898ffaa2b934 -85baed0c58533216eea5d8fb00ead2c3d7b7705621e3aa3273aa169dc48030fd17d4147d7ef012ad8c6e78742e2e6736 -83670e8adef8197743aab750dca036619b2332f605408a03e02cb5ea77676d53dee0ffbf55d9d1376a16d1380499902b -964ae3ed47a75becdf6642d92d814087f354a6fdf302237b3d4ed377fb0e2861da71fe3870d69ec2cc288447dfc92cbe -85e91aa028f1e3dcfb313bf270411db2fa781fdb47f6f7048641f33e6a7d6d4550ad9a55023fee330814799f6313694f -a65c1db81b36d3dde2827c25dc165fcc0acbd2888de3fffad30c7ced8cfe52b22e4206e16e81962d23f88da231d1f4f4 -b8cf40de6932ab573ae728f1370d25aa6704ff4ff9a30df7318254c8afdc43d015d55245feb4b8948fcac6dcc26987b5 -ad264d25fd1305d9e2d1f05ac38e04aa4b0081ed51282011b886ffc1077adb13f8a2962a24010243a3e387a3c3547bac -aceee86acadf975924ba28d3b39d2e5f36abcfe2e8ff7537df93a712f97274bbc081e35653d42c14ed9cde17f5866e23 -a7488f97a965156ecc45be6e65a17acff20404cf33c42b50b020b40e8487fb3c5adb23539d88425bdd8992e3608e6b9f -839edd6319ed8f0bd1a7dd16662f8cdf0e10edb20a2a3b25778c697406a0dbb0f6d4ee3deede368c69c12538180b5815 -a0160015f24a154d2ba89b51da15c7c6ba2b3b7fd5921b6361d7be19c8500dfffa7069cf1554b6ddc06f13d6454b0b76 -a0d616f8c67a8d34f5d78ac4c4cb82018e994dea1fb87bef4b958f7e00f98080849e210b20a0b3751d7e1edc2f90144d -ad2101804832725c535830c911d170d81ab5eb95b77a5a3e9647b55ff22714299195a79ca9ce0b9fcfef2ff235c40149 -a396e9fb081f58d7d87dfdacfd1aaa485b0cbffcdd73dc343f08722fd2b78a1d9886d69e3c2e46b337d0f2d113b266e3 -8a63c45dbe602e94eadcdcc480da8c19f3f3805c070d1288ce61ed42636553ddb788a2829640b95da796a31baf1610db -b81dffff1861bd705bff21841d25a7e6b928665b0240db599dd5acedea06d5baed4438c13567d2e317b0b2a7289a7182 -a433432a9e7527ea1fbe58462dab5a2caded53d73faaa94ad5a8fc9c6ba82371d2e76560037fc3ab71cfc3d6a892487c -909697ce08dd4a271dfdce06ebaf14434d14620a357507f1ebb684827b00aecaae087438aa12f0baf4ad50bd23f859a1 -8128edaf0df52d4f591daafdb224e489ffa48cfdd178f95e4d8249567ab33af5f43723880a9c2348e264e41b57852a57 -8f258d0d6688d7ce9a9c48a8d60723124299d83fa63a5293f470f4eb525f231518b2fd2eba019a85b54a85663d33696f -8ab4d3e7fab2dc269f17c1e7999333414a068ee6cb7b5cba89a3913fec37a534c2174e91cc2e3a32d37c1d5a68d080b5 -81f5e9b2caae23d80578cdd80a157b194c1e526dbd46cfaa492396a1c99212c37d3fbe31a6f10bb9d46aca43a0e8de40 -b0ce70a0ac711fbd8a4eb3c4b54255e270fb06b182854b8f43ff6396bd231f53a0871ea4eb50a0ec334383a24c1fadcc -a96b58cc5c0b0200064fbaff39e67671417a62a9f61b3879abc31e4ec7244ac76bddca1c71c1717754d5281da5c3dec7 -97545dbdb887352d72240ebcaa41f280db98b636f5669892562be259073fa44c91ed3cbe082846791ecc360f30f1ec1b -b0ee85fbe4a4719534c6b4773c2689097c0649a3656b2f9424ff26857a31528b7426c93342f70312599781b908a83a59 -a6c6f6ea6f9c5de477fade06571ccc12020e17cd663d5288ea7ba45cc2208dd05bd2bb5ec1b6c6249cf0b90b82190100 -97ff89ad97fc129be2766e0218221b0db246aa8c2f639b2f2ea76ef66c68f77cef4e3415b0228aa5b42aad241bc0617b -b2d806e6b614f3894cdb3fa247074d353843225991c4f719b3224393866c6e026c32e507825a7b8b1caf100bcc47356d -a348a178e1aa5d07be48e34232b516347f92e1eaa4351fedaad438e1f10231c9f757530c00dac590dd18a51ef48caf4d -9743734ff71182dae33e372ac979aada54453ccaabb4d3000636bf850b4a27bd1e45f415d472355594b7634c7b01951d -b1971874c6d1e2ba49743581e95be50e4eb46c1168901692edbc361c706002fc840d58709a43dc05fe00348598f3a1e7 -863f56b08c5c70f3c4bf734a1920671f030dca9d6c960a30e021071dabfd63832ec50ce2438acda20c91fb8561fa76d7 -80eb19d134bfdf4aac1a71c05ca3a465fd138a7eb573d7cfc7005c14fa6b7d3a7ff2db6a27dd34acb2017bcc87356200 -af6d6c0c96fe7f079b467d12e96b9ee673fb44b094f5f98ae456346d987a86f969bb75e67aafd6ac9b08acd120631db5 -8b8abc499cf059826318274ae43fa4d20d3890aa4d5a4345b4837812628a88e42ffb0bb03c74f0f9a8178e222368395b -a2569780b48343d1842da870be7d49f6362186479ed449a4e4a142f374eb962eb887e21a8c33100ac70281a5ea6710d1 -a91cb368416a31559e5e6fac21074efc194664081dae2766b5c1799356be760a88a6349d431935f50f7bcb5fbd7fcf2f -a71dd9ef0f35c5ef0e3f5d7b1228b7abf3c626b8f944d9bb3572297b73f5a468d1f7f61425b2ea30f59e3dfa06d432be -84f3d175ba62894daa9257cc1120eed5cd6a9a3eed9219dd5ffe0efad3e1b5db8e9aa4cc40f66390c6287ce71604639b -b1db0256b3d835246fa5a101b403b1955c9676cc0fc6a6c8a18d1b8264c5319ffd1475f9ac09a7ffd425b7c00079bd20 -97cad8e1e0e402a989036c10d1afe0bf3f37f6bc5b80ba9a76503ed73c37a711119de53661a24879a8140f046db0b10e -b2f1c8298ea24a9544c1b3a9aae5bf401aedb2be7ec18a4f838824db529ee42be375f150bb19839a574efb6101312d9a -9366386ef6259c0b03af3250f4b47214f426b8da47fc21f8649f4bf987d3181611fcd15d4f9aed355786e3e795a136ba -aeb85d2f5cdc6fd73cfbac9c05462895c15b76b440b9f70bd419d2cf13314327918582bb97ba488722defe1fc4f3f6f4 -939f3e6ff3fc4b725b738a5146c472b9b05bf25f4943a5a40bdbbe4dbc1e2c8fde6b23f591086797eb3fa645b9a51f4d -96cc6a8fb32262ba66f77e2a3503806a37dc845ac708cc0ebab5a117ddcbf1db639ce5b286965d32fe5528e935c16c3f -b9c29ab963a1fe07c91d31c69e96b33561a154b06ad2e200347bd4b45da8a92e88f2399bb16b709ad9bad79eb4526d64 -b371d0bd32750c6861ffc8508b56a6ec5da2089aab387b54865bfc995a1c26fce3e72487c1260814bebfcd0faac4965d -a512416ed09e0cf4b6ec2d26c32c24f9f466153610d9cdc2d9d589fc8998cdfe5fa78dfb64095b3aac731b97dcd91c99 -a065ef8f4ed7549d4d0da4b0d34467427ea2f75830e7eda916ea009589c936da326fc14e8650831baebc8e8fe4e30f1e -a6b5778203729b5b088eb3eb4221335c01e9bfb86e9b9c36b411a9a93527279fb9ee0bd38d8332d7d27f4dc5bde5c014 -8d861e128c2ed021944d0a1b3c2464cd09dd5fd0d3dbdd904451940a67500c1ac0eb5a9be0bc70abed64c9a0a834db3a -abaa203eb2e0a933c37b5afb4c87f2f13017ff45be2d31d6eedf1ddab06b0220f2855f19d0661d7f85f9f26e24b564b2 -87fbc271212889afe590a9beb89347a3eefbb6e26017fe86d84b5fd3853f122e0d337a0116ceb6a4638905138385f4a3 -938808e973a6659029bb687b59eaa43fbcae2a2e74bb016ee8d72d8613405d42ac70feca852de0f893d4bb4adc1863a3 -aa8218cbe96b0bdc34cbb8a2db83cbb89cbcedef8732dc7a0e96518d5b26944085a25175568df6e764761309f0307b5b -a72d58e059451683dbe879550df0414548a71ebb09afa92c611bff46255b3264c1a08f80b73f43295ff20f2cd985afba -8d31705592483aeb390c6dbbe954cfadba4b3c7bfdd41c96fe37cff15e5f05529c55c4c7931f19a8c5726a8a93d4b74e -830402323573567e4eebd3a45cb4d920bc4aae9ea8d6729aaeb98a92d408a24ff6398cc8b8f45f7260f409d5f168fddd -a2ae9b856cb0bd4e07a55f3e6cbec869d5301b3594ef788d0ee9bb16b2a51feeb4f0b2c0ebeb2d7567732af68a545c11 -a37f593131b6eeea297a8b4137d4d7d7f76104f6e389bf506b1d0dc5f3decd3ac47b641ee105d52fe93a482bd8969505 -a596432e4085e7465d033818f362c01ec0e0f1489beb44032e8e2a7b22c9eb75781a814d22910bc00f23c4945997e2fa -8317aa4eb78107316e5923ce628b0ded12736ec1a4b99a06911736e32194c14707be570811790a053278bcb58e4a640d -b42002173f15971db599190ba89c890ab06d0f1f812ae56054b4ced4037c71cd44d3b4a05e0b9da6140df6b3ffe37037 -900ae3558cfca95fb570140550b75560adaa3a8c6a2bba0fef52e6a0858f30fc8110e8be24b07b1677d8482e443d368d -a03d4c296e6b318b1be1929294803e95eab0ceca89d6edd7a3ac0eb599f63ff61512545d2f2e833fc4330ade64c6f367 -a370791b7037f9272847ed51674d7359f085dcf3be4f3e257cb58b33ffd61241b634092dba99778e5b7afd45d4169503 -ac158ca0e8e52e03a0ce1cd71aa6d5a1c523450f1946a7387723026e62537209a90523be7a3e0fdb0e56dc0f587c3a97 -a4e58e394382ae1f54c2ab3a26264d3b9eedb3b719ca9b67614f0c71ae6852e07c662f55dd89955b1513ec24c30d57f6 -96240c606e1373734cff4537cd35ea3b872e10db50e6c1844292e8f2dfc13011c02bd1fde7b3cadfe0b0365300879b01 -aca2f4b0b4cb842361db3fea6732c5abc7c86b35c8e17808821ffe46601bf837d4ad9bd4e2d63096728ef6abd197f660 -aa5db011966b34121f6e646ecff340037b8418e8fe8e5b3fbeb5d41768f131ad9094c894c570f5610e61d1a7fa0bbb22 -8ac096b615435701dc7f5909a750df7fce6d9c5e729f64f5f87cfb983382c908bd82084d07a86cdf159945015a619d4b -82a45567195020377eb7f6997ab38a50b3b0cfe015bdde35755e1f82b190a6d7658180b541e5b372f5fcf5013c223e91 -b4b380fd0166d4b149132d5e03c77348d3c24de2ab1d6ad58e290e0d1a64366acb631254c19d40f38acd6287adfa24d7 -93004a44b6d837b2ba30e6722806a6f9a135e1bd08e7002f1b1e00e3f167039e0f9a4caa657ff5338db1a3d42b7c51da -b34996beefac26556fda7e841c80a0c5b773b7058e1dce5d24a6f8a9ef676077725f8ae042cd43bd6316972fcc74284b -a2f361d240f71b79bdc9d6c2e4a91e9c0acd2e8c30c06b3361bbda2cdb2e8399435487716ab4b3347f03ee169bc292c7 -9840e4e8aa479b156871048c4efefaf9f76e4b74f563050ce27072b0355ef8d2ead55fae908b5f5907e66fd851501078 -b58988544eaf6432b60fe4962dd107baf1d7ab49c30d73f8fef9bb30ce97c2208bd60c6fa38be450ed2f33e6aac7a2d1 -a59fe4a4d54760e6e4ab783a9c06c589a5733ac7b2a91fe55f3b70f9c61c93e705b1381750e714ef21a6c62af8bf28de -8f9fd78d6827a073ec3689ee4868e98d4cb9fc11826950b858d6d97e9133cb24c1bc9cd19f80251301c5387b72bd498f -b769d64a58f3b33fc90df5596be30d34eab62dc82d371cc859b1c457fc2c394456eb78be1aec2f3c5168ba7dcf556519 -898a6dd63488a5b79a2cf5a814216860699907ac8c97aadc2c11f81694250b88628e88c24a34dac5d2247993615f8b71 -8763629cbfd47e64d1717999075a6098cff2fa31e21cfdab855cc22929d339516d289e1af042be47e7d9bc07022bbfd3 -95c023e3fb832014861419394da3b9752ad27198df056f56410bf1c2af3ec260d3f156bdf63868203f70aef6a4d69615 -a0c265ff406c8e52058353d33c0e6b51ffe352254d8162fff65dd71bbd6d408d4e9c07e9ffd4c6cc789a734f8aab73a7 -918403559dcd9d1d571bad020550d123b4c6771f02d64720be3e7890946cec25e5537b62d905ebae3fb51c70033c1cf4 -a5590edceddcfa32f0b83ec20923c5fc29bb8351741fadbf0e2b33e0cdbd7164fcc457b1582f924a58b0cd14b2625a4f -91a3d228f5449c6179c7b5cc7fae5a84cf5f9e633cbc7bd67cca33fd9358e7119a9d6d497622d0a8ba1978906cc570a9 -a896ccd7d373ff4eca5915e957b9fcb9f1f81b86a3b815466dbd684931a0fb7dcf77a335ca1605e6b3f40f8dc6133048 -aa4eeecda69ae4b8dfa4577d576f9c8504598b2554b918b6607040d3e2551bfa3acb513544e910a563bcb3eed0f6bdf1 -b5fd9607e0a18daf2a6cf189df03ccbdf380609d4ac93e7bd6a41b68737dbdd1da22c0855f0f2b86763307baef3620b3 -a881f02800149e2d0722510e8bf649e20cd95b848a6bac7c51424404f65e9dab08a76dd171d60459ad8a19766120db41 -8ba340aad01fa1db841eab78ccceb0a307a9075e73fbb942e3a3105d56cbd5f397882e58754312d3d5d677134b22b11a -acd41901b371e3d6e5be2ea974f5c28a85b2745dab4a45bbe1a1fd5b257a1249c266a27a8d72613d93a27a305318d86a -81a335cd393d400fc048e9776237783f330594393eae51003abbe6088e310897b2a2cef8ab41d53b9d1f035a2822b587 -93d3023e4901b3a7afbc80a5df6bb68037eede3a24da9526a5dff7a0343376f9ce37a791836d5aedebabba1e168f2b92 -afc6eab7d3be7f840f84cd377ce3e727232cb7e84f09b5b5c958da7f58f85dbfbf53fb86df0c63b49faea485484b2f29 -afbc391cd89945d65f8fbb9fae653d7eaa34922af6e50febc4b9f4c1dae93aaeab58f3fb7b24771c05cd86920f313f12 -803ca45299970982d5e8ae7667f90b5ec942b8537bbf947c4693411c2be55e9a013e8d304110739f00a3ceb66b382293 -94bbdd9d1d137d37fad717977445c2b47cdab7545827faef98767c6c8a3981e6e265f743f6211e69acc2daa02bd54def -b8437af291342dac15736f6316e1a416619c948706f43a35a2246f447de2231b1aad10a6b201548f3b3af5d2b69251e7 -a54d969fec830635497d3e5796d9240d1cae0fb0c4cc64499836a8699be55721a2b14312b307ea82de6683f049b5aa3d -b05e974e8b46cdbf532df990eb2d5b63a7706fb9bed3e36937675330289cbff5151a227c8602ce6dcb3dc2c1e066e4f6 -b5db56d1aff8e5edc041ee7dcd5f38ff5c40069c1c2ff4319d9df24bfcd0013161cf3cfc1c768128fa75ff3627f44eaa -b222d049daaa343c282f65294122689fd672d67ec589016acbf13d21cb996bf6be0ce02915b373c1b8a7e5ff84d57410 -83dbffc0fbb585179c4a7c3986b67e7fd6eec0db319e9f3f41b22110bed89d89e30349363135e9c45e99fe326a6db175 -ae9b64c78e620d89ccedfb152f67c373e23df79650c334325f1c9d465cdeee6b9a7d181e409289b86c3dd863eaa01b2b -a244db98b50b6ae80725964ce432b8f117004a1cc50cc7af5cd8d03d4f53095d6ed5515e63dc2a53d9b5c0bdcf0c6f06 -b7b62e68e502bcbd66b4bd40c8cbf96b7e97b4388169b72e0da7c162d89130e244a0b22e74873a73176d182f4401074a -a984c5a1960b4bd4fa6d215f9d7a10154d95596b4a919841fad48b5de0a8921aeb7140326240b3a61b6d82a02915ed9e -8ef36c5e37422c43616ce746983a4052018ef98af3370c629b2c7d6a01c2826a99a1f44bc6a8edceb5eed1770e4b2a96 -87ae3161cf5453e3d4e51fb335b3e576a6ae7e5a681641268e4ea1dcca24757a311b31f2381cc55b58320e4c56854237 -aef4349a3e2bd6e9248dfb1b2020833a81f7b29a615a928c3629f5a4e6e47fa2aa502756798b90799b3d12cdebc40c5f -8e8aa1c55aaaa5437e92681968208f2f0c809982811fe0e7a6a7457c5cb453a2678b3b74e898ddcb0c77689b3cb3faae -838bdd057cf0f8535a73bf5309c4c2e9a2239b44aca7b7fd00eda5a485ddc8078709e64f5445b27baa0f9e7a67f01875 -8fccc1ddbc0735a9b64fe55934301adc6abe9d3558555861b5984ebced26c69e477672db0ca32e0c6addbdc106735b7f -b3a19ff36301280020886757f811fc507bc994a9031544c17ec672fab9e85e179572345c6b39e8aea2c180371d198b44 -96859072913f540253b25b4355c23c2fddcec3b3282abe5f3d02e0a759cfeab4120e0dde4e5c734a26bd4efa91e90ad1 -8dbd8e8ef11d529a346da1da3395accdc57937721935b69e45efe632fc7fca5ce1e03113a5dbaf7a1794067154eabd03 -b4a5782b4db5b5f2d1fd431472ea60ca8d1ede74f87fb0d247b7ea312ca316c0cbc8389b3cc2b0ca6f0a80d0f39f4f56 -99923e21d180d6f17b9f10b4d8875b0197031ac75457c1296839498e8fb3c787d12da2c78f4502bb2f9f6d251a2a5ba0 -810058558422ad6f0ad8dc189f623d167734215b88d1e092bd2e49d8d2d4fed870f6b7695345798abff7e1acd87e25a1 -b665fd7132875c917a0fa7bc8179764f3df02b8d2a7df539ada02d4ff8e75377f3db4a3435055b6e0d660deecde1ab08 -b02e3abb9175ebdad4f1ed140695612b67e8634d58dc8f8c3e87ef7c96a741e7c8d1c1136a1b2574fd91a77afee77ed8 -ae2d87c2ad90ea25aeeb850cd98ffc1c5e8c2b9a16377f1e2198fbc510193a23d53848b39ecf64dd46a6cd435011ccd6 -8e6216bd7ea092137f8ca97fa126c92e8d5b660b92bd47ed1166ed7a01babcba7db11f77c15914b81fec9ba3a92e8c97 -8aa232629118b0b945699e402f4e56e65eac6f2ecc4f7547d3537e2e83e36a8a57b3c55080d22d2a5e3a1433b67e5530 -854f384c7ff7323b7bc78400f0f23fad2ccfdbc583f173f7250099335d209bf95fb88c106f24d094c59025158b41141e -8420368b4221d0fdcc1b855728446055d636c0e7ab2c41ed72c4ed44171cec300bc9d07c42d6b00dc2933f18933964a6 -8f917e6ac546cb79a13a25edb71de01afc8c6ef6339c0ed2bd99c45ad2ead42207ae5298d25921c55649e42643242429 -b841a412f2198d6a55ec27b8fbf5a7b63f6aaf66d18afb8a2edb93e4d1c03505a785739a0fcfeced96e30af988a6ad9d -a39d2f86ea3df6c0a71e61803f6a1611b4a126f1f2ec986948c34771429a90399c1c9f6495e8c97acbc0c1df56ee2242 -a0289d0c001e9dd9d324e856ffaed6412fabf056a093ee2bccb7ecab7ad8bb4d0468a717f119c889a5fd0a0ae4079e77 -98063963c1fa5ef09bb3947040b1ebbf2fa47847c3e306f11aaeaf77e13cb7d4c6892e166ff20a88d4378875710d4d48 -8b1443a196869252784c26ed092841222af89c4d36f6517e33df0169137d4b0e0b27e5fb3ccf16fdb0d4c77f77e5ec44 -b37cfb13bcef2b83014be5e895205260dbc328bfa1e0d5661c89f017fe84757d95379d9015eb65fada510d8b766941a4 -b51a9e91a25a24b7e4f61de78e54c3313f0ca5f2b62b1625cdedb784bcbaf383d2ac38a8e0d2828d8431183a8b476b2a -8e120c604ddec61675cf699ba9a59d435f8392588ec9ead4253734b489c0d3b065804579c3e3ef36e502cb0db834c352 -89a87bad33d3147e610dad3c0bb9eed97d46c062d3a62574eb0cde05cead09e4cf943b171303e0de7521677b299474a1 -a125a6c741156e635a9bb84226de5fd128e43b67a3250b69a760f8c05a2fa08c14bab843a08a72496480527c14683197 -8c32ef72c985d6d0b6aca2d18f6588e910a1f6b6d69c707bdac51d6a7c796108ca8cdad3695d9640c8560d1f9ce9c571 -b95ef06fe08e01d86af5003dbf5e2d3f633d3421d5531c4a6c769da958163bcfb4d2940615fb37e9474b047b7d541a03 -91a4934bebab72f7090cc3dd94fd6f9114b0f17bb8149f218e18680cc22887bd22adf3d6acb983fe03b87bb68dbd53ab -81b450896aca89332a0bb3365314d29aa228bc39e8ed3288a58b6a7468db3915ea5e2be0ae8332863bd5a97c062b7be4 -8de03113af62b9fc128aae45fc29bd49f8137742be455814cb0351f43cf316df313ce33d6963ddab9d5511316201434a -8c431605c0e09a583125d6be08b3475d9cef5d78e83ed5d8d74f6957c474412deb2bf18957b41b447538a147a75d96ef -b698b1033b4b7677a6404c1f91d6d71afe48e85ccdcfcae75c92ea119bc7e166a92fe0a89dc4df83d8d73a10b285e980 -aaabad329717f3a0899098e750f4272acfbaef68db41e3af3ee3ebb24021233660cfede0c0f4308b0059d0a222bb6b41 -b88107f155f1e996ed859b7dd9571e784f62ffd4f93e420fde4df5128222a2ee995ab634089904aabcf9bb9e1e1759ba -a094e712a8671963d54fdc10c97c3f2c3dba58f58c8a375a174242293ed7ba50069000d8871d3fc08527e20ee46976f5 -927030dfdfe56634aa8003811ec409ab1edf7436d01bcaaad7d17bc7de55bca29ceaca4a556bd20ba9aa8089efb846ed -94d43222a32cb90424d81a31e61ef3b0ee624efecca23a64d68ef79238d36e8e3942d96dbb70cc9efaad313fcb79c6ba -aa225dd0b39ace4be104a0f2fb73973eaae7de46992e529ad7476e7415924fb936ade4b9f5a341bc9542380bf48332ef -876a08d3201ce8753e03d11ffdd6128f9b7503689f82ecaf7cf49096f0cf49f1c4020976c77eceb5037041daf1a88533 -a3db02726d73d8c2d85d9e5a740548885098151b85b4ad566b1168db4c008fefe39c8c19c47ab8e2e98d29cf2e0ca6db -938e606ab19e3cb6c4356326c80a06477b639e4c999a0c8a2af339d45029e73273416bd681bff963d58eb0d51f6de2ad -97151d15179031d52346f0ce34a20bc25fbf4bce2f22ffba3ba3afb94d546d9104c3abbe5a9dad056b73dbb92196a552 -aad246d39111771450cf05e0dcecd3c157d708f48b12c3939541ac67159dfe5526542b0fc47ceab2348014b6463462ab -95dc539b8402b15501407cf6bbaf7980a1d5e5b3d1956f3207b41a88205657e2d68f79678740e8882ef42027a291cad1 -a15a0e7d2196e546ebb0814cd655334c5cb31ecd63b5cdf3e25e57f4a349424cc9b18d4bebdb4b6ce3dd5bda40afaf99 -a2516e8bc63c912fc2e1b5120de4eeb8881ff79e3e76069871a97850efdccd98ccc33700a4f45f4df5fb1b7ab48708bc -8b3d59585cb65e7cc14d2305a339855bce49197490fe011d6c3d7e53d08261c9cdd500956872ac795feb7a8069db5589 -a2b38ba575e4035b6667f42365895cf623ad0deb8f9034d1a5152a0a0f92bc82a088aa6df531de59d2896f17ba107542 -b40407709905d2bf57072f48d97bf616e40761cfe063a4cf46083ffbcb5bb7b4f03365dd5ae3154c1b03e45c41eb0188 -8616fa00c0157abc75b34106fbab547890bacd79f2f6c3dd0cc57d1778234e98a6cde96876b40d2b1b5f41abfa1828e8 -8f4166998dc11be96d00067284b17c5fd5955612bfa778e27136e59e2f50e617d1350f5f71ee1e4fc1267d1312a67482 -b1cc89014ff795080e2eef431f3ecfd4996c91221ed9b2162a9ddf6bbf080d676d00445ef0ff8ad638a5fddf089bd760 -b449e34036924ff051b5632c65bd17e86063c684825df23792a11fc86cee34c04b7f4df1e7c03e626310e7fcbd1f93da -b9c43a3ba4b3be883879f6edd1c5d7042152aa41350e588339093423d4efb4e3bea017269439809498ac87f2794edefb -a7af51fd781c16cc82669c814327bc9b27f730b21c774aead773832b39721d3589a5d16acc302875e706bfac404c3ea7 -981af4e16aed2074d7efa032826e6e795d41a3814b59ce2b08011e26b72332d5259f50c796e1bb6a9d00e3cb74cafb85 -8bb3b5d865cca60631534122b2af336f85b422d802e237b68ff32954856be165d4aca1e9524e15001e20773d93dd6b4b -8e3507b98cdc1f764222a9a3a2b1f1c5629134b9927813b63f541660894d12ba6c7125cedbe2df65506ce5613735af83 -8455432e4e96d5c66f4511d7a8f9354bbea9cedd5e841bc6ec59c8366941ac9653b54fc1e8f0054c1bee8a845f8a6a2b -91c392d9edb2005daf49189446ed05a06da86f5a8f98019afd0e7265ef56e21917cc5dad39a2974f538b465008bf1c8a -b04e185eedacb0058fa60261d0c6eda38799b57e26af75865ff986537bbd71af40279fd3ddbed5784e9c8516c46750f6 -b8d711015205854b9c9e132168920da8d305d832f8605b624d6928584b6b129b479825632beaa14aee0470265030ae50 -ab46f74d8cd5eb76b9692e9dc17d766fb9cdb1d4b5150ca2a12104e571eef22589adf6cb8f36bdcbc197c34e0fcc1669 -a64868b7d4b989dfc4b203fa11452c1508dc2c5c3ab70b05553053177a4bd6911f514f654c8538032ed5f27eae289328 -a06eb8f5cecdb2f22c51ae4d116b24b2ba3d1ae5ca78d9b6e68c1236771638a14c6f658451a82e0308ba18c944008b2b -a062c1078055b84e7d6667ae319ee53d5775780b53ac6d0e14935726969bae506d4cac567d61c85c8fc7ee49fd15ea0e -af25d65ac72963d2cd704315b2a2644a28c9babd8556b336ec92c2b3858a68a6d9287a169aae0beb3c1b3dd823457dff -a299af91ca6a99d4b18589977a187c60f77a3969a02b198aeffa37e2c31d97da221ed2c118312c7fa4a59896d3f4355f -ac3a2bc16a57e9c31287ae506eda9a33da5f6d2d332c3c11e76348b4a88d6ecd8180c23c46b5bd2f3b6131ffdd9a89e8 -9513ab2308945d5663dd78b7947cd7b1af4069aa8ee91e78ffbc59761bf5addd9d175527ad071613b7309727db6ee230 -a6caa49518386cf727a4807441142f0d4cfbe1b5af65b1a481db3a8567ffca87592989c8524e6fc9bb17d152fee1ba98 -aeb5732d108aae10e7001e3975572a7011b3dfed7896bac60ca20fdcb6987ebe28029b4cb88c0c0e089b51a9958a8077 -aa8bdc59089a268ceeba2f1ae72d417721ba7db13831f3f8459f5bfedcb13cd4215db8e95ad6bbbdaf6dfeb22957ba93 -871b8fbe47c39f588b39a83be5bb638ca40d8b67f28c86b736198063116bb21ae7307d074c8bee09af5bf8cdc715099f -a0a63df7079f4c8b1ab6f03f6aa2dccb66814ad0dd8aeb9bbceff49f8d7f128aaadff1ba9423789609145b0d8c30ee0c -a37cb4b8a4ac21b98e96c2e6fcff89b858375ed343b84fcc84686bdd34325a94f694ac778b04b2d1e47d8823c50c62de -b66b6b21fe5b8c2770eab015b9fa68755f9ecf191b71601abfa93b086a39c2519d2699b27b972ee387b189217b4aa20f -803b6fe1e211e81ed598bb6bb71708c232c4ce30819176d1f0871865d2bc2ecdd910a67aade9b90dd43c4b093f7d3539 -94e82e2b330709ef5a227130d8303b9d8dec46ce62c7bb98cfb32f6237532ffc779388651cf9225b15fa9d7ae0d0cc1d -ab6c97a5cefef3b9cf3c24dea3606e2a6a779781d8844c01ddb84bfa170dfc17b9a1e8d3d9a94b785a45d869be6f6be9 -b44c2a73ef924d9026b9671ce54eaa18ed04a31d4e208cb72e781c6c6ca33bf3d0719d9783eb98e185854a3c1845b646 -a1102427966a4c31d79eee110307913c1474abcec8792dac7beaf00c7d1b8b9a9c4a1b6839c59a4662c17aa74a9ff978 -8103081fb9da8266acc1389a192819788b617482b5bad78a4ceecd9d61eb7d6d422b9fb96a7701650135cf53b7b02edd -aa70eec19373a104684f75a2f0ab9e04a11758e7d8d084ae7c581d24eb8de4e730ce602233e39e6985dbac46b5b31d7c -83ad5dd2b8f2d40a40747fecbb43f3acebafc401b9152c1fd4d6dca191feac67e772a3255af530d6c077166f87095129 -9612d53e783404194122b28814c30692848a8df340e8861219a7ba3a68d48135ff3a17f16745c4072edcb398100932f3 -859b45780538ee93ce7190bf44fed0ba3ac9404126825b5df7205f751734338f2dbf67ce77ad44f8cad2feb3198a29ce -b4d08630a1824e38ff9d2c7945224dbfd06846724631706a44e0308128f8b32f848094fcbe0d666ed0b68b8877e9768d -b7024a8522e7b1304e664ff4d994078d6b27409503badfd93b6d46688ee87892498aacb9dd7344686eb7ecadbc008135 -97fd9728c81d6c1b397627f9f2b9c2d325e8d322a2548b5145a120a2f982721d108e67744dbf7480d69f5361f38f1094 -847962abccdc4058882a6191c367bf6b1740008bb0bda738eed9e86e3d4f8c0b9a7802282b098ec89ead52946dfb6c91 -95f269e85cbc2eb22c964d25853dcce972f4cab07e17dbcf5c378166e7f4e59301b45091ae5db025aee2f7ee98a11440 -ae32874ade98cc4735f496d8983bdc40a5afed1925b5d5075c3d762653c8412c6f350b937021edcfa7fd36fcf9ce3807 -948baa72a58c7356278535883fb8d8cd53a302601f24a517fa2bced64f013064b3df50812e3ef1520a89e0a2c5b6216b -b2b366f316eb4e01f42cedc02b55588ee588248f8a76399f4576cdab3b0e7693c283100f214f36f13840dc552b30a1c8 -82143b825c11793a3352a710ad98fb233ba5ba5fd7f747563261cb7210da1f0b8b5820e5f2a32f805eb71bc60ca4a802 -a00c9ae49dd513e76bf683c9a08d144243593ab3331ad9d15bfd2046eb0fd9b1b030d3ee1c7596c02124f6ea8838f5fa -b63e46e0f04719f11b96ed24fc78b1436c2db43b609a143a396c17c1afea68c503a06d040c1bcb5bd658d2017fa4cef8 -80ed42fd52c5147ff899b4f6e0006677332408ec6206c9823286af51aa21e4712f1053621d1db012f9ebda7d087ec05d -b2ea32bd02856d8f16a500cf516744571a326be577a008610aaeefded4e66848ec3ebd3c28d677d49da7055dd9dac3d1 -8e101f8901aff8b93a55827396f40ac816c3bd941e0c4a16a6a524c10657b99166010a6db72e4810583abcd61124039e -a025ee88b7506bf580e3a088d6e6ba9d987811671d82a8a713149d8766cd9ba6876cef464af3799d117db61a69121578 -823274ffba3fa98e6da63378c8b8a7f126e6bf398ee58c3dcfda9257dedfaefa64222b4e30ba56a344a1312f59be0b17 -b60341190dc697e7eee593b8dff04dd5450c86fc7b59ab4c95047adeb66f550373fcd3d0a7e92555ffbfb1467fc813e0 -b0a873540769defedab58adfb094442fc20e065ad29d49303e7a2e755724d798d6dcefe226a66ccf9211f26075618cab -a4bf3b4eeda02d170628acb15495967635897cc58e6805fb516d95b339fc72e01bc8c3b74c62b22bbb65c488f3c9a315 -a4fa6be0ebac0bf5327e87d63973ebf44d34763773eb623dd40a9ab09a8db4b49f6bf4acd9450bbc4a790ee8b4347d48 -93657b37b155ecf3282e68ef8f62999896b39d8cad4a0560a24ebf70f68008ede12b68dd7b70cd3f7104e51b903221c8 -93c33362bdb8398f332a52aaa3394682505996a8a0c76e22c0389be56915522c58da4d1583af137b417021d26dc3d84f -ab338b0baa7ae9a75971b6750cb72457c1e918dba3fd449a576e1b0a9dfdd19356c232aa8f737b212c21831371223fdb -97043c53b0f54ac81afe3c67fd4941dbba0769b9bed718171492afc07317271a4c36b591cd18f057a50e4c7527320109 -82c54f2950647b52c649ec7f25dcccfd71484c406a53a94dd4e9e63758ee2e559fdef8a4560ae2ef41b08b174a131761 -b35b2adfe6fc1be668745067f485dba3494f547d2603ff28b06fc241d48225a11c85891f144609337d2ebc0713f6696d -a837aadc06ec942edab4116efc246540ac5db1bdd8981963a7462a2bc3f9397c4c634fc8c8789114cc1018fe8beb0585 -8fe5b4a7c8bb42b5ce8c401f7eeff20c034d83ef10d6e1541fdc135d389545d731258f42ec5e0d30512eee4aab053b7a -81a42ec920b00761093bc856cd630e117c9ddbd7dd20584990d91e63f972073d9588cd948141fb9d6e9c7b61174ef4fb -9805345e5ae2a2bb90bb9d058f01a2a7db6fa574fbed6ade4160ed9dd54d08257b1284cc4b80573a8f620aeafff014d6 -96d085def67e05ff835d1ffa00862b5f2380119ed272510da798492f9d5321e1cb5fab1df3202663b6b751d42138ca8d -82390dde45bdf7f1595025f1c272daa8735c2af90f55da415c7624513982067ee77b54cb46936e1b583556db1c260e15 -8b793c439afaffef75d891d630c2c3bf2af67344ee02bbd3a3f80d02898a7b54c1f0e0527713422ef3270a1b7a32de9e -8842e5a3ef7877a42ea39e2b614f7228fd77442cb125d14ef9ccb6fcb5ce100e7abb3cd34f009d741beac6015886ed4e -b8a00fca614badec4996098428c60620b8ac7c41e3a60d33d9fb5efac101d28d5f38601c1d2cade8a8762f12e5c7f293 -985262af141e2b58c4c6ad685e9b7cb0b85195d183d7db0d7449e42a5ec64e7f2a078b49190ccce4b9c9648b9a999cbe -87e4ad488400ac73a47cdd477457b67b2d97f812917cadda9cfb37d9b03885da94d20eccb58a61c772916c0b5591e71a -98795f653a08ea25248544bcb113a16f13c36376831076f9b153ad6deccf07683a3db69968065ce672414aed53539852 -89cbcfab11dbdfe1699c2fde2ed918599e862771b7b866fecf903bda117a6c70ba23e4edcff84535f0177e7cc070a37c -ada23420b0e5be2706e4446208589a2647e59d1f3b072448f7e4b04812add50dced41c7e41fc1a97c60d04c7144e5324 -a962d643ed5968de32bd6729c56ffc6a6f237221ee9952b28b3723179f6308d053fb484d199fbe6793a9e6fa16187cae -a2ed7d506f146158d1be02e9a37b85a4462666d9332f45d0eba95e87810f0b47bd219aed4e3bda0e456e3784847e8ff4 -8b003cadcc9e7519bbfff1116206d13ae9e9ee258a7780fa35749e5fdc9485e934bd7559438653d62031afec801c8bb1 -8676eeeb2dc70760196b1313bf6a75aa71cc692a64c1d6fd6f6922e26d4520bd302f17ab954bd4016298e2bcaf91316e -af45ef2ffc35a5f8dae6abdb373f8958ff975c9f7a2f74ba1545c2f5c8abb3ef2a997818f8fffa0be760016d3aa19cc2 -a5260b2c97ca579d72c13daa826cad8a9da4d5902443d29e60ed67203e21a7fddf83344dd94730e8f155aeb65df4e480 -a19267cff056a022cc8d0af55d41e78dd9152069affe22e9fe9d9dfc848aca4aac4909103b35300b358098c36456007b -909eec06302c81ad6bfd3b96daf577456d28cad59bacf933fb0139cc6aceade01a686015d2cda20d25c778b9d00d5355 -87391a5bbb409e0fd6427b6dc805b69120181e34f53c73c0ae11e0521e97e036d5b736250f95c8ecba37b7ee27ea20a4 -b821e81e4f887d5780765fba9c79599b3fd74840d7c2578e03ab8859cabc982f4fcf9987e757a150aa81a000ca3442e6 -96470df0be386e1bdbbc94897386f22da7a80df9724927363142b074beab1bc16caddfcb731787b18b230becfa7ab0de -b7d1e2de7254a18acffdf6c2cb50bb23be3030269a230b1237a0bdef1656875cbafd8736b6ef07322c20b8002e9d8d5c -84e795c3d85b5f526766a32362c6f7f2fcddc99e89734c99929dfbf020d04f285a4f44f2d0a4a03b519375db43fb9f89 -95bf0f2965d9b29592c2168c79957db4779c9ed8da7ce11da7eb8d11c0fe165f8c37a38baa398af78b8a963f674282b5 -a6253e4f2090efdb5c26c0d50fa5fd2333e8f245b68ade9d6fcc6357ae2c6fde5cd0d1c6e5fefaf102ac8ef4122ae238 -b2b8692016f5fa5dfc720d382f0fc05f37c5726087198f5f6fcd6dc8105bcebf98ff819870e2b944c23d6d4ca8e7e62e -af86a8f6ae1838ebdc29e2d949a1028aebf8f5dc7d2e907396db3d112d236035679fb2e0fbb1a49453ef120cb75bda88 -8da2742e7215e490e38a0cdd851e95ecec258bcbc0f5b49e9846397e3062dbdda8b5decbe22c7615a851928326b26ad6 -8d266bc0dfd6e35dd975fbcf3eac55103863fa3f62c29f12c6f825961670138aacc1c89829c88a8e1d3caa44c62b5891 -a40bde477fd236c36981b8bdc3191d70f01fedeb99a21a525ba8512eaa614290feb98cfe9351fe39c27d12020ef46100 -b3856656a88647aca31dda0260a6f7308f7cbf7dc93a0fcfd81a683cee5a008cfeb044d0688022da5f8fe52e7712c742 -8dea06d82705d27403bc89cce3cf99125709d6baf92aca6f40931cbf4ef1346feafc6f21207b897416ff9a2042ccf127 -85852dbafe41d671cc0c5014a6a666b933c95f831b4edb181b7460e6780ee430540230c2706ee6e1fd669bc9369c4421 -83271d68b89db416fef7ab75c64883732be779cdb7898eaf7f84f9756b006183c454ab99a1270661b93347cb25d5ec59 -8d2ab5e538c44cc5a2427e367d3d2535964a95185f0cba457377b53b9079f806df0a74c475543a80d4397bc60ee36877 -a966f71621491a0db22379473021d8157c3173d9ae7f331e076bb51b6d5f05b76d04656e702c78efadf71dd24e844692 -822f5d8b0f4f19f98b52234228a3a4d599c5391df1a019e5c3e69ef5fd39a49c396396488045408ca3f83475f5a94cf2 -8cab4eb002432c0044e0f1da2c8313516dc57913df7e7be4514e9283e759bf3e0fc67392cc09353d8d09d49a42b5557b -84db5c6efecc833af8f4748f1c976f409faecec916fbcad97a4424f0f018bdd837e4411285ee912c217ce4f8b3494eb8 -993128e2d935a83ecd7ad5a223fe53c7915f8b258ceb680df88a682f3abb87edc922a4f2f2f16905c3f493ed91e1ec69 -86db3da05f3bf2f21aa3d6df245f35023eee4fe1df6f83c35ed060b17b51b5d88db0597a65ec6fe78f2f0e429362eaae -a8b511e358d9b7f1211c9e54038540871864cdb5af32f7dfa53b9c042a8443b73927c9d42f88c3e19574e575feee0a77 -a3c8cc9ccb1bf0c3f38b147b4c060ef3c25e44524392ce244bba1ce3fa90d2b97f9ae61d95b5fba2428e5ff85a7a2f50 -b2fb21f203e07478b7ab94bbb22d1449567e52e3d41327d2a6d140a70a730eeb22b617e22882578bc228d082205aa5e9 -b22f61e7ed6823abbae7f7afac5ccb4a0265ac5e44ba0e362512917bb99a19c29ef93676af86279ff0b1c1e21b767970 -b2b212cdb1eb680d863c592f9d18e907677acf0bfe0b1cc824ac67cc0f9e8fac383bfcef1b7553e654675388509a7fc3 -a5ebe9c66cdbf144dd97470199108e50110d24cf1827df6d3ec4c15ebedbd4c588094a66db761980a5ae1de0bcfd0153 -8175a28a961b033467fc010aea4d6401c322c17b8e50d682428365b34f1edf87e80b9d4e83e14351dcb58fdc16d4785b -8dda8c206dc3daed2100208494a2f74d5fba3f0d4157ce8260d09fc43eabead01ffead91898af37d6330fb1d6492a3f5 -8c97f0469be2c1e804620840f2fb9add5e169f3d9a515054c4c257a633f71a2e2ec28b64167fec1b25092d359db7919c -98d7e6bce9423142d1a75898a5072a89fa2ac1cea71e2ccc52421e84d6bfe46e2a827e053a8ff1956ed87e554cff5ea7 -b37a7bb826efb2c71ee980127dc95c16461efa9da85a1af5c1f07a05cbc923b571f31812513e42798db148534302c2a4 -b23e5692e57914cdbbd48a40d09193e8de74168d29e44eafcf93acbeca3f4d38946597d23d0f203484b6ccf26fe0022b -a75e05a667d03207bbc23699af1e5bfec382654417a67cb2ab43b7827ee6270240033624dffcf522e77f879b24c8c51b -9082f568c7dd35651afb5b3a4a7fca8aca001168337e0a372daffea34693d73d582f1d39b860276504bade7088aba905 -a384f338360900a0c9676d75b4ee56b1a52f615a12cbec40ab9653132668fc464807d38069f34fbadde6fc44b9b17858 -99630818df6d307a9bec472a8bbfd59ef0a718aa6d6e1a0a9c1cce94691bcbc5124522edc0187f2aabce454840d3ca05 -883b09861a544f8b36a69aee91605df08ff83810d5a01ef14989e9c6d9983929f3b539f67887431729a3db5ecd8e1ffa -b31f237af63f7bcbdeae18a43d2c640e8dd33c31e404225e10af733724b9a80f21ce9958528a30cf8fcb0fedf5921056 -8a120f0bf0c1e8dccf5092f8a3413fd81b30dc728dbe0f67768d2152b16ec286579c9fe0614bc7139d5c8f85d4542517 -b8400f4d89d747aae0e8fde37dca6915ecfa64c34504351ba34fcfd91886fd670944de3d5169bcdd95e7271ff67f2a06 -ae3658b2af425966770203237b34fa49d429898d82ecdaf685e2f82aaf3370efcfce31b5504c9109f048c416d4239b37 -ae3c26c8c9efaa1dcf33f5a2d9196a8e8efebcc7cc1f77d792be45e27c0f8dd7280474f4c87be9d0d898587eba6b5074 -8d2ca62a71717b9c8308af1b2e7642df12e6dcc20b6b83ff0e426839e9aca4b82171c33b86dfcd10e2f914a4a2e27111 -85c4564c09f5ad99ae5f51f587895e6a5a06e5f513e57fc0f91609ccac4055881a1009c3c45900fce6711dc7fda9db90 -a1dba47ab222520779e91c024250e3e454f7744d48c04c809a07991dff72794bf5990c5d23bc82e441e7d3917fd6de5b -ad65b935bc07538780c56b735460bec2e647d321f28ecb20801ff313a211f003a4e1f9d4b094d0c66f238cbe41f08431 -a9c322f6fcd5e831f10be7372b8be14369b0333f82d87fb444cebafe6cbf90bdfaf2952b7a310d76831436100a625862 -ac5706f371793c45162e72812644293f491ff3b9a974a025c62cc98689e801d25c79f3b072fd62060afc0d05e07ef85c -a9caf447df8db5679a3e88ebe8aa8d0005cbc9a1d0378817968e44ffd55a23026672e75eabc20e7739e727b98ef0d377 -b168a9731835b5d6a0b7b0771dc6776d3acc079f114a60912820f0c5ebb705c465452829702a041f6c9bd24414f94c6f -ae5eb5a2b9ebe9131e394e9763108ec279777ffa1a6f5b8b6681dad229f20a9c1778f23cf72d1a24a753a65360213132 -9563d136dc234ff6eaf46c0630a163414f1f4c37d22448744b368c15f77ce11f42094b4b5e49c870ceeaef3424eaf89d -a39f563d3ae876eb1629fb0e1e5173b096da74b57972ca630fd7d40462a9abb14ad34496f4fa8e4dac6ffff08d1378b3 -af9a1f6040f8936f3af1b3ae86efb09f7433eef92ef04527a7f960bf07f091cf54b7d108fd7b40b3a9052d5be1061ff5 -89ad6c6a1bd71a413895672fb29eab7ce146e746778dd7eb4968f551d57467e16e1f0ef73ece16db4abf5eafd85240ba -87a5a23d2866b87785cc7159f475080de9c684963dc415ae3269fd0b590f5c9862473c7b6ef180fc7b96810096a3fd19 -99ccdecd6a4df1056e6eda6820cd2b6a21450d0e3a78131495767aa6f34c41e4593f78c8ad3e593f80fc6c7615a6f17a -8902f569efa24ab3c6facd2b52d5f9a61a7e687d5837dcb9b2da1ce34a76a37b86812c75f62871d0dbdff06b42f077f5 -8b32d41254d26cc93bfec4e5e157bfec7a2d1f15a0c7cbc4562583e42588c1dbeb2d6c47fdbc02743a4dd0bf5af17675 -b391d9100c90af9d8ce6224b37b763c994790a9a97fd040f091d6fcf38c61f6d39944a14fbdbb24aaa9f311f539b7a57 -81e950e8e1d8704c5017e19dbebd1e7f8a3c22545815b840f42d2c75443c783f4f4c2c9fb53786b0a5ba1b36f238b91e -b80e33661703bbdac230ac7759024e5bacd83c2432f7395311ab23a02d0df677d5f4a832be045d6b9778a80f07cb2089 -8d7a57b024391481985add75ec5691eec13e9463195ac058e0488e54ae8a79dad3a4614790f853cc56dc9471d51c83ff -a4a824c80b84864865cb70b6480666b6297d65e827936ba726282ad0e0bda9787338909d3b2022762c9f9080e196e6a3 -b5a18c00759c83f5e417f0fb412200bcfbd3cf991b14a1d031c0cda35b539ce8724693a6f1e99dda25cc333a0c2d9113 -a4b6659247365ae1d34d8adbac5ef593ab9ac805297aab76f3a7c5512ab658ee7793fc0a27c15641a68d76450b083714 -b8fe57f1832e8f84ac67c1c9b293dcfe6904b51aaca5d2be14686974e110dc0e19c6de94fd75a5bf3259bae1a32aae54 -9734c43b2261feee5e9f3c2407221c6879f1c373f9a0c4d5e926774ab1ff28900c3bc23b4ed4e3c376f142c3ac198c00 -9693e8ac023bec1ae3f9f50a22d753cae7563a98084efc6d8459dc169d49ee2d22a38c1cdfc26fbb75e2b54eeed889d5 -866961869007a8592fac6f104d840f564b24acba1376c5704db2510be47058e9863b59f4f326d530fb470ec473552c80 -a8bb285361734bae3b5110fdaaa70facbdcb3f27bcfb43ac9953e28f5dc844f94149a53ff7bd4749d7f8833948f88015 -8e9e5d9605fe356d779e242df3219c0ef12bbece370ef44c4c19674a7873a477e5903b70d8fbfe884ccdce4ae693267e -917c27c26cea38d8f0351df8c8ae3ca6332cbc5866bd52bbf73767cdecc62a1d7dc9c562da90a6796c8d6ffae3ef1952 -a3cbe2d6a84c296423fcf0e6bca08b1a306cd686be8486b7a7e030b7cb5c5f791bfffa38b1d51c5ec5e9f9d02ca8bbbb -a1c019be4651babd247be6f8f5a8fcdef0c3afc62d06bdc0e4abf51559dcb19a95f0ecda6e5fb6df659ba5fba904e67b -a9172867edc3de59059de8109f14fabc9cbed1567fb1dd77cf7b8a91a4e00bdfecc3f6b0fc149d63c75c488bee3b4bde -91213bdad35d8c4cf3f9e1305da45b0f202fa8e4b3d872c4d7f1870667ebf5174b55e1912693e2850ccd3e507ff07923 -99a25653bab38a306a04c66ed0bb196ea9a522d0e30608111759c0752fbea1ee10b6a574c3e4ffe9ded91d748fdd9957 -8c4b08b4c9c5db17ebc393c279aefbd6f228b2831e94f298feb04a3cd4cd5cc5b7a1464e4884616adc1d54e6c6654406 -ae47e73080e00743a2b8d39b1a296fa47296fa19cef0ae2d4ddc949d7c18e80c44a3b43758e2deabec96c5ae8ebdde7d -a4cbfc4f49e3285acbf2a3e9bdd5c328a5d2f0f38c43c727d424c36d7e97774598e844bdecf7cb85f6ebbad4f1e6a9fa -85691977690857c611f219555cc2aacc305826fe68c735b01d562a78241df139023e1d6a971f136a7496e5a2073d304d -b735f6e75b63734e0f3dcfa788d44bfdfa1658d5edd3cb36f54699ecafde0441eefbf672d7be9aa5878cda81c3903499 -b4ca2ffea56733bd0093d2a6fbb5b80d743444bb2a3003651a3929c7444bd4b60c8b6394d06f9b282c4f787e48a04950 -857b50a9e21ef372ed5e04ba189f9b963658dadc2014034b5e8eb594c64cb4d8b0c45146759136d0d7b537276eb3e85b -84a36f7781c8cadab24fe41d225807ad19396435d602deabacdea6739ebaf3cdb227ce4533b2e558e3894628c115d6ed -8421a4523c8b6645c16aab3cb2837274c1789fe6d17a7a646d0b60c6d3404175883cd1a10b9ff001a8119aefc8177b8e -b58457173e92fb4a01d043199478863fd715270210e2badc16f11f22d685dac33520b16b2d9d9d27c089eb9caa37ae76 -b0faa3cf877801b399a0df58ca6ae2882a895b01f207f7006af366c6a4454a015db0318a2221e91418382e71f3a0471d -90270514cdd3376ece65eae4a2b2c51b1b39373f6643e82d9b2e0c8576752c81c1c5c964b200bb239894ae267e61d5b7 -8fe94f4f6eb2f9d60a7bbec546bdc2744444f5e62555e30d11558da42efcee1947096a514edebbbd0570860d9b55e069 -84330eb1f20a6998af40d4b9e7ee1c1567cedb0401666a10c0d996ccfd3e7e9e4edf585e1fc2597c34c45f36d457057a -aba97d70123cbcca89f325474fe8f952742eb092e03e9878cf6e32a5bd20c4ea92844c5311686cf8baeb72402f541a2a -81e8bc4463115453fbaaf844d59484cb83f4ef9655b2d410e33262dea0902f7f8cc41580cfb6b4987425166bea1ce3b0 -94f8478aafa15c41539adb3309c919a9606afc1edb590930ec09d2212781e3c22333a2ae83b6a86d237c873ab3e28059 -abd522f0ecd0490b21464d4bb5fddf6a123db84aca829f66595812b05cbffa5e2adfbb6e48f0ce3946fa7e0f78a2bd4a -b5dfdf94da381ba5eaf3dee38831b29d053f90d25baccc4dedffd2f8f5b7d4c635a5adf08a992ce16080514d94009732 -93f59a048a8140b5e112f100f426ceb923a63e2585424e2a6374d3d7b979f04e5a0223f6bc56c5c26b41128b272ccd5a -b7521371be289921fd4f230a8c22727997ccfbc7aaffad9f89c10811a977031e5a7a2a1f924fc4745339208ad86bfbe7 -91708536a804e4feb12184d477935ab8aa80857ad4d2a3ecc25b82e28eb064f4f7482873a841ef90ce38a2035570b148 -b193714c58139bfa0fffbcb23dd77dd67279855b16965b23b12059b8b7c8d596d30239d0e7ddb8eee4a506b7fa974af7 -86e780e0be5105efb9aa74ebfea109ad286dc7c2f259165f78f853d161823b20d88afdca6e5630e04a6f01f05ce52cc3 -b03cea4d3e78cda4879eb498381fa06336e49b950267c5f4e9569570a987e120f7f7fdf34cca04a448feb268dcbf737b -b504ce6ff4d2daa4a87cc24ec0e3c540d32a6e315d8fa5e95561428aff4694cc8d8aa9be4074b478482cfd27aa7d5482 -870045338218d28c7c04b5c35881a04eb5b5aececdc1aa0670087cec292eb3ed7061e25a62a8476bd5be066c01add42e -a7a458be8f7108b009be6f43bbd37d0298575f3f4a2088739b0117fcfeed6c067790c3e45390bdc95d93f5188dac4c8a -a91b31776550ff92e9ae28ad985763866475596612f041538cedf619dc68547bba4394aab553aefde1103d0b7bbd7ac7 -b5afd11d971c4e963039a6632b244970c783fff2d813d16dd64fe39e24fb7b7c1cdcf4e8bf105ed23016b7eaa7a42031 -afd6bd91477dc741ff3c7c9cb6f95268b213480df214a125e91f592ee28ddc5a7ed8adb15a3dd2d50dc793d1016f97f9 -8ae49e2fc2aec47f422c32ea2cadb055d1b11432f9362283a9233cec23d90337001109397b08dd640471f13ea5c75feb -918972bcf1001b9b29b1e4c236f0c804caa618af7873030672944f03c52e465a512083ca57ad7c4d27dbee9e0598c9e9 -95dab13d1edf88871699219e5a841a0d29f60d1a738fe48e5b994ad49fbe4b193bdb520896593cfcdf3ac54c0767545f -a985c2b4a52a592548c14b8b3fe1a519d5b43d13a7c6ab8469e62518c89dec4091a8fbe39565951cc515599391334987 -af5de579f796194538d942cbe4dd17db9022bd4a1e733fa6801baabd062ff04b91430232c99ba0a64da117089fad3a7b -af0630c3973c54081bb5311700267a4e1072a2e031cef7b8a759ae70d34fe460f81fd9902078f57df82ea9a026c6527f -89fdd70e79239b6307117da507cde8181a6083c0b3bd92ec9501fdeadf61e98b9bcc65f76f3db7b5343c9c4e3edfa47c -8a8457c75030580d719642a5c19f39d9bb6032e9ccf59f033d7857276f61a7b71c402bb60066298e43e3ab27e1d17178 -88c175887b19a4540bfada4ae515cd5b88c814eeca464e1b4aefae226a9ffbb82380836c3d0e2bc23aaaa7d2d39cd988 -9169c8eda5925c9658d7b89424362c8242ba9c94de010b27622681f6232fd587dd4215c96ba6466c2e58e65099360f1a -b7606b010b4ef7cbcb05fc4ab2413f9442da376c17ca59ea64cf3705d54916881dc34632a3c5022b092d68aa92a7f34e -afe50503d1fb68471f14116afba2d2c3ada54cbae919116971792fd1bf928af95338ffc79ff877923c40bcbb3fcac884 -84b8abf84753e7bfa8310a1f28cfd0e548b92ee89dcd7d9f0f4d9f8bff32a47db28e633e531c851d4f343ef5aec63881 -a601422adfb6ad2f2619cecf13b6a7cfc56efcbfc6d154f17dabe036a81ee885edec82bcb46386647253b38728d2a662 -941dda044f880e5ea1a3e738adaf17d1fd5e22ff251cf8dfb8748aabfba36bd0b54cc5450bb92ca2add2809f192e1e5b -a3e262c5a365ed24cfa5ddf50236bb0e3bcfa3b65561e0bb7422c8871cc58b3671d14956c725c5ff1cd10e477092525b -874fa6d7a9c062600ff2bc836590162ac38b325b3460feebca3bce994c39a84bf3d79a7c716936c7fa8738302397568d -a3b510950ee9dd109d1507b24f11c725d8132e57960f5ebaea1a0503cd63d70eab022ce3548a96816abcbfcc6b95d872 -802badde14c7c17e5c0e33ae8bbd9d47b19d6a48d950555871fb470d4a0904bb99f12352248055f147236dce9796364e -aad6a156f82758677e6d11cc7caa66124dd0038ec15697531d89cca99337b1f817bccc678d617c2be7700d320456d993 -8fa6f41898c20d2c45dbd0bbcf18730d9e14d296214b176b3addd2b56582f22fdb0efdf743936532a94a1638fcc6b0b9 -a9e741ce09dfa9d5d845e0fd8a729ed088ac5d1b6a84709ab0b753ae58b93160064163a72c38c7ad6628cf7278ad1b26 -b1d07f1a7a19affe01f1fed47dae377ccf1cbb3724650cb85a40dba5f4be77aecea8dd01f8539e7071c252d348e4299f -b2ca0f4f725f21fbfb39e151dea4539d961e55645b0b32bd89a94b5f437e6b3b11733fd39588e889cb111d52a2163ebb -a73e4493bd5e8354e8c43a77f4509e411e4f71b41ec57142f5fb53616c26eddcdf87b8e58684eb0215ed91ead8aeb028 -929c423f8ba701474ccc1ce8bbcf0bfd13d993ed8915f628b9a447a87df32ecb8727d056785a9ccf1973d47348e76948 -a6ad64e1fafda6a7ff88d4358b5e56fb0ae0dfbf3f7e4e488e95b75b51ea432eea257523d46fcddb0171eb10d92ca96e -89584633b7146779a810226a3664f11bd53db295f6ccbf68bc75ac65d335cb1ea2276a630084bff9b32522379342b0a7 -a7d48d4957df57d02dd2373acba5976f0b0cf5a08bcc75ed5ae3366b8348a6ea885f60745993cbc7d08426357d313943 -824c7fe6f5ccfcdfdd9632f404d0a24d8ed31efdbacd2073c4df0f152905783275947b2ddb4e16f668c7961ff2c64b0f -895b41fdab7ceb53c0e34a9f9102eac3b07b59494b08dfbabbe371c724bb94af401f0a088b057f141f7d59ba37630e9b -92964eea33e7bfaa502bb14a61f7b11d6e78579b47bb42f5b1d9b76f776c0d4c39e3edc4866fb2d5eb884cd6393b17d7 -b6bb929302086421d9340d59f2ab09b70e9de5c21f1aea362acf0ff9d12093d5429be7b79c73db6744eca6655e77d810 -808e98cb92d8812364b5d4df334fd2d5aadb2cf28bbef2687e488c32d314630b759b21e01d14e306faccc2e7e18d2b1e -826d6371c5cc0ce439c2559ea7956a5d08d7e4223adee421177fff534630d719a90d9098cfee50b84eba8504c6b657c0 -911aecdd90a266f90edcbe0dce1d60a8aa3f1cf0f5eb34eedf30a552d298c5a16a59bbab1a6ac8621e33a109c202b653 -ae6760730faedeae6c9e04d9e238836b66565c5d640d6faea105d6e2d80d0729c3ce93e52983fc2570da82c1f813a115 -a171956ce56ac78660f3104d95a920be6e45b403770ab043ee745337db4dac6f0b29675b41bdd5d868b91bcc5ea825e9 -b2ebce9ee950de59caff41e18c8d4eaa3fb6f1efdf752d265b13633d6563d7cdf991982727f16f2d345727e0f19aba7f -907ca32a898b6724ca06f602f643f339ca3dc5146614b18a82cf4101074a265af390fd2348338c56ddeeeaaa1923912f -b29fc20a71072a7150363e32b4e70f3cdcd1f07a3a123f8c7f1a168991a38cf1f1271031fcec56abef8511ea56f24af2 -90a2608bdbe0ec8d9f7bccc11ca47989f259d139362f88a17dd5853d8041c8d0ae171983a2419eddc81ab2d6d9ed6f54 -a000d32501144549004cb758176bab726c18f22f733fada52cb758445e4468c2f37f24d379f2b8da8a1ec2ff897094e6 -b2964e64d6550bfeaacd028bd98a622257b03db1120c5427a6562474ed071f78abd245c1398aae36c73b6ba7c9be7a5d -af0402a6a54784b4aae6eea1d77a9230fe7247fc036a18f4cd1b72e340a0d05460fcdb71a27673f96c0f3d516567fb15 -8f8a7177d7c0ec9daacbc4cc08cc8e79fe1171ae2aedc1e73bbdd7dbd19ff657b8b2ea47f273df47ff3b8b8350589f7d -b70d568cb174982b2085754ce9805c3b1c5d84d254665525aff7070631cbd7bd8507e4804decd58b4634db2dc795f057 -8c9de130d33911142f0c695e336181fac12baaa86a46f1dbc3d7732b7ff3ab510c810f5b5e8f581d324a5b19e7608952 -a455067272e5d83502381d67043338f9383ef699d0c51d41d3d3e4b663dfb65019518da4c1c218ac3a161946c640dc6d -ac66b2320624b299f34d8c783a99c431687a7ce6691122178abc0fb7475040e4b37295c3a40eae085658b73a5c20f7a0 -ac8f16eda4d2e2e827f127884bb9f3166479833c4e9547e5931474849855d9a18f20037684fe03954da89879ae49a164 -8bf0e93f327894b55443ce666cf5ba0eab98a73955a0c86f8930d6c7d7ef48fce428acfa9333395b50d3d7a64f8b32a0 -b4864d3ea19febc215a832f73d26684891746a119b25606cd3fae30cc23bc89438efc74554c9a38916294c47f16da6ad -abcf5d2db0ce95154e769afcdf5aaf2121890df5e1337e38ee88406f68e203929c4610e62630a12f01672a5b6f04d166 -8f9b7c9c79472c6b843f168b1435c998e11f2dc0699b576dccb2323de78e7e3da3b90a49c03f53bf82947ad7ad8e943f -a89c329c3abc9e09c2f34cbcffb64dc7b85973fe160a60e7e7efa648e3296d06aeec2c13bb732fae98deab60dd792d90 -925b28995da25a087816cd8a5a2c7333f60a6c2103fc8fb844e555423c278d8387e0fc2fc0b96ecb8c1484bf0ca152dd -afecd3a4a94349654d120b15d2bf889b8c10bae16b0d128ba1572af01c66206c38ec33d72027add552f36d37f2aa4a55 -80213c7662a65d8d0769dbfe968ebc1e55c918236b732b9e7d84fc11cbca3065455ee8a4a96a354a5c285b23ab298d67 -a2ae0c26241c11142be790985071325ec6efa7975de5cfd4147ed9f52dce00e11fa97fab03dca5febc79855a618c390f -8bb07a399319799bf8e638c3ee5eb13159b3e6358b9fff149b1c880cbef565e1c735c0e7600aa88fb41985b9e1f8cf32 -b445129df95b895f274278ddea97a9231f9338c85f675e5c87a85139171c57fdd191d61fd4f50d5d78dc0d0b4a623448 -85700e9a5c920594c6f13c532c462f8e0617ddce14525272356b1ea7f7220b2eb5ab4be5a66a973e9596cea6ad3b6709 -a7c4329b116f697c5b36f56d6fdf0d64cfc926cadbe1002143276205ed99ae677463774560e9bafb8e02829ec947cf90 -853e5f8c34d35222714264bd7ec2e94271f44aafbfbda308e947ee3287dae4b83d5b0824436a8c429b263047ab8f70fe -ada60cdc0533b1bab7ed400dbcfbbf3ae2844265bcc4977c950d83a5caa9ccac38840d0939c1544f41c9706816fbcb5e -ab3ba8161a9be537d1a0502846f4ece158c13f0e1aa58b748e729806695fd4cbc0c7abad92175fd04e817f2ae6d67f71 -b4bcf82b6131c65161f008409edda485e3edfeb61dfdab6944cfa0d02e0290693ab6a6b4a22bdb1b9fb07badd1f17b19 -8aa7e58efde80d8952e5b18cd1fa856ecf0ca04ef55c41780392feac675685cc394b6a08acc2ed5219f59c2df476bee1 -900cf373f2216f4c169e442f68ff271e7b28a05c29763df873426a12ac981a1a08aaaa0c731ed00b651c99f160c3e35a -a35c6fc25f434e15cb98b3b58714298b0cb39fe71582404202f340edc1fc741c598b22c95405c03e850fd2306d398a99 -842b31dde20c3b9aa1cf814696f497279a4b074162b10c6c444155bd7728bdceaed4388d417841f3664dacb5e8e343e3 -8a588d64a90030555858f1f316f350700522262f8f8378869bfdd5a6b2e2ac62dde279e6903c2d85279b868216af020e -b92d2dcc4658987b9e52b67306b3918c08cbc38c1a8600b7d9edb96d6813241e53e9fdd9b412b0288fbdb7de87a715c6 -93fb9780ac3d5334c1adc6e634b29a0f708598d620c7845d6c5b5a1ac87c36564395ac9e826529912986314ab75d6b45 -b2cedadb7c791656f3a93e254e43fa1af8370f8a9274876914e1db2f667e994ed183639a803e24cfc32f8df8db618a4e -9972861060302b37df9a52d80f048e4d5791f593c16c97b3582ecbb49bd9861906e4ea7d5c6129e1cc4f1bc31f51fb7e -b7c7e62877cda820c9d12b716666aed4e0e7c8f8b95c9510dfd0ae4904b800287249fcb3d64a7ef466be594042d029f7 -a6d44decf085de8a61ccf23c132f3e70af2abc8732aa46f4b2ebd6cff90160fc9c0863938315f53079ff51139dbdc9a3 -b57c378717cd46ed21395aa98851e899bd37d75b24a08c2e309e21f642a1658f6d1c0173edfa66d98df4e389ac337b7b -8207fc98fe589a795d884ff859e614e2ec5e2b98d87dd31b4a197c018be913bf6a53021a2d74d879e0736c23b44d98cc -8db222cc734adeef98c79be58e68780751b82c34b91ed6e532e11b922cec9d8da32e1129694c7653d16c2ceff62a55d7 -823602a4f5c867e0d790621ace7ee783ae91748b8b2a112d402352561a4814d0e128f8d772e096b0d272d287c7192332 -89b3344e3380760745a463a5cc4882635c189b9e50c749422dd4fa467373d97e8b4f0a1440c2e3c55b8e814a2ea8155d -a15906172a85c6c0741544d02bfffb73d749f76b1acb3ee800ea6f3183cb70ad4b27ba6c0eaf46094886983afcac5c41 -ae70492e56634f7661826c1e176e63f92b70d11711dbad737a8c01ad0e523cfcc656990a8103cbcaf01bfa504f66ecfa -89caf80cac28e2c8d874d0208c21cea2594d3ba0f0e0b7756e1d4405dcad55542d54c0040e6ee53cdafe21227472d961 -ae38ea2af6ff7a1f8f92a80eccde3e9eea111274d1a37e53a5c581836e228289feb4e1eb3739fa1642311f8179eaf4a2 -9932f5a85902c839c140cc76ea1ae79e4510a28fe365f002b57afbcf0eb813c9c7e670d49e319fec93111dd74e7619f5 -ab281d07e43197bb3649df41ee448aefad59e5550c905a500f6f7a22a77fa6f56b628565c83bac51e03ae23bdbe50698 -9556234d43d8f72c69c8c2ca37ce563d1ab3679de1fa1009f78288d317fdc26c193688704876e784e248fc9cdce647fb -8366914e563b5926904398027a7405702686c1c96367add1094a33bded979d6d5870a429e999bcd0f49df892fcf4d0e2 -a01f30ea58ab75ec78565079d38d509da5274717127b89b551e744b44a8097c90482b3d7f7283994865f8c33993c23ed -a16f3557712dc456eb9544b2b31ece03ac3a1e55373468c3176aa662997da69746878f07d659b73ce89174f7dd14328e -90849671487c35b35910718d1bee03836099b263fd85e7ab519cb7549c1d8798832d7f3eeda3ce5157d202e73833240b -850553f71df6378422fff8e52d76d2983971f68352e38906aab1e7ac0a400208099a3b67f84c22cd6ab9d4c31d4393ae -b62abc189b6131823083d41f2849b5663ebb8d17e8a772234690793a0a3494a1cbe36ca6161fd80bd25a015ad20525ec -b460b5277ccfb2d4e5ff751cf03727541bcdc60c29339020968f29aeaf3edf27cfd2dc672548cfd4d6e4fd88f883634c -8b2b44c6f68ba4c0b8a5e81c1b8ef81ada56fdc8cab7aecf4b8615d57a65a0dfa0185c90a72713a84950b1376cdf77bd -b450f25fb3fa3c0dd13a5c9178b7aa72b43f39b3a9c74fc24a618f8069414baae56ded1ac6ad66f4f30a44b2399f397f -a2f9271c47a68a73d3d2dce4cf88ea6a3eba3d482037a3623c4f5130d8cfde60e6ed714d7d25cd1b647a7e7d553085fe -b8a7e7335e4c060bc4fa72a90146e2f13581edc42edf84040baadaedacdca0d45072b48b8f1ba51d7aa1fe3e7d9c7108 -ae0dbdba0316562aa2147c91cc7a3402861d59e557951195cfba8365e90a62a5360944d571722bc10a5950c2ff82ada6 -89dffb86429e7afdef1bcaefd0f6081cf7f421af52d25a0379a22c93374aeec6832d0e6a236f56bc3efa98849a9550b0 -b9da55d3d8a1f9cd6ffe6f7807f6fe11470c940d4214406045fcbf1ca61e514066731a28507470f19ee4fc329aeb71be -945f8e956f36f8345a16074248ee73286fc00abcd4ee34f2fb7268bc07555a2c7055dc6c766bce563b19af99fd3d262d -8632c4f42f282893db3e3a50347a6f23718ce1c6e55a568291fe94165be9caf819edc8610e3a8e9bb3181a19b42db32c -8642ef6aed39ef71af8a80b0bc7177bc0d7e575e9bed759f88bcf7e1a1375ed4538f2df6c7a5ee887a7ff440faf9ee6b -89b17b8a26bb7721f30715210c6561147f8e6ac03489df1657bbc30845056db9ceeea0a7f7cbc211b7cdb172d1120ec8 -8cea2a9407985c328eaf2c5fa3f1ef93919459fed082867fd4e0be4f155df41a448d9f24caef89c2b5a64ede2f82591a -ac227d5bc123780ba295e32fe9f3cecb0fc5e2bc87bb3d18dbc886c2fea09e37d0dfef830dfce7aa8b61a0fd6654e16b -b49c7c4b0bf0a17540dbb6019453f4b27d43baa65414b47c90b603d18809727e8e844ccb4871bced384f8b9116555457 -8cf866afb94ac10a7443a8014d2d7e21ef4e2d202bcfb5e9d10f47d71bcc2b86861e377c5931199d591a3d02b475583a -aa25cfabe1c313df181ada5716923bf4057cad7cab7face00bd904bc660773238ee8e0f615a5f9815e445c78d5b8e9db -83ca763b5ba08cfaa9ae780ebe33bf2afd39120397c71d1213476f7290bebddd18ce9f9ad060f1ccd423573d566e04b7 -89a3acba12e9f7e4237331d9f1f4998a6f0299a3d4dbe546ce187302214d4614508d4b775a58d2d365766fa6275e07a2 -a26127a3502d14b92e35364bdd29c07ebbae240666756d4dcb246c0d99fcfafad98b0c33369ed02413ea9c32623ac082 -8f3439f26390c844518834d2d52474abc4819542a0378ba813a264140532fcf6e85c24ff58261e7671cbcd52bf49e7bf -91439c54133ce9b505884beab1494fdc62ea957acaa875708f40e687db536e8a792ea4591f1bcf5177ef3e8518dffd50 -9477cfdae5369a59aacf26c370756148734737fd0f494f04a1d562eaa98f2e2b97ebcf32edf8654d48fdbcde4adc09a2 -afe71c35cc3e33489810cc45201e3fff52b7fd9faab39441ffb173d2333fd3e7d901e4570633aa2f9bc6b11970fe7742 -95ed1748d9b3f6e5ac35072edbc25c2e72d183dd10fb6cb27fda78ef7cf6211452310b103bee2cc373bfb0effc570902 -982e1eeabaa7e12f2323796712a2ff01ba0ad0d68f97413369fdc53e4463741d465dac5717e18e50d6fc292f259f23ba -809a1c0abf6c9e06ce2f4ec57a9c68e5ee441ed5ce31e9f87d1852ab7a337809de2fc5eadcb830d15f2209f8cf0072e1 -92166578302b6d4ae165583324dc3f4f003ce52aae45f765cff7f4d78d5413d66d5cb17a8c9845e2d63bbb7754cac7a5 -b62419f9b93744b39a40eba6a37963bc885b286aa5de5246670c26624974a2c2b4d9a17b551b0589657b17c8d2ac2f50 -a7b5bfb381e75f35565eda4ae209cb051c22e79e80a81bf121b5c3620497020a4be6734e452005b707b0d04293c17f35 -ada1ddae5ed319259cee96dd20787ab09934e32c7daaf0bbb3a50e17af6d528e151632034560d4561a418a9727636a6a -8cc9aa9ac525811b72b8a04f58db788b5fd921912dcd5dc0dcb3790d8244971072c7838b7286ebfd9b73e883ad9fab3f -91c01239a1d07c041dd665c23acf74ceb011ac22934e4c046b0de75841f8cce94b321a9490ad7616a5d0ca6d976b69ab -af7e6698f0ace7dd08cfd8bc0f7d3933e1020df1b101beb35bf8bcc40a13f37183b8943989d4f39c05d62c192d891697 -b0fd60eecc7600d4a1c17fe7bb899a323729c43de13e38dcc1c745c637229de260bf3e53df9aefb268b40119ddfcbdb3 -8dcb252effaf99207d92df32aa0a725a1a252722ef3b378c37ec5d8e1daac9f7a8258ea3cb99c5f1a7ff3ba4464e643c -8ab01902afc9e7963bdddec3ec0162e535a1e1e222140d0d1cbf24f64a74ba74cc94bbcaf5987069b40ae82731423a77 -800033576380f6f6c3b05a9a8f6f48cacea7302f50b844ba22882b00c724446d835a9810f4e3c267b7ceaec3a620a344 -91fdc9925bbcffb2eb156c935ad573a310c37a421deb09cd045f2397f27245dbf5333ed044463e1f938ee8361855026a -8901e7ebcaf9fc6b0c649d9e2d3008713e91849e4ce6b1288c9c32b46df96f5ac9ed1a0b4fa326b1bbc3ae201a9cc9e8 -84501003cba5eb5b26704aec93938ba27e8e1cd61513a3efc70923d1e5fced20dc4ca375f404d8be956dcf2d625fb705 -8eb4da12e6b7cbd1376fd7aaf282e81bb5257b1c895ea7f2056f700f5adaa2e4410a2cc8b738bb421a21de7cfb6da14e -820cfc7fe92e440fbce966380edc8ac81fd825b213d63fc2f0a389b85f318967135bd9d167f1bb82893cf6f530494076 -972107296d7dceffa80aa47d23967c8edcec95b1c941f01b5f882766be3bd890f9fd0235c604d39615dadcd7ba9526c0 -986b277afa1e64c33232185dada5e49f06ecacaf45a98f3c3854f085927c34e714a58cacaf5e6b65bc065b10a86d82d9 -a59e7575dd124680a9ce7cacc44059574c95183d2ab0e48c99c966482c8930815f77386db66b72f5a22bf0de69c6f684 -956187de896db28085631690a30a87455e9a28f18e12d6ad1631be60d57207588b2b1c74bff8c83062bb743e411f3bc6 -82e01d894bca2484284a668e8c6787c5c074b0aaac0399219025c59cb85202bb3ce97a33a09f79cdd94db9ad8f9ff319 -837485ef346fc13df5e2f0ce8151d72ef05ca5100948ace04dc70c66a6b42f2b40530277c9330047c337edf0c6025bf4 -9753e650e0817ba23fbe57468fac8da4d45565872f210d7eec36157d95152b7d3fc843724c61440300a7c82e3af4f9be -98bdcb902ef63046e03f5b93a21ab29782a16bd4d9ac4264b260904698445464f29dc4505548a511d4ef57940519ae4a -8c161972f4f6a2c1c1ba9fa6a3fd580fe34d9ea6337ea3336f861b8450db838d5919e89257b21871d01d62b1d4cdaffb -888472b71b06971a6016cb08265e3de688837bc312044e73ccd600666ae3633901051b40ac2db99a2c6c2e0fcaeab2a6 -8050c5b5b3e6dad7154228140d9a5565ed900de2c76c1cb584bb51b55c0b6bc6907593ba238028c74c9000b3de53e52b -90cbad17b9b8fe56b34db2526e4d3819f7e494c52f3f10ac1577777b1bcadb0dc1478fc5737855571dbce3e508e12c51 -abdf4de4aa5bca87cfb082b6221d7d778b4b3ddabc73ffb668baafdce7cd665807990fc2fa8c48dc703c872509f9c239 -b003747b3471708c2fc4119694ee1a49e4305a805008cbe69a9ca5e9bd881f33c50971aeaa3109e730710f51057fb400 -957d15096e585e7436c4b09e24718bae6f7b8e57529de8919f6590c793bf5e7029daece21dc9d4c869c9fdcc304fe909 -b44683865e50f7e1a5889654cb2f0f988b604d3dd48045e39be6926e131894c5b45922f4a5c99b14e9b6ff9b0fd6d764 -a8c3357ec6da32b87ae3ba765bc551986d4a48c10cf9d63dc3d5741c8ada1ce04404ffdc8abf8a011b6a0be6f6df75ad -a36cab5f77c06265ee2c5de52e7a949df78700d42694a722f1b730cb80e1c28fb16e049237b819a3375c4e3012564152 -94f1ba006e839d0d59ba4ba467b9a86816ef36c4fbf772fccead361854a54d19e0c8f2d01931b493f75e0746fd1a88a4 -90f5010bbd4ac4b1863a1e836793380e54b0d3e7ff864de935f3f2ec3452bac436e3b9a283486faaeadc84b3536a5cb5 -b7600dab8bea821696bed4fa62ad6b7da3d389ecd129bcf8cf4b9e051f12524f476f165e59f31310cec5c6d8adad6d8c -b7ed011e2caba5e20c69a9bb1347d83c0f8dc80049d9c595cc67c69ae429fb935d648672c18e7d1de3855ab3832f7cc1 -b2e32d45670936b75b6f7252a9a0424d5efca0aee58b7407c95d55f8274186d24ec5802e9bae316cf1a691448bb6c343 -97b37b07f399d550aa17897dd6f900bd360a2e4b0cc3dbc01f2cb3b286d3825545bd31965047d7fe1eeead3cbaf13373 -b09b1237bd55ca5eacfc22870de32e9d62b9eaf8f82abbfdc9b72152e453063deda0862733ab16f85b858245c57119d3 -abaedfa830ef39d52ec646095f3bb9beae8a5846977aea57572880a55af193f1b4a9181560065d6bb80f2e7f02009dda -81075b578ab950b7bfcd033856250c00f9ba19fe44160f37f6c3b685e72c9b597c69d6c7049e489622983dc81123519c -84d4814756b6e2003d40242c6b4a5786c91633c7e7e35898e8ed85c3f5914082a67e84dac4a29a77bd6d1f5bd0a076eb -85eca1066cf79df86f0021e4ea2f3ca5c4e6f1c1665842e17c1f800baff19ef07bb208f5cdd5a3c67730e612b617559e -a73c83491c9ab66346c5fb318e58e04da31c36526172fae86c9f928f07324d4924f789c00947eeea7975cbe76917c947 -8e4e317a6495df0595c0c5c8d0a2ecc132eff18d59b95c30d53f80b93b1a84af63e6b4a13cd29b5b05c0034c6bd4f3bc -8111f89d99ee085229f03206c3faa97e1697ee963eb727a1e472b959da1e6f7010885c5230821c00f214907f7df14bbd -950bca4a0a796da47b8d20249a70efa37b78825f1041d0191931bb15804ea4094a779ae4c308aff1838b77c0349b5105 -9743e2343a75f5b26be5eaaf45b2c90131fee1bdc51be5a1c3528bd84be758e3603b8c524388974bb181542505be9cac -98753f5e4893d342c7c1bda8f5ab603cb13297ca45ac70e48d9841bf179d7a7e89f4a42d543c215ff0c9cab085c43f8f -8b59cc94de3c45ba3c435e455b0e13c11d27491181b183034faff0c5991d9b3ce17c4a9a8af046679cce5e6cfe9ba641 -a649ff0ca2dcd50650628a6632ff484d7d83a2635f7f8f64b242477c172815c70b10db2808f13d8217d631a5466ce229 -a11d300902f0206aec5efe7678b749aeba561592ecf10a20d3d15448a0a11449bab75a29c2174f6246ea834bd09d1abd -873f64e5d3a94ecad56dcec7ffd577ef638c9965dfa41b931f703c9fc353555505aa708df02ebfb30dd303dbd27dafc6 -a282dbf9ddd9f9d5fa040105cb1d3231bff53cc9a5bd6abd6ba6237f25bfaec55ed9d564e447b37d2cf90bbb9b3fc899 -b633ed1e46aed7db30fcca556d7ecaa4660abcd79355357a6b0823b2b5c56db2ba98542b0a01b57a3721b94cf937fdd9 -80f8c27c772857c997c681cccb6f8f9cd5e5aba871516649d9238f4bdd05f17bd6a259608173a1680bd0fe62c26a3a1b -9088464ecac788fb6f172a43793e9601df21a3118180aeeeeb9f006a4a3ae8122f815b776ade7bb853b8d682f571fa3c -ab21eb54ff6d6c2b66414e50b09e06a3fa230423c633bd597efd32d5745e88ddaf8b04687a7715f7a106350c61ab12bb -b5b25b462223cf04af61cbf16501dc91797087bf7bd462c31d1ad8f717df3ba970aeceac6c1208515d0deb7ba6f31061 -abfd331d9add9cb57b50c6287e23da675a6d317923b4144c1c483fc71c860ed4a405775cb77139232f9e0058a4011d2a -89d91987a4f51250fd6458ad39613ddd1684cf6ccf469127a0cc28fca24f22a2b8dd871f7027e8245d1c6dea92d388ce -96b0be61787d04bc33242bf47fdf8926e2e8859513ad37f1ef337b418f89fb4ad976216c3316d18ebf89436f24524470 -80d0abfc071388c00092ee7f56747b34cad5006e45adbbafca6044941ad67c7bc945afa050756eb337caff11a2ea35d5 -88d1513b1e59920aba986769129aaa86ac1390dd570d751456c0d5c304a74b383da3f9fb9d19bbb7351569736961267f -8e835329cb92627eb816d67d5cc6ec4f8ec28e1026722531927e989e0dead65ed36d9ceb845651a85369d309c45931d7 -8c2d3af0c84a890728b24abef8e1d061ca74f822b54c8fa29c9a5090b0f876d907d9bd37672ef33d5f606745d7f50a3e -974e4c1aea6452aca58d4ec134ee7598f9d4a361c081cf247e69a7e70da35b36292e13f58b6a80c7f27793d72f101b4c -b48134934a48d6f7c588c9083bdea8b765bbf08dc34caabdcedeb5101bb1331e70ba8678abdab813a5a84a55cec9f23f -97423cc7b679d37dc04ab1ef13e3d80b5f8080599aa55dc2972b8c49f215f30ada4aff8ced50b1704d6d3ec19de9649f -996378cadc1c5368ba451c12a8376ddd4a5bd54a1772b73accb0a024503e8406bcf6565799c1b9e14b078230c71e294c -88a2388ae4d2aae01b20c486da0fd3f5289921869d5a3b1d3b184baf6adafa1a7379b4fcd3be7e7a05f5c4eb45a8ec37 -88b53d4c6a16a308230d5d10278c8f439f0815f036db06ba2b2c905a1b2eefdef66f57efec299ba64ef63cabf475a153 -8c40d8e50ec024b124c6185b5a87e9c29be8ece392284986ddfd24e4485d84cf71a4843dbd8babbc2bc7750d66e34389 -895ec63734a6b9e8e476c4d85ad1e00b9905a0f900cf126c2c5710396228b162b307d24140e24a81db5bc6820b3dc8c8 -851c942f884cfe3c946c9fcb80a0651c31451fb3c07ae8b59c4d804e169d165b3fdac28406119025b450504418118263 -aa8adc591dff1cb710d03bed5ded71a67d71efd563b8848bed2eff00ec7327c9d8dfac6958fba08403a4310f4093c4c2 -b03bd5a2544ada5f9a394e6b3c2a759f2951e3330839e4be3818308d98f7bc51f2b0bcb624ec7cc3561a736f61e1a65b -b7e9656dfc837fa1263068a950ebd37781339b46cbacf9db4167e61e8e2cd48e48a1d9133abc09e56b776c3ee9d9c06f -84a23d09ad0e6fab688c225d319b12adb60f53b62647d9958743564f4bc02a46fdb661a56187e7f3c101304fe3add149 -ae6910e101ce9a47121f451060d81b7cf2ebec8dea54d1ad9c2ca028619575d09aa262bab2b71dabb8fff00d63f693f1 -a8e407fa60eb152eeadcd079dd61aa2b1e93c56870e4d5a6321cf87d3621f81b0629fd7a5cb221e2d7874c588dcc46b6 -a1afb62029726f5539aa88924a11a50eff945ab2b62e197625b25d3185caad5ba8bf7c49b425d7f320b48ae3c1370e37 -91bc8c89d0df80419f8cf7e9384327185a6ebc3fb1e22b61c627c40b438352164b5e5d7b75e785f1a7fe9fa1397a6c90 -b6232425d78ccd4cd3259639676a779af2143534a5ea52b5dbea6aa6e76e3cfb434b31872e864820b7a02c7886394999 -9465efbcad40d69869a6282269b038f030e01ef6ca32b174859ff0942685f0dfaf364fee7432cbe644dabb4ca85e955d -86b4b41abb7144be3002724890619dbf336c2f38fa45844d6636ef3ea0b97999b87b95a98e220a816dd90561ac25c7e4 -83fbaa1b7f43bc9e4e3d9f9a44cd6a7c65395e48222d2540820c5e7441ab40b24a9bf3e4961ff28041bb6d07be9f12f2 -808bc511289484f032b153122a82d719d8b13bf5f2fc7f7f0a6509b9ad5ab132ed90cee390a4e72cc842e8632d167aeb -8e4bdaa3b7b057f7825cd824c978904482aaf1ffb70b0d573da9b40eb8bae0df5911b3a356f5892c91470f1652a99c45 -8f224dc2aa20cc9c357d47a972cc4e5ea6b8f65c63924315bec47158f06bb8524dc4e9c1e0ce55939a61f4a8e0ceb8c9 -a809370c71bd64d37315b0ef483617c3637693fda702d2a4fb3dfd42015591af29722ab5381207d8920fe246e2334505 -878f9ae4c2b0d287d292873df9c87bedc45ba54bf6cdb1076c43d97c44dee0a32f105ffc67a0bf300ce84eb656f844ae -8e3fda631dd1d2ad15756f9430dc157d6e1daae235b4296196c31233c906fa9936064367cbe8fc4f4d926d70fd2b812e -8ee934bf12bfa342214e893e918d8c40b4824d0ca82f6cdfc34bd1b6b469235a26ccc7a15eb27c278c14b76274c861d8 -b59c220c7a9ef00213fe7da2b79f9ed8a45c7dbd1e9c1a7d16b4ccd6fdf6e5843ba1d20f1d69d249a86df5f6a70a5f5b -96065ea9f2ca20469a851eafb84a1b10263c8be405a4d7f3dc569e2c7a8332ed1e838d2196916f628da6246c939942ee -b0fcaa930887b72bc3a23cf17ad969d289d06b39e49db55a93052d4d9f8c110f3e07195ac3d74de3fd10cd73cc2aa811 -b2e8efb9fd890bdf38d944db8e2bdf34cbaeaa2c3bd3c018b982e2661b54587e69b67ac0515f6f8d1b9dc2da686242b4 -b7477f76fbd2f6cb042e0db1d5f738f4368369b73b0ae9972d6633f4b8cd63359074bdee83f86a9cfaebe63edc26f48a -9835fadca0bb0e2c35ed2ade4496e415f8aebd295d5cec08d43e0528700242e7207b17c015898e165047cc60a6622a1b -b956cf0854982226cfdf08457a7ad76576510af44e0ca5947539581a802caa7848bb89acacd2616a8363d2092af4086f -b623b959d5b1568a4bf841f7d3db8b23b18f5e74d6920546ae4d026e17d05019d8a2ce533cbd719cd95bcabde40abc99 -9870c15c12bceb94d0758ae9c3213cd079d5bafce5b836bcfc8ef1a5fffa416dc23154bc8afc6446eedb3f74481193a9 -83e7b60040bc7cdc0a22f234d2cde0371ba9843e2a0cf7656368c471f9411a08218e3f38a26475cf295f9751791ab52c -9398fb71cf88042f3c5c8f9edb46cd1b86fa541a82a9774d173270078ecf26683e18a8e963b458ba35fff42e1cb50886 -b9a0edad714d3e7e1fa248c946660364f4092994826338a7d376a4e9a137839cb93af86de5f5a43b530b42ec0ba90271 -91c2d320baec5a90293f009f9d3462bdab20ea462d8e1eee06c526223c0e817d4743a9b8ecac8c56e6f803594a8eb9df -8056d637e4250684d7bbd59cdfaff55121e116961978efd26f27ef82ac832d0c47175835bee2464e39f2a3c4c037efd2 -91b7afd1a2b07bd4bfe02903c8b8eabf2c2d4753134caf38c9ab547e063ecac74fe9a740bc20483622e264b071e2bced -b872a46732896fb881a9189abe18b87c8d5b11b0e655c41338a1c882033260b24116219588e037b5026511321e84882c -83a9231dc64a8211105f39de667e475fdc87e9c336859cc80b531de191c1a09bdcd422add7cbe164f0fd810a83d1e17e -ac7f8ecbe74c351fbeba9e6fbf6a041c491639a506a1f0e457cd61d9338a2b1c382c33a512a7d2bdd6ad220d5f4dff9a -8a2150265171f97f7fc7eb56770bda654d91845540b9126cabb015db3f62d8f78c2845ce9bd6928250b289bffdb78af0 -981119d1385b5de53f1f1e894ed67b17cebfd943fb61b611a95cb81496fa6375f81e80f50803d60a4e8b430e0fc8fff7 -ab478a70772fb01532611029a9cfeab2b23506da69d5348489c0217e039c7ee1b287aaf0e22ae26e8abb23a05a184bbd -9195743d8e943b9aa365b42e929f49bfc7d2ca84dd69ddc06da096ca681262ec1a32341a8fc6024c23823a666d9ef511 -8df2c92ac3e7fcdfbd2a5f319a10e39936176099fab0e6c47a1367153ed084fcd6163799fa62401e43353118de170cb8 -b388cda12c5b400794616585ac6d646b87d73d96f7ca05dfeefd85d409b53789025838850c430e629daae94b49eb9d00 -a46b2eb3741e2fd9278bed3b8e6c208f2ead291f1911371ad078506348c1e3017666ed7cd5c927bbbe94e1dfa6ee5d76 -87913b73e14ce516fcbdb87b547a60a8626fa3e5626c9ba88abf60315fe7536f7ab08d8f9bcbcbb89e8ab88b9e940965 -86cbe3bbbce67685e88727114e89387e9aa650ad48b02937fc456be93dd8c2a498d34cc98841782fa5dbd4c44a15f4d3 -abf37a47fa66584ec202f381fb0902864552a467f8fb3108f694ba927414c36f29e7ba80aa5a8bcc29c168e0a7406407 -a8a1e2f98e922ec615d98a967475a38e66f330ddb28db9cb68d8f762ed7b4943155bb8714970c15a007bfd1bdc247f4f -b9fbfb18da6c54da8fd8fb8a7309c91bcae253456cb68f42ea8cc795f0bfb627af0084815da886d5ca9c11ac2b9ba305 -8a89215a3c4858654d55bdbb698e29734c47e729afad4ef929635b5c81b6df8aebddff2edf039675662ed672365a18b9 -b7fcdec77a81dd820a3b30a761414978a19c797883c45991709753f6b5bb8f1c18a739fdeffd5bae72f4e3e02e73f185 -a758cd7b6b199082bf7542d2c3cba834e252e78aebe11070bd317fafffece471aa9a14629197f31b2febfabb29fbd02e -ae635672ff682db3821effc3bf7343e2fe773cdc9e65b38f950e14d40d75d556ce1436880cfc8ebf94a29ede76d0d914 -b5819263a5c3fcd6637e326c1e725c9745b372ed581b4367d5e1209f12ea5d8cbbe41799258fe0fe79f14a8643386dac -b2d31a273e3c20835f807d169396c24998fa08f050ea7045a10a5d71b29297a705c8673c482fd169f8f6fe518dbf1e80 -ab8a24cdea5cd6a85be299e105c80c900d316c3a87910f248fd6324c673af793bad2bb1b2b10410335df2119ba1c1d09 -80fed5a8e0e57005fe9d1a95219afb022bdafb4ba03ce5877b5700c62219348536564e52739ae4a4ba94c48b225f8fae -b9a8c38a1a75b49900974ea32b8966c4e7eb1b90a889a2a907cc42632e185f1ce714c42bbacf2d5c0748330d8673e170 -90e947c28c48fda8aeb1448866ba81805f7b8e66afa6906690cb9e5e4057e3cf33db75ea6c94ea1d2f7f74f1a1046f0c -b15f8350a08192d2c0409b4c49842f1dbfd944471fbb7ff1a500138b74ce9d1312de757790210cecb00bbdf9915a43e5 -80b2f496ed36674e0448224d6b3d6add8a05e7f3c583e6d921b7c9bb819ee8844ab46e65016178d1176992a19bfc54f9 -a866b0233d2b441ec500b90a4300d1365a7fe579412e70414c2255541ceca8bfcf838381536b8c6593e016c689cbfb06 -a60646045a605928d928a680181b9648f404d4dd81eef04826c07819da7216a0b35cb246078e78da97988926dde58585 -b714167ac48a849bd61dd9970012a51c3494ef1c2f34720145cb1f4d7a9db1f78449c324c2d30e28b4bbb038b3d04a86 -b68c3c3ee0d123551d047f6028d5703c963030540b523ba86648164f4e2a24691597f0b2a3e3bdbc1558fb4ed6348473 -8697915a6fc75f4466319f6711d1e1b945b49714c2ae34be58d82369fc490b963916e809a3fb62c87225327460baac45 -ae55418375aefb77297da8f846bdc81dff73d16d37bd8d04518acdfcbff3b948b34249f4a268701b73144962e4b91c77 -806bd788bd291f36d8da93c63843a4318e09f09992a25d1e0c22843216aaa05894d59e749b357a532c553a41696c644a -b1cb21a6de1f47594c97141b447202405328f8f132e22d386be88863f960feefb49901b553bf4156726979e4bc3f8003 -83ee909bea31d02eea1ce6a2d2ab840fe9ad1866e91abe71712602320281492239c5baffbf924f662ab7e547a2362c14 -a4a12fad59a482e6e951ed81f1a9b55c0bdeb3bcd8bbba4c7b8c75a31222f0565bffd82ad0a346ef354dbbf65edcc81b -aa4eb0563ba8bf48131e95bb0bf08b02ccd261d06870670642abcc205d5c71a1d16eced0170c910be5994a4775e25f12 -874c9e395f1375c334829d790f7f127a88339a011d96f9d71153abd592fc74519fce0b99eff3353e51a4b939f3df3df7 -b88a068c26c1fb140637f4073084a8f4d927d2b3b175deec55c3589539059848e799d172d5c1dd1839a228c93d1fd443 -a700cddf34adc75501d3e76788a265362cf46a5ade7dfaab8dd5e3a4d12e6889df3bbd6f350b9e7403a45530e2159569 -89fd0b6282fb7f24c27d5841ac8f98085fd4517abaef35ab3f95baf0a7949df79644bd55ffb15caa1259334cd4f1206a -948b6e2440fbdfee36e6f803d87bb185c628e0416806a2d2f3f5d507e1568ed944541f6425174180dc8fda5ad02f85e8 -896e8b40dfab92097d6fc61b68f87931ce1bfba4097345d6d03ccc69228f6af773a5704ce616a92e128b4fc29a7b777c -b670d62c0349baa9cdb6698ce66825800e8c19f203f24cdec43431eb5f2649a16ef146fbd22870696e51ef0ec14683c9 -afa59f1fe510c1433c07ccb33b01ae03456011aec5b2283a3484f1b83a397eddf43a488ddee6054f416929c6a59a32c1 -86dd6c8908bfc961fc051108239a7a7f9817d6dfe246d869dc597570188716fa82f646e78e2925d268a5f41e4753c986 -a90557c3239ff96b569b1abe835b2cb416723e22b46c94bc9ad493c11e1198a3ec22cf523e62d318676acf7b8de4f68d -93dbbb8829df5dde01126e963ed9e6a018b4f32e971220af3a0885e7214a030f2f32b218b95349ac03b513fb89bd79b2 -8abf5b250de156e2ddd74225b96098c1048a77588adcf6169036c8202e3b34d7d903af6faa2381fbf658b7f6294783a1 -941b133b3efd11236b812300f6b86f648114eb63b2acd5d69056dcee21d768e9b11bf94ded851fa86fbd4a34e19ec2b8 -ae044a3e783c7a9d201333f18fb8d2271c9ef992c1b159f34ec750ae47ebb94c19e894a3357f0ba6eb4a166d5e9a03b2 -8c99074fd22e374fd0f9f04b1ea71582a3b4781ee92719eb2cae4b1cc0add33dde4d27fa51952f4da7adc12c775c91f2 -969619df29f70b4b640d499f1cfb0a7fcb8f7172e03162c57b18e6f852b67f7b8011c08c96b96703650374c6cc74fdf5 -8dce5f9adadcd74ac898508dfb8d5c9e0af5c97bd7b7e4eda7530888edc3c3185b76912c784b50e94b068d8e89e5b3f3 -847e13a166ce6a3c5603534740e63846f8678f56a821c584aefa5fe8c6b329ae1c8733925e411265f4e22b766c04876f -b45235563058e9ab8b60d18ee419a5273eea074946a36128b04e2e6fda9c0fd4a757dc38a8fb66f95c4142f632f30b4c -afad39b4e71b1fee0e5638d8f1b451e46fc3b061f8567ba00dabbbfab4186dc35aa05718a67aada68398b1ce55344d21 -86ef83fba1207e07938905d71ac982a65f1d9c07b1dfdb353f8cf3cbb4d029d404fac9a469615e9516aa70f76d95ffb5 -a5d82ee7a0c78e86591ed6014ba357bc99d3c8f8055381e60635b26ff4c7d5d3a7647c123b2dcff3af0bec938bac00a1 -985ea179034ccc69e5e967ff6dd75736a65d75e3dcc0025ce77b601d88c71d2c83f714958cddc71855095eded030554b -96fae05c8ce05803693e0f7d26d9a22a6fe84a288b0d6ab9510105165af7fcd22329324dc4bc4a8fe0cbd12e112bdb8a -85f57814cdeec2c2058fc3775f9523d524e08628d0e26873eab34d50e6a6f85259286b869dbefce4fb52708828938225 -a0356a83491292ec1fdb3b52be3fb3d93736665b7890f0faeeb801ae9d7a5155c454b802b8053b684a283b5e2228df49 -b5e65a53da86fd205a5b08b0cde0651bc501dafc2a2cfd41cda2c1c832f40c104fbdeec19351bf2a64f2a0d924447b7c -a6f1bb7b1be8a1da4b959ab89c1ca55507c8aca491dc0e4426574413797df1172b06bf81b2f8ad6d151274123a4970f5 -8731989df4554d1b01d3f4368e34d7a847db33999e1b539076410956241b66f64769b918a64007bff8c0e79d965074cd -828f899705e275454b0e0c8ca03b28c0b29a553b386475e8145ee82e7e52df5c40935b2e7043aa5884c72d82398dcbe1 -ab76d40137e655f19bf82523a8eb41217f36e3e06465defdf7cb85f3441e68632ff80cdcebdd7e32d2dce1d1f4944fb7 -b199ab7264618de46abe65a38958b04837ba0f09f142c32df13ebfcb6d744b2e44190e5a75f55ea8823c6f24432ded75 -8d29e36142521a5698358e1d493a0f7050540b7b9d9ed4189e9e49cb209fd35d4376c7c775e845b05b6e76ae1e0b753b -a74827a37dd70e170652a8419bc9c764fa5865c28b82a8da32bb0204ecbdfe6937fd12c358a1cf84ac5105d65fa18491 -87d8858eb200cf06cd79d0b40f6070a39cc068f0545003d58715801e6235764bef83dc1ab5172456ed62dacdb3822446 -833cdb0c49295457f0ebc2d0cb8529dfdcfdb374aad5d795e9269b329a3f42080c4ca6c6bd67c26112bf353af5e4cb48 -a6ae76017f72854535b900fc1b65c66d664b5116adff8ac5c98f4ce608394322fb1a55bd6b0d0a2a48cbcfad0088e44f -b4b8e550e34f4dfda5a9a4728a9e98df7abeda2d98f59d2d669f6f2fef67ccc3cd84338df86246ccc3265baa33374da5 -83df0f4a96b738a4c7ba953383796e4104f91161e277c75929b868bb46ed7ebd6f11486a538198a79c5d968beecbb80a -8bf116bf11a6cd50f64658c91fe70d87037c26737dc27c6b2e847f58ae68c80c5e18051a052855285b4aea6a2c59aa0a -94282145933642e11dde303fdf0a3acc7efcda93d690ea1101e214668b32880f60b166b82857f226903c4035d0ddcba9 -87a386acadccf0657775291b3535c5feeeb8b539ed87f271649ad86dc4d627373004511cf5b992d32d0547f78767d59d -a2ae82489beeb713b2ccfb18864e3d1360a41245d11d5e0540167a4c99c786040af5634f54a8e932573491cfdaf12e4b -8155252708565223b5b16912ab6a3065074250fbed4531f00103ddfe70f503d6e44fb2840890d7e08f7a43163bdd6bd4 -8bc06269ca1c01887411a3f56093adf42f457eaa4cf71c2aed68d93cf33724551fbed7eb7eb6d9e175958261c3320802 -b56dea9e21465d07333950947a5ee834b4b65ec915484f6d3a1aa1fa139f590da063258bf836872170a7135ab77cb544 -b4814a15ca0e84fe0e227580d257b6928d486fbafb119c2637886cc5b1880c9f32873ef86d67994676f06ce5a370508a -a966818554b445a5160a4a85f645451d410743e5d760e8773bbd48d696a6812086ea4cb04f4560118c3abdcc25d48c3d -9487d339acaf52f6e9f4030c27aeb1de03973f8fd2f22261e52cd1639dfab125d2452907401baa2a3c8cd478a6d96f31 -b637ad911c7fe2df1415a0ca46c5d89c3c565e45326c11e1d2cb7ec0b6de4f3979005885f686a26949f92e07b872aa17 -8515e583b2c9306e200d45bd463eaf6b0825eb8305ccc94f0df3c0e4358d16f2e74ab6f38c4e41369688d10ee773c5cd -814d548f00c441a998924ee541e9aa6c7446d671dd5903d9bda4423d0e0bfbcc17a60d67d8dda5e996aa58bdbac3f286 -82b06475ede16ca133f51f7134543f04d785ded9fd7ead6bdbe06a88640a7eb938237739ae0c25f7d7d31a4dedba348f -914e544da2241f4f20e6423e71ea9d61faae3170470716828b1ba085c3add2524fe8b7fc829983f183df9eab93cf29a7 -84e7dedccff0096e76f1da10b7dab3751b5ae11ae064fb73fed166de0b443513bb5febcc9eaea70e6428f370ccc00cbc -953a96582c03ed199ccb8b6559d917e10b3fb68e26cd1d79c55d7170d47068bcc2ee99867455c7515bd39fb8aa65f559 -991b6bb0d1c38454b66df5fd994f1f7e64c86cbbfc1e1fa9cefe43a3abb99d587ccfaa3917d7d17663d666ebf132b208 -a53c895486d4f1aa1ea51ec40480af48b605a793bbc744972bda0dac7537e34209823e7a209054b55baf72a04875cc46 -af2a939b6a1fa9c72a3f17b924e8aa79f30dd31e885a019429112bae06bd1ad1161d4e8e637d195a1f3f58021900215f -923c825c417049b5e54387d6b2a54cfaef5b2b3e5670e365345143c5fde7e2e7a97d6a44d46a508fdc5cc2e380342271 -85fb356bf1cd8608f37b1345af5a3989772eb2ff57d246902591e3ca7cee4ec4bf3404887e48ed6bb665865edeba133d -91f62dcb8f551ae315fbd364170ef5416e91dcb7608e4ed843304b7c43ee88f4d8dc83cfa17b864bb3905c6ea66e8796 -8bde8af0e6946e8c3e374246fb8a411c1c5d60be7de0183c4904eead260fcb928043bc7eaff317909596be4eb1eada53 -b5b356d98dbcad6631a9880536c2fd2865457f12771c5c93cf8f50e833515ab170ae90ca88132596bfca4ffc8663cd3f -970fa9633dc4326cc46e338d9cc33a3342a48ca7ed37f08e4212ebd2654d550cd49e6cd4e4c9c81bdfe790f784fc7ef3 -a6853617e34061b2a7343f66562752412f6536be4d2dbc0d497feb1d8c433e3b97ed733f0ef7ae3bea8d19947258382f -a9e0b9cfd54f565fa5338add602cf42a6f29df615c10f6411f071735a20c528be78cda5ff0a00c42ca995a02b83db048 -82b04be368041c9cfa86388159b7e3251e69de821ca812499f6c3a5b4617f6f7405716a55796ecfebce1eea91030c648 -a1de66607ae339df3ac0663c17f886fbbb3d171b4409261c6f6ba6393eb7d02c8d411501328092862697b0bdf6049209 -a3c87f4b678dabc307a13a3db0399068ce6c5911741c15626859b33a98f8890a9d6b369f9c2b0915b72dfa3df66f6865 -afbb00da7cc05ecb3b0f3541e95fdffe7cdced5fe7534d7a0baa1231ff108f3eac91081d74f2c34153f9415c75989f5c -a6d5d93bf144bf242f87587d24c75e031311a9783a9626dc4bcddc0f5f2ad9aa481957dd34ca8ec1fe5bea6900577ba3 -850b02856ab59ca4647d58610856d945cc91b9e552b2ca0f177198eafbc7f27304ffab5601e5478c0d74b7a1923f7d06 -8709938390a6f908e5da062db82db283eeb4088b5dcbc9d98a85e70bd70f6e31a3bd9b4942dc8a784ce0e414dcd1f3eb -b6ddf34b458ec683512b64d836a232b8922c3b636b73641186a086238cadd2800682899e51574b1cf6bea6fe3bdbb031 -99e61922cf2af203c20ae7d1c257d4a537d4090a88638acceb0643c52bd6324844a800338e758ce76e5af21465635a75 -a398a441646b0cb0da2a981f3dc328a2dab3bc30d4b1b2631fca87b4876376d77284588a95a3253b449058000e9487fd -89af46bc559c9a1774c50bd52f19eff4a8912b368c2c07f16ec4842fc99c453bddc819604f9224c11433c87c018b8451 -ab79ca2bd57f367ac093096c2253e50f2b89e830d1d03fc54611dcb53b6cd43a17333cba1e8ec71c3c686a72ab57fe12 -8a1bb874c06309d9b955153850b3d7ade8438897a664a7d060366aa41415081b4d62853217115339dff7218777fa3764 -b9ab9b63f9de036956aba49e2b7ef84ecfd01e7e38141ee455d9dd40266e5d20f23c354ebfcc584d8d522a3139492872 -b21ffbf10b8cb1cd407ffaa0698083b23400648cd8261ad8ead00546e29aa4f31d2fe57faf03fbf82cdb580c6c68a822 -8fff4fb6964c648ba78e253717c12bc456b20d9592720d484e61bdd6fab86cef2a05c2753b19bde2fa34e48c5c6bebd5 -b15e375b81351549d84bc2ae0b15c5d533714caac8cd95af204192871b0e64a973b0f1eb43b00f277f5ae886ccb759f7 -b41b4335c44610752c02719fdea71d1a9afb55ed3f9525aa59c5fd5b34516d1d59f55627f3fbca6fff2d51247ec63b55 -9a003a004719cf96cdebb9da4e7e873e06c5a6917c88101a41812bd1e454bed7c6fe5c3bad0c91694e687ebb940e09e3 -8c4c051cd89d768f292ddd63cef95ce981185b2eaa6b00881dc4e2d4575a27585216151177bd3c89b0768eafaac0f314 -b5175f65864201d28304b6dffd1afe1e2bf6927a6e7ee7c2a72b33fdbceee6e8f038865aa0792f3497957ff0706f4368 -934c87e853a48ee9d972c598a869f0fad72e8aa08f9417a610de42e271b596b94799e3964a293050bbec68acf032a4a2 -8366feeab4b7e9d76981a2f339af9f2bb5fbdacc9d8f42ae5c9f35e3fb3a0682afba1409892855b06fd844f23de3fa95 -a7f37245d59907265403faebde6744a7e49900720622942e1807600eb12e30922fa2f31bae169ce03a03734f8140b0f6 -936b72ed53cff2899bc4a3a1f4b89b5952464ca2a392a743a57f32196b74b3ee3e2730298f927fc82344b5f7868f1106 -856c52396d73cff6fe3163c8e6a9df3edae08fffdabe613a6c7b571251b033f96e9ed537563a50a1e1269d94bca4151c -b2752a0fde47d105e961271f7a7721d6c00b05b450b9139776fa3cda88b5a823011d3f94e466aa245bf6ec65268a4c3c -b68de7ee49a342d05d081269c326dab75effca2640a4a8e4137187b17a2fadb9932f20005550abbe6b5ef7920cb80913 -aeda9b96b866e17ccda3c776925526ecebedb56df894ee4ba42a7175333c28bd3647e346b0be48151646422108322eb1 -810d6c783ce2b123deaf084b9a83474289e2b5f27f25375367f152662698a90076a3e0547e2cb2f5ce55d435bd6d8e17 -ac9d3ee378e6bc72b0ce27850e6785d3cd2a0eccfc58f9c1a57674b74145df788a8945a25a9bfcb9d92ebbfe3542a862 -b6b4add36e2833ee62c6e3af170ab98499c78393bf0d9a2c20ce90c084f6fb40d194c144e36e0ad858fe04652244d196 -aacdba3f33391a6d77717dee3b657b8d9b1959f0ed69086051085213b5568319e92a7e2f4244c8b1d08a49607fc2e785 -9612d7354ea9d498d084cfcb16f40448a41f9fbc8577f9019484f5e5f132c906516968df88683736e3be9ea56ad307df -983ab9562091c6c22d679c490ec87d509284184282d88bd595d0654656fdcafb990b94686a1c78d9b3401152318e24b3 -b26da8843d02ae4d7e85eded2a14ef42ce8c9ed8de537ad71918ff904200125ba5a9dc6dbf91d88a55459c583f6a0c51 -ab1ff878d5b63be94b33bd2a020be63c2224ff2d9f280384a736165917292951b44941d897e5931642b5cd515d0bb21b -a81e4ebe87d8c1e3a7da09859da87f5a41040a288246568523b289b4f462f2dae1ac2c98b73566fa5af64c45d9a38f12 -93a09c17764c560deaee921d7c4d201244e07b2e29144ccda36897807affb915ad8cdfd552508973a7e85443315bf185 -8a0bc818074f839e7c0f8ee790c558b7cd2b7a5fa2579e558de8e8e7e24f58a249993802cbd41e592577ba4bd33a8d4e -841f3155709332ed0ca4de91f0785f544e97108df112b8242d418ed3bff63291b8a6441e44b03d0fc4db311ca657bc6f -82eaa6dc58e10042585e49c981ecd01f8b4c56ef40cc40b834841d7c786e73fa64cce3b49c0f08ea425c3ca578d5facf -b2914ff2d76c214039bfc251371de379cf845f2c554136063af259975a20e3a879b4d7b953f2e6077cd55aa1663562a9 -826f7f3d2e018b7afebe844822045b075801cb3336fac15267de78c4955651c6b5108169edece60ff0d79e2811804ad2 -92a335d7a69589aa8a6746a4b79ac6ba7dc0ff2e4a39138520139b2226abe993add64dd021336191eeffe2320c01b806 -8769450d7a06b03687d851ff4af7633d813763364804f1f282f887538e9dd8b73b8f9beea842e801702f3a35b47cb007 -8bb1f1a0e4928afdb3d0573f0961bb5baf9b0d8c5774d72fb47b9c7bf498b54c7ee313849929291caca0bbe8d84956e1 -96aa07703e73cfe7a07495e606f232eb979d43136b45dc09a113b9118fb60f3aa87fe262863d06e29450f1d5986c14ce -954b63e620202bf53f7a218a8d85b4d002b10260312945f476e6cb418a061abfd6609d8fffa9a74ceee974144c2c6a3d -a5bbd89697ade42f596923479cc31d48baa0ac2114c6d8f81e9c57e14e6d560d13d594eec7cf41978bc973f430155ad9 -9438a12e32aa515510b99bb1b1dc498399dd73738f3e43693bc1d8904a48cc21cc12e465c020e89d60f1be97635cd46b -a31704645fb8c1c10b356883df2ddb170c94eefc124ce0a6b52952eadc9c7c58103d8a6783b9f63dc436809534686156 -a578b4603526bfe2ced9b3d33ddd105f1b13515f14e4b64ba86cdaafbe8e72e8d541174c6ff8f10eb3a0fdc14ef0fb87 -8190e840190cec3180eccacc18a06c64ec2c10cad9c0e5bbd4d8b33ce5f92c7aa48bdab7f16cc9fdb59b485d5a8feb19 -880a7eb87c08bb9919c26143b77dd02009274eeb872dd4d2afd1a0ca9bc16d883f5750af1b8df2b385955574560a9d35 -b02c6def10ca7e11ddc6b4f7ee82e8a71770b096aa4471f34f3be7984795c518b1b0993b3a95c240fb2d8b3009ebbb9c -8dab9465b51613a08aca9dd5ed89724dc621cffbe854180c9fc349186ef43522cda30aeaf3bba2257ea0dc1c44e9d0b5 -94c4b590eda9644d443e1f5bd2a9882f5607b5ec02422b0f0a122d39272532dbaa64955ab85fc624fb1632911942cf98 -8e28830d75e787daba69971fb7c8908d9fe9a1e10d8c5680d69b2bfb5075a2400f490701725c2630e9d257f6bb661a93 -b4e4a18c10163c0d48beead3abebfa11e2de9b7a4fedf2ef9bcee3833858169bd4028bf70920ac8072a2646d6d3676e5 -a5ee5938e1e660245ceb17694b0f78af5072bdea8cfdbe91ab2ed82a172e8f98542befa934d4893e16c280e9252e17f0 -989182ea9a6505746fd56ab54db1f52536e820cc4aad5c680539f74fce835611afd72a893b9a01c91ee1432dbcaafab4 -a810d9b591c63561f91e50e81dd9ba78f25cf6e11937e9ef71b82953d8420292048f72d4efece0819cd1251bf2acc080 -9199465d63d8534a815c9dc600fe0a947fb46ab729f8d967dd4c74f7ef5f5828c2fc9b025f016387e5cabaccb20cf459 -b4c7c7708469c8cefebf1533958bf9287bfa68319a2a5dd8b4b80de5838b6e8ff48a35abe0bdc441ac747f62d8a5e889 -a2fd761a066d5aba3cbac530dc74b061733dc7fd1164741729194c324a4909fc337dedbd8cc6233d81977e16b073533d -896ac094f7bc7616865a02dd345fcd515ad401ab7431d2db8559747abdb8dac8783e932f6615e70ffedbd0a192497935 -962418805a1540fcb471261263c8131ea4852e5743cb55cd389dd41a2bcc7d7cbfc66a7409ec2027f065aeabdb6a0c68 -91cd3c9c042e447074a4e81788a9e928498dceb4582afe96d7eb2aeda813ff5505863bf4c22342bbae3766dc5c76a4dc -8f9bef4d010df67a3a6273e81fbd82c4b684047ab644bad7d075cee39a2b110b6bbbf66be37de53bb3ef737cf384ad9b -b172457ba38a5049fd435cfda214bd886b73507e8f1e4f11244bb04abb1ca03111efa7bb0120d2d077bbdfe47979c418 -8ea5b73050aef2c83a1ca89285fa2f97fef3c154561e0e14970e7d3f64376590467e12f6a7756f92f5a56bbc62601a37 -8f211ff10056a4969916eb42e03cb804ab827c8a6acd65e9c2ceea50619e3c2a4c251a0ed20aab4231ec24c43095a227 -b6a5304eaa1971a291e029a0c745e509fe9e2972ee8767c0f6ea1dbdef74e949bad4f58300db49bde7db51847715fd90 -a75276fbd3a4c1cd7741976c3322d850e205077100309d8ecd9a75a37e7cb98502d0a1825c475873761c688d97bf44c4 -b1508cc9de8bb9b4a1ad1c3043ea010e484a47a800c0a0d89c5b1ce48408d8b0cc4ee9a53854e747695ece98998d6020 -b0bd8615cec78ed275af10f8f07862d46df627f2eabdaf8e2c0edffaa84bb65dc9694ebf6aa203fb046879ce7914dfa8 -960f0e7eaaa59c7b6d56e45a28fb70ff7af88f5e1c0f18df60991210b053ab9b266abc08632eedf3d2bb9220da794e7d -8ed015d0b5f0572e034793fb7c4c95a0bcbae5a37535839dbf95c963d7b42bc4f3b77c57942b1b9ebbd3992b4d2a69d6 -83374eb9a0737a0e5044427ae20e69626b23376bd384d668327f5f94f4b6434e8b9b3cd474631d3173960562f5bf6489 -981191b111c84522a203da8e70d4e6705511760c1b2eba4f2dc7d26539aa3e78848d3910b89cec357ef00eb7bff538a0 -8f1fab82483781b0a074cffd02c31a5f2587e4501e013f41ab4cc4c82a03daf6d2f60ffba4b19013247dcef3a95700ee -82148cf05f1bb1a6d6f359fe3fd50bac49d4ead747972a74665fb5f98e494b57c36574b4ad888cc145ae2f303bda04fc -aaa1aff56f4edc7e8c418497133d3d1e46553e9af968288d357a9ac371c60a11d69329081888bb6e4b107c3d889cafab -b8524852cc0d960f55b1bc2522582b6e8babd030eda069f1007ab239ceacf9ffa71843f65f13d44eeb545690596ba98a -a5c548510e4748240e3fc16eea453460a6e79550dceb1b4915494706deff4b5a81c85ce0e671417596b94ccec433f903 -8b811108269365c612cf79cae9fe5bef5f26723779d65c9d691a49fd5dc2c4d0dd03abf306870b968a17f2d844a84c92 -838dada292006a290e595809dc7c90a1cbf30ef86584130a6aaa684a5345db729f23c37804a2c53d1fee7ffe98f2cdf9 -a07b85a33de86da460288517a4edac0ad8c90d1b345f94bd865267aec70afce7105fd3a6cc8c5a46fe597ea12e159c3f -a4c7686a5f089cb3c22220381050e241b3108078fb25d1f76f9df3ff047d939c29c7817717a9043582d870ccb966157c -845efc33d77bad49de56a86db8e49ec9d7b63be4846df0f8ecff24cdf2d483eef175fc4b86697aa4fb9ae13e50d34bb8 -b07218c43d7dba8f3828164e45d95a2145982086fd50cc25e020192f5f06fcacfebeca6800af122391361d91b5c9b289 -8ca01a848cf2c4a8d2494c3676df2ef21a493b302ef07eb91f35c86a037bd257115431cd2479b238d3e6704765783b39 -b888fce4d308100b80db530f77b6fa05aae79d5ab37424503b067e1645c6726ca853ecf464159afe5c21e2a644e7fa88 -894ef8a8981904bfb3bd52cc542bda628e4753afaa49715fbcd8e71416748fb3ac0c3a58dd99ad92a53846c057885c21 -84fa13dc2f74525c5608236ce203a725a6012377816217570f11f49c07cf0805bd65d07a3a3b04ac3f0216c08be03f3e -994fd004f24f7a25602dfd673ff0de7d25e0f8bfb610a51ea1f5f53d62744ea13e35e07f1ca148eceb0fe5046e8ba6c5 -99d9172b43c5c3e4373839a8750eec2d9d116947d201afd3489bc756033a4653439dbcf2bc17c4b6f89d5f3b755938fc -8c48ed35c377bee84d981b639fe51384dbde6aa9d233338bc67576e80fb3295c7680a1360e80d4849db15e1e6c96c177 -acb66cabaf2f1195a971ea6f541966daecb14f6b38a4b14aea1d533126c619f47a578cb0b0140c83c4584aebc6a5f7e9 -af8b47dd0a428ad4e8bbfa79ca4df5acdc09788bfa577eee3fd7d9340dea40cc3eefe0317cda42081cd6758145b23607 -912241030685892c0a0f7b506af2e91770c5d46801e67762290546317060efc97a01974a0891c7d80016d3c981e1a33b -800a3847c01658e9254994c7c2e4cdfcefda1dc343b44e33a614db4fe4291bb69daf52706764eed00afb62c765548742 -93e4b46ff582300334088a34ac79f04ba952594b37dd600ee1d98def5f9f68c6104c61ac068b52e58d8018715e973909 -8e7405ee05a43ffccb09362448364895e366e6cc44b487c4387785a43db294d1d4d30ad5ad0586e9634e5307d3ce59d4 -a9945e23d916e8a91ade76764f3c8e82e0e84cdc75bb00fee29349a1d458d818139175e6bbb37431b10e89e1cabd62f9 -921503ad71f7b5bde9543deebcb26ef07ddd80de728c1430ae6e65fcd77f58ab3bfd96c5bd5896b299c6539786eaf703 -a1eccbcef6078dbbe4efe50d9165e6422efedcda8ce6e034159687fc4048df9a3b9b2ff0bbd064921213b8e3b9e1c171 -b26e68c4bb858c8abf57639883cc5d3361fdf65b46deb9dd072470e881fdbbc3d5ace4526bd78ee54302604b3e7588e7 -aefbc139edf03596be101473129b27d0f8dc0e3de3c0a7a15860c461f07be21b6a5ab64e6c4d02292b3dec6bc906e1ec -b01e5628810d4954d47295436d4eae0b7a2342158ffcf39dd9d0cc3aec88fb8f60f7ea28715598a3f84cf74d7db21ce2 -a08503d0b996dd7ad60698f53c2897678f427e3f73f94676339cdce01a878a412d49c8ac30e07ec401563498aec4193f -a5f0d9ab071d520d5581c8d27020c36427a8510e0a5cd3ebf4facb5b23a086d0e16075c25cb27a76ea3c33b66b801043 -aafa15fa92e0541830838049b172d51589926d46ce332b0b4842762bbdd5d34ef08542ecfc300334cc04ecb3079da726 -8297a2f4fe289e80197f37a6c470b53b4ebb7b981edca05f794cde9f99118e18a351e7cc545dc4297adeab7f98ccfd1f -952628464ba502253f7c65baf8d9846b643bc6d2e2063d9950cebc4f038a5cb3b8ca6de03696ecdf5b4a8b29c8e71673 -89970155c803cc2c40afd62772385d013be58840dc83c707534d045af75eb74f23b8677e76425209dcd7eceed7dfaf1f -90b8d942f2989392f4844b50bca7db21e76f9ea5203909a96ee344a780934e5edf1f93ca986c90e489844e87dd0d757d -83f524793024a8e74c49a62218beaf7c9cbd0f19bc846da048063590e358f1d7f08fb5eac4967f45e91d618f7aee389c -957dfa91c79b987eb2f841b60fcaa6bd2a068b822031e812ca8aff521151d1cdeb182cfd73ae267f28cd5dd593172764 -a56c349794dc95dd8cdd6f46ab1af1320b7b930679d9ed7086de286d331166f97451bbb73c92d6cf8cf72eda9c9e81eb -af8a86cbb980cdbd1ab653f5cc520e446ec4281dde5fd2ba6d8c9b8f2a6b2752abab3ae114f05c5f83cccfe3e1ffd907 -b1f909066c8dc5dd144fd9072a2f98bcc5341f2423f213fcbd77ee3d175e0580f712e1849d6d0a93ee4761c0938b43ce -8a5bcd3d30ffa1f3cf3832ed95c9196412cce5b87d5489c7236e09ce753502fc282683edfeb89ce7f2cb9193e58f9a13 -a7d56d4a3829d79e346f37869492e98231b780a821b620708e604ca7cb44c54da9eb7e64257af8cfa29d748675b84ccd -9823c5101bf77d1bef4990eea5bf977d51bebdd065efabda6d9497eaa612fbb28e4442756b4f064b1dc404a4f526e062 -a306e649f4bb8c2fdfb2c4b4db44e5517d8f140d25f67116c70f4f5ba945bf2c6bd141c1d8c972ab97549ef76228b3a9 -b21a29d215eec2a859b4116830f3aa711385eed8f752b41bc0ae1a018ce26eca95d580cef66d482e1d93b9b13e4a0415 -9718ea189c371f7b5ec0bf0a7c021914222b0c0c097fed2abf1102b891fc9762447288d5b6e0540249844cfd6f8bc9d4 -97af54e990253d59462da44512dc9fdd827b19c33ef813897ac5c19eef81f826227ac9d5aad7592a55de2201e538aaa4 -94070ddc8ff58e7abe8f328bed1ff68ea40f2fd35f59a0177af230ccaa27dfc6de5aa1c355bb8f223a0729f253c8bd60 -a8ae193739dd68590c6013e6d39c7d1ff42b1ec7a23ac014e160fc6bb1f38921d52e9288eddb7a3c8f1e9e5d9fb54b4a -97f1a8b05f21174283618eb824f6869daaf307090944539cdcdb939f186a1f4b71a7804bd3e84e04e18ba785a843e9f4 -a59b4b3d7396f91cc5d2a0de81b64e392a4d9078068550cb604ab404155d0e9f7d9b24ff5312f77245ead90f84404812 -a91e9b1002feb8a1ed0428623dca3716824f912fb3ac8705de17347a3c3f958666d4a9c733f85f7c7889b0722f4d397e -8aa7e633c4302b2600102ff5be6ea69197912ba5c996281827ffa2dae626d004eb0e94ce6d2e56421d3b1b38f6c4f006 -a85bf62a088f01945fd9f106b66d05643d6e6dacddb1cb1a4862c4dc70ffee8658af000d59f14037121a255dd748acc6 -b89327857364e08e3282a7c3e1e948d5b471e7cc01c12363fe288a2288e14afda0f4f188d32c416bac0284956cac7d47 -a34419cf8c9e38cead5a4799fe9adfc5b163992857ffefdde31d4d3f7b78e1668f3c97a5983d8723a961b1c1d7a16953 -b3a759078c30c9daf097d4bda7e978a8c890b9500f448c9433a3a6a04a1fe602fa4f2f8579c835b308021ce9dfbacbd7 -adef01176472a6b1e7f754343431a6546e585154b9e1b8c8ad8b0931871915c4a1f4ea1191e97945935de8a20ad15935 -a5bf71db271304c3f7d45038af3edff9a8b46ca58bbe0148b613eaf10d0d9889f764fcdbe0d5c6679c60821a70e7218c -8631082f83a0425dfe7804e5353774d94f0aa7e9ea5b550496a467a9004d6f2077780731661cdc98bd1678010a355429 -b94bde69b5962235352aa8362534d81ffb7fc231a4bbb2e3b78d21dba6b4ca5803b03019e0ea1d1599e4fd3b0834d379 -b0ccab1c13e0433401e13ebfe2c40de50f52f64fedc0b40e21b8a16d454231741f37371231c0a71e25defdd27af4958d -ab39ba2f15003bf2301fac132672b30b8f9ba56914f735cf86e26d5b18b9ac21f9669e67c4d83603b9832b19355aabed -b40f050f37e61809d528d4c5d3bc1e49695e148bebabe1258db4ae87b0b3f867f96f89a536fd552d9387341f982268b0 -84cf939dcb36c06287aecae9af6c1f10b7af60b95d5fb6835cb24f3de00aa7d29b3a183d6b5142e51910bf870b7beb28 -b876413fddd2841c3bdc5f68dfa5e3474733980305ff3f1b23a9b4c79f8c21147c70b85756d84b7f90cd72d81fd619ca -86b94bd8b00d8c58d847888e5d3274ede565b7923c449eff6631c22e3287d129c43984e0830d5d4a56a161ab87b6ff0d -8fc42831627e6664e0069dae30a7745ba859990a796caac5b35da7bafb76cb3fe6d35c17f4fe18731b5557c80286e1ce -8fc1634581d595bd62a2056b9ffb0e1f192094adde9372c2c2c962104a03ada6a24375a90d841ab59612b143fd323be6 -99e8b7d5ffc168a6ed63210828445e5a1d0c92d0af838d68be18f8c1933c5eb3ca2b2de818ede8cd286d9601df807195 -8957b5411db6033291e4a4eb3c371b4a0d23e0cd32e3fce3223a18daeb6c6651ce52d3ef8e148231e4122ced19f622db -a953eafc61744c73850370bb3c668026ff7da4c6111225b19366ff47171602aa7e7b804a07d66d11a7f846a4e1220c9e -911ac05cd283720ba6c9823c4a6b0426863e6476cec90d04acd23bd70a836c3840c92c1c736fe3a00d228fff0740f5af -aa9971dfd2f849afd3f543790e88ab0a3564300fc92fbb2e6d07ab2a3924fbf823306e0e64a4e61c3a3c29b7cc763331 -873a07881327a1b7cd89adc4378d345eb7e7ca8b07183556efe14256fd80fe815b081e222eaf1ca999dbd127276782bf -a3abc764e38531b0faaa02d65b6d55fa5afe6718171c90b6881c62103a5f522aed8cebd9bc7646c22698bdf80766df3f -8dd398d1b545c53e760a317c5e8986d30be632274f844a7307693194f922c3b64c57d6962ea2a08c3d038638efe05c36 -afa3cd1d7fbcbc5457d01f8c81168e742ffce1eed1c0ba7214e71877e4b398616b61c72deaf2750dab561bebe362266b -a98301721ca2749b525eb7d9241c16369278ade01efdb3243177994ced890e85ac2866ee1edebb095a93c56f39343375 -900336e57bcbd83343e17044583d0d8554d4c30cd24a6d24b7c3ffab0937d73afb35b6fe0b6a62180089b066b1077504 -b4c301de41fa4eaa109953cdae91d7d7e07e99de6c24187d386c6b039712a6545e078dd10adee6537e9a3fca1a925449 -89f6ab5eb0e3b4d0a66f7f0e6d8be3b2a71c0bf17770223c986270b4abdd970dd15f38952280247dd5d7d8530f3aba07 -81363450b997a417b07bce8112e4bd8ceed7c2c926a41e7330bc932d8beaad97b3c9476624e42f51be94fe3a08d3b257 -87ad66a0cc4f47e7c67a768017c6d3ae7e2dcc79c45b62576e0c974fa996f1d8129ea61370b6c0fc96d57ae7f5ea7ee2 -b44fddfc8363a00d47e8b4a68610457363f0573f3334e91fad0fdd455f77b7ae53747771133f623179000e9754739197 -953ba496feea7aee5681bc6adcd94fec4c193b25d3c4e91475c2678dfe538798fbdbc3a2ac28b5fdb1d1245fc1694e8e -962366ceb249f563ef4c25b71d398fab8ab2390e530f287eddd35f36b40456ec7475070518d743496c3c81e82751ba54 -8d99237960349003e9af91465bf3a1f05b0bb07668c2fcaa6c117213fab7d9fea045d444df7847688e6f9ad86673263d -a0a7dd3b99b0081a89f75d07b62628836a2b8aabd0be7388148524f6c3e7f81f8c7667839200ff24db4662b0519f8849 -93905293e1b4bf83b693314495a3eba47db401f7454fe643300ecad40b5a7f95e4ce32ad3eb69321aa154d70e0bab49e -ab9418b844163d0a65f8bf5685bcd65c33cc05e8baf67d39b189ec11e6a5e35dbc6e308845a9bb87436ba31d4058f9d9 -90faa906332541a1e2c1c920d1a522794acc5322cad37fa77664b9a1a574dcd4ca11f8fd74fda5201ea9cd82f16f1cad -afb9e5f8252bd1c54afb3afc879653ba0353b911f4fe280049da34112c29f746a23a6602dea9854a8cdfd489dd2a8310 -97f5d30727e29a99c9293f24379d959cc12db68147c6bfd2c9c95c7ac900cf02cdc751dace8b14be742d56c98f987228 -855aeb6d1123a470a644494c31aca5d3fe2eac8fd46dd33596e75e08c6a8a9d7bdd2786b1b778ccea734ed66be31482d -a42086a41f49e5748b258fd1bbfcad7ea68b9be599dfd33af003e0ae367ae1dab1c4322c345dd6c4106e8baad3d4773c -b5818cd4a83b60d1cd3b217b54d40e10c95c786aaba40909e8e91dab2fd72bf60f245ff6e4e0eb6f33d6447bfb2b432d -a53c70bd904b5f0db90ef096774d2a9aa7bf7a804261b2145ff36586b7da97d4a060a9d053f44a4d786b0ed6591c71f6 -a30d2977551bcab52d1af1d76f1858d58d91e64a5f17c72041717921a104dbd79d16cd9bafb3caa7367f547db2bb7b5d -b69c7bf71a97af9032acb2729e0d1f3ef7f396584228eab2539aabbd249e5ebc072927dd2bccbed3497405e3191a92c0 -ad560e8ee9821d7f65e4b00cff74c9de653ee4d8d21d180bf576b1be9538576681c10fc3818b04619ff67f4eaf68d143 -a1c2fe8d19077a82921aee2ebe09ea9f9fefa03eb139d0332ba5c2d339305d9abc2f13a5fede869dece520a727b7180c -a27ed8b82d83ca7d811b77ad1ecd271d50e3a2424ffc21c799b96f5901fab7bb98d226c6152ef5d8ec09c00445014307 -b838327b3c0f94e61a75ae7a8d24dddb63ad4973dca7dab35ec5fea80b47dcf5315da38367565f45a079ef500a5f85b2 -8bad947099d91caf0d7000deb2f30d8de55e219c32a479a767d1d194c59b60a80acd67e352bf55dc69adeeaaef035fd9 -abb4e41d1cf53d678cac153371d59db1afd9558f4a57c0d194c2adb5510b074811dc2240e175311110bba4f7fe96cd1e -b775189bf863b8d9a0437d1eb4ee462223b6f577fe018e082b52b1150d4f9429a457768fb54aec43f3004650c7009371 -8cf5148e022bf824b9c109e3a7e6ea3f9e18c697ca9f0c87f14dbc83292eb9be6d3be63196d876c43f351080d22a2f4c -a7fd5701ab8a86b22a564021d1a9c64f0950fc2d9d73da4760256741b9a1d38ece6aa6b09c4fae79ddefb9c7ca2124ab -85f334609d8f2e1aaa90f9ec2fd3284998cb1863ce9f74242311c575dea8119367f3a3fbfa8261188358269ad2f2474d -8aee9698351034bfc8256e465d4a0a9516858aa9cd78417d80d99eb85ae1516847f1bd3b1b0dc935a1228f704136339b -a8b657811da7af90d6adcb6a593f7e393dbea46a88fbdfe9aff1c5b3e6b71a2a15054e4bf237bfa74268c0828175dee6 -ad8eaec222113d1b25d70eb2d72aac43e42a7d706ce6ed5539e10566944dfe912e640398e34efd63b0dc8f4d3c90f417 -91cc05b426252ac6ad46fbbd55839d6f18489c70a9f1374006e80f49fad3458f7a6ee7d48292e42e38ac5206afcb6c35 -8566a697b01b14ad3d7f3106c1a77aead26b5ea8386ef481c486f5d915cbb6f5d6b6d82a8f73e025dca9dcd914aa07f2 -85c0074220d7ac0b95156227a00e28c3024ef7d5c2f28c384ea8392dd6b8cb10f2ea08c3f2a39f08f12cbc2d68127411 -985f1f49789055455b15d3fae87118b2ae523870c713a03b0c1ab585225638133d39c1918e8bf3ffeda8dfa90809996a -8933711c45b67084e34323238dbdb6b4a7e950574c751ace651e754821066b52b268516ea15d7627d2a8cb6179dee242 -b18d7dd71e7c3e3eb30f5d817c146623384da271e9db8cd93b0a1de990b57779542a80d0d46038a395c1eedf68ec0462 -a746f6a923a2bc6e8ad72281e1a5f2e8fadfb232c60c910bd4a06248ea9f9cdbe14728dbe36a01bece004fde28084078 -8c3929457fab0b88496bb9936c2cec7a536528b52a81037bb24c0b2a4f92b24e49d18d05fb4b4b561c99ff0886eac714 -a31fc840766f6ca8d71cdeb48ae96f810bc93d1391d2260464aa01636ceceb9fc8b7fb04069bc323971779a149f1bf4f -aacc984cb1050c46062cf66235ac63eed0f6aae5e5856d14e8a7d2f2b0e0b6a2c8b02c524d087812f9284e70a307a6d9 -a2f56c851597a137271ccd1404234788b9b8fb4658d86a7cf52d1853d06d59e529f7b590662e03fa10b2d7337fba4358 -b0706daf17e5d489b38fe3ece28446f611e935cadc0afed74ca351477e865f01e7c2b981874d20a1e2088be907fcf3ff -b2ccb9e6a8425d24b1fc8e9393783052772a797284f20ab5fcb0488bbdf3b2bc0d3e7ee1de50c640b2a1331f1ade7bf5 -a311e9a137a00968ed5710553c4e2e6b750b363138b4ec4d8ca64f69724c172254bb388597ddb541af4d60b3230f8b35 -92917cc9b65ecfcc58300780683352ee53e9d97f9c80e6957f2f33eb5715f338c248df91734a5ae311b927810de8c5f3 -b4848cc6950f2f6cf72a29512e0c5aa4809f92dd23052ded771c0d0f5983b9f1e757a3dad0d0f9367f4d7dc959143d07 -b137cd32f617aea12399b96732508a98b9fed9ee1826234b609809b8b6de78caea3efb9b2a02345ec6cd858f29be04f2 -ad50d176a8ed5880bf789808af9e1f644818692c42830035a0de1f2e84f05314540f26b131d620ee3ff06e5520018ccd -a0a8b45da6ddb4ae76fa0d3b3e41c1a0c25e608d44db764653fc9ae386e31f21fc0e3f5d25c3d51acd6a29606809c497 -99169f72682034eb4159181ed7b06dd9d22b92f191b71a9fc1b1a2ab1f1dd1de81b146566824a2ccb82e963f8cdae939 -954da96017ebdb49ad8e37d0232772272e117b011f8f27cce61df875e40ddc020df7e13202b0bcf41de1b7a70f696f71 -b237224c78c3603bd96afdff5c18df4f34394c5ac6e9f9464a02c9ffe05d336b7c99e774c1c90741d9a578d31b330db6 -ac9acc3b3aca921cac56262c2cee12838d7a0fd0a6591a3608ee0dd125f4089e9e20341aa30dfff2b350c3e731e84c03 -9736965b0a62f6de4d7afa08f73eee59d13207be3a8d6172a9afb8634708ffb4f3b57d435be1d46d129e67f7484b36ee -b66b26ebf416dd77533dd99b0b56eae07acf5ee1d25601c86273eada15125909aeb3bf952dd6edf51f487b0e72b5e26a -92969a53a41c40bcec986bac33c93b5d9d5e2eb75da29de87d2bccfaa0b6e064f0569e6d5b073100dd337daa1e796cff -92bdfcd98d045e0382b824eb85a7c139ccbab610351c121742263c67019f33eb1a0610c7205c48a0d0b66ef4e0a74ed5 -8ccef40286790a5821bacb43e62f2587ca8a6a39b75e571aaf7b23bef9dec7baca7560568beb5c4c2b9f0e8c932cce62 -94a7df48ea09c5a9447e8ced51c2ace333f4faf4faafc9e3891c81fbd124ee91c24518d33d4eb9c098a39fb1b7924e20 -98a9104df26593e242f776a7ce01720060dba0aff25964a92386912917922e683b80c92f0ad05d2cc3220d6776a81463 -853339a66cd99d55649f871cbf04dc9470683a17dc146205710a68d4b6a2eb3c5b11ca90a01eaabee3570347d4df3de4 -b4e6ebcb474f2492b603254e40def81501795cdebc5f55f8da94997486e515258d8369418caf7b0cafcb78eb6d12eee9 -872db3827d863bf86b858d0eb5bbfaacc6720ddee05df3f7f71aabfef4f00c30ae232dca52d76189eed6b67e2b9bc459 -9774fcbb9cd74304c3300a577bf02a7abb217f8baef4ea9e2e093ad4671f668e9620293c5ab79c787d751959fef06d21 -898a464814bcf68bdbd1eca6f5135550e9f6269381d3a007b9af3d8635bc1deaf975cbcdc50b8bbc7b4250ea1a4fd913 -a9483156760e5716532e81405e332184a2861444a91408c9309ad2d602f04276ce55b6ab2c80110049e8d1fbf6454f99 -b2b849982a14f02a493e6d4f87dde41276e3c9052a5901ae1bee3d8fa038fc8bc3b9d6bf3fb32c72f4e71b877522fe58 -a1f4a0c2d733413e77a6bf3521bd14847f73d6407cf687cbd22c9ff0447bbd6cf55cc637cad66888f092787e044cb383 -8a52c63985ad65384ef4839c2ce610d6d929d012b905eade48ac21e0c64c7f24dd6344450426f5f2f9bed8e8883075b4 -80ecbeada5350d85619bbf3d3a3b0398e69bbbdda4033fea24bf7163fc281049622d8de2765aa33c77e01b241bee0067 -a51ce6fca804bb1115128117dcc222e2e47a2fe9231249f356be20ff31ffeff9b89743e1696a6fbf67cc1e45a5d2aaaa -8b18a22d9a1161a7da4351545680ed5588ed2d719f29fbe4b91f9dfcf80aaff745748692815afdc556b02421096a16ce -80315c2e9c749c9ed2b7087d734adcc953a77f8bf15a76c1e57856233608dac7b394b0cddfe8fefc7918ce2e4fdafa22 -abfb47e401e4cb394e5f8fcf505f1408cdedf35a5fc792d3f249ffc49b0cb4a127e36969b41d0e44fae5f99544f505c1 -878293f50097b562bcac669a84bf8a74fcb965d3c339982474edcaf9acffff8adc20693a050dcd84e738667a41de7ec0 -b9e9af496479e97f1abcdce1e32581139aa0d242d794b1203a235d89302bc8cceb02582307f9a8ef40957d2a819b526e -8eb026243b0c4cd00468b0664ff17c7dc5017fdb1ecbc32a2c69512c2e0c478820196e6a752a36ec44bcf079d0a30fff -93bc985a1f17977f887d95b9d4b9552b8749d7aaacc1dcb996149f98d0b1ad2d2b520c539d505f188056f4eafe960c4d -adc9ad21c21a59401da86ff91314f570fafc9a76408fdaba53431cfc4af68f004a3443f5459ddebc734d45388bd3e8b6 -a4931b824ac65f198466e8b9d0270820a0a652fca2478523c8d5ddbc65dca265bb8e33541398bdfbee08496db19d2cb1 -846b13341044f0b4d7a51feb8e443532cdbc31e55d7c6f3061b9322a3a139bdfe22753eb439aadc001ff8d038d3847a6 -8e8641eaa4b59f1d89ee862e090a72795323db84a44f713a2213bb35f24d0505e7f13eaf34b8af919a754996d4b7f747 -9394458456ed4f5394f686bdd2fcf1ce8da1d483c410ab8628d57d4a46ceb53bc7ce4a1422ae357e4f8168907efd95ea -88a7c22d3f6c1db89f41852d8e873e6cd8d50c819b56e1f8723ccb9f70cf58626a835f0d30c03f61c96065f32b79fa01 -ab88e29d278efc36c91da55acc1fdeed510294c7704b50fd78615af26c591b88a749f806b1232a5beceef89f6b6f65e0 -ab58fe1634e840ac91b7f2a67a128fc124058e9c01fd41c484f71c450b46336ade2d8af9859d2682f584bc80f3467f1a -afba6c6447e739fe6376ea0258cf7a5c7f6a0d9d3a1d9aaeefa674787659e49110ab71d4338eda00c01e742b8e8ca7f0 -aa311ef95246b2f40be0d4f841ca4940bf04234e3d14934353245617e025a35f2c67d7801520aa31ecb9664a9df992fc -ae1194dbce94654c8f4928ac572bc621fc95561bcd7471177ddac8e3afd06a3f6eb12c778e7e8d9a0f9f9d85b2e70c22 -8cc37148d715c7ddcc8cac2fab5be88e38c03e3eaa6664810f01dcdad534ebbcb2a4221c61980e7ba8f4a877a2a3b283 -a22a4ea30e67a7588ebf1e82b8b4a0ae62c84886298ce177de3d120a9209f38d77be5a500d796945f0eb121f4c3b4ac1 -a1e4c85a1052e114938ecd70798912a18d553c23d90097a5ab1aaec196fd219032a3e6233cabb4a400bf8a06fd3d7bef -b2a495d076e9989abc1d0d186125a41677a2130f5940c762ea96182607c79a911c041fcf7d1c48663ba6d7d5ed037d14 -b42042eb4d7228336ed9ba194b153d31592e68c2120d2a51841dfea91d18d8fd9d968f03adc451d902e73dd9dbef4ee9 -918363ef7aaf3b0055dc30638bd47dc6107e4e0bfe134321dc4ec55062dcf32367fe0a9567d5c9dfb89cae17f2901ddf -aebf3052052a34bd36910688a783ed7940cbfbfe0fb69d87fc1976cd0ae5b5b0e0474b6028d052fdd58bb26e5c1d3812 -ab77ce15ef809d5eb82957d6f8dfcb118993ab1f9c2fce0e341a8e277f0ce1f336009846151369e6be1dfe1e68145127 -aeb7f47254b2b4cb814a51138b16ab0321a1d4472a99bb25fd7bdb808c21cdf43c37b8bf14260c6a8a4e7f76d0628c3d -a94583221c9cc3493c1a67a9bdb928f87a41a4787522df84b20194ead596ba27cb4091ccd72cba0f5bd644cb3c166b6e -91e169c186529add07c3990113b9a6c4c7cb684e8caa182001d4d8befe81f1109e1e55f76560e899aae4b914c99e2a0d -aa05f0c1ad14f3e05ed82c9313b8fabba46c35e46992cdbbc6ac9b647125ae5b8cf99a61172fc69124929a47219512d2 -9583f86bae21e64079cd703d044e37b54a4ab02492ff6f79d3ab4c1b80e7ce30ef9c8d6b17b9755e936052e6d46158af -b95df374d147581ade4ab83fcc2e89022e4df13639c31892bb141371c9bc9adc3f8bcfda0dc474f79244d1280a44f4c2 -83b911218e01d15fb1b2d012bfe1c558e86733de9726421dd929ba47aeda3b94ec63adb41ced6d78d4043ee49f59ea91 -88c990898b0f45c3b33919199a25450e41b204e79960ac77cd71f4c25673dc0374176eae07a11a696bc7493743956465 -9938a99c2b85ebb08fb1647657d11e046f878411cfa04d46ca86a846ae22317e98784762c9d117d41deee6f271b235b4 -a7534a38d879eddb4d9e5c88ffafe5adc72e79a940e3bf4837fa1ac6beb8bfcecd535b121958949e1de0054067f52db3 -a960483f4f5bc1593fa633a4999bf26191b385c9666d34133f3a764fa1fee747f30859464c5817a8d57460c7010fc7a0 -8411dba8ca101a94227705aec3ed53e0c1bc8a643e5b4708b438146ab7acee480c399964f3f2d9bb69540bef7a007fed -992677e53aaeab9490b3532dd51279b9c7199f36027417d99ca7181812880b9b5cb202938e174c14615ca8c3de8d300c -834b29582edcf7c1f9c3ee4f8dd68124ac3e3dacf41e8f0982f942d337b80896ba89e5793dea39da48aaa3448704c16c -9543124834cd95958ed49bd4a3da93294237931be4866995832244f88323b8a6cfa7960722a08f0351c3a87637bcc00f -aca0fed5e4cf09deca026667c7b7a3e3ccfa0164e64aefdc79cda25bc687977350a3396265e2c057b6506f3252a11f99 -8a7b2e2422040ae70de5712849422ad2e0e329ac6a29a366d75cf2500f98e1e6d828d480e915431784b28e5601469535 -a32f15218bbacad0939b68c1499a875010e77e3ce32fe20897ea290b001c6d518aeac9c90bd0badbbddfa5b75148d70e -b46a8f7fd5806e1bf0ed6f9673712826558e22435fabeeecf9672843386807aceea61ad80323c0d0a7b0e3da8663453f -a8f47a839c746fff19b8ef7ac322f310940cf210f069d0677ad62ffbec5037014f27a9c5879256033e55410fbfad55ad -a23db24a1ef2fc67f72eb2a05860eac8c8e46e6b84f2ae8ff8c0fc2cce259dd84e33997638ec80a6167acda9a943fe39 -98076cad1074c54db0b34f1fa405632306c745c43ab96983377ec2f12400a6007395a35e31ae1b7b584e7b7f93242fe7 -8418abe5e3d7e33dced70e2967265a9fbbb947c2a8fd08696926e614685b52d872e0fd2605c042c4ae8a904d3f5db4bf -8993c52c291c0cacc11e5893953c6c40a714c651fbdaad303e46d0b9820572c3cab41ddec6293799a30acd244570fda6 -88bdcd39f1a87b5db320fd8d2f049e752da3c11d95e30a92117ec70653aab1d0d0b4e5f9d80f299cc73deecc73f7d1a8 -b4337eef3967d4b0534134484b2559b39f0eaaee39e5d2bc5f5f061fe58280bd727769c51a6faac003cd019d8e8957c7 -b8c4e705a021cf2d9ad691d4ffd70e5d9065288b2334aa4a656f1b544b94efb69e292fa3e577bd4afc09521cd233766d -846386ab374ccabf23a4c3b50c210c13021220485b6d63fd560c34fbcc0caa79224b18d2c6f393af72c411c2ebefc5e4 -a5c2aec8f5448348d7955e02d911e5299b48462cdb310d6a6b8fdd110af8bc0b19e8b5114c603f60797e1c49fa84d340 -aaaaad09d9304462c2a667c5d8ec0cfb69d74415611c28f0e63354f4659768e1fcafba4a4bc789c2ffe6d949a1df0673 -a88cd464b45e015fc3ccdf73cd9aa6e0f853adae85aa74f10491c77ee789013d9fea9728d4e093dff7d41f517678e1f2 -b0bd572c164fd55369b6f497ab08f92469f54efa7ab9a370e0267ab0407b342393a6dc1e254cd196ae8b3af87d6d470c -abd3dd91f6605ef4eb5c66744912c66d65c1195cd03d3567102081a8f6a9bb742a31777163cad0012d2e827c0df4e76d -b77105c960669db2bc7de180f8e2db6616bea6ef0579061e08042e9c3e51d223d4b54d775a0fca577d85bb3b5a16093a -a1a531788243b5aa5f13480e2cfb2b57c97560a1b4fdb99e96963c4f3f5a738aab34835b377ece2a97bb219d2e8d13c1 -a8254089ac3bf7fa2ed1d0488325bb9f5cb8eedb6cdb854f74b820ef3a5026685f4235c08e3c43a943e802d2e19edc99 -a1a4a71ea5dce7da4362e94475e73c4e3c0dc89e2a4ca7f99f417432fcd42f8fd7c729ce7622262d57d9397b55406d44 -a5114fcb6bb48d8acfc37c67bbd4e85eee31c04836347f860e349a33a6f3d986299f8cdfc130c01d51f387b603913f94 -b04258899536ae19827321b030f124687fce06ea637a471bf3316df7bab61f9b446bdfd4f06488a6808ee632483f74ea -b8cff2098ca286dcd5802bee95841dc437e8af076cc13eb7afc4a218ab947fe6ace914beb8fd423af5083dac972058e7 -a0db982bee635f0b4dfa2d71d3ad0e72d5e4b6ad67b5a840843231d18bd47fa2785caf87773fe864b0490b57fcbf0539 -b8bd5710bd99a87cb3e6a440adadbef75bce9674e3a311cc3042c229ae3b485e7253f8d51d6164100795778eb484001c -aa68c476cf5232978919a86fd21acb7f43c700bf7893922720b2c0fb1109bfb28e9acd39a355c667a93534dcd4022f2e -b9feb226d742029b5cdb88d10cd0bba4ec62e554554bb9724ac7852b5b720094fa48f76116204f0a7742e4b624a341ed -87635324242b17632f5a17b63527119288a96d00a66a536870bdbb380a183e3bb3aa72c4522a467f7a3f7b1078fecd79 -a99c340fe2fc95b6d171cee4f794d14d3517a949c59f05fd6d3412077ea596193cfb375f6899982f4944db6c1fd514ac -88da8e4fab1e171cd2d7784ab78e4e6b46a7e6ca3b74aa39a64a49579905112fe87ba03238b72f2335009c1dc9c00780 -a9a25e49c84ca64f2c61dae502be30f94409780bb2f8b560d9565ea7cfc98d6bffb7e47dbdbc5466e8e96eb4b8961d0b -a9a94096d3ee0408a633a4101a5363ba052d11ffe184b9ea9136929b6a1551a49b4a30c2c20da2c6ac67e9264d659f6d -8a732871fdc015dc35d31963b263c219dd9be7b0861199a08c1747d4c16eceb1e893faa7721fb21ab78aafb7b59af2ee -8152789d57b3e741a4261bce2daa128f33909d74ac233ca04aaa027b3606a6e2983790f5c8b65ff391103132378f4b97 -8cfbd04a6d6c1ebfdc64314e0d899e8426688fe72a6aa847a2189600381e23df277c083d5d97be115ff13558b8e0a067 -aef256705fba9ec76391a76e0e3a5ad3e034cdc5d289e5725055fdc9ab64ac39e76d1a8d617b499c5e8f98f903275e86 -9621c68aa5d362874572064b4b5d39e7398e8f1a98034f2a43685b9d4a0d6cc0a1df1c956faf0848369bd9781dec62ac -95f495261c2eacae60d4b4b14d5a418e00de331ac321ca9298ba126dc80c9b605d19af890c1c22304a12b617bdc75fbb -a89a3e5332462aa968b7bd5bf60579cd1fca1372878232f7e833568e43854361498f8c5122383575fb6a239732df5eb9 -a490ad4a0e78b9c498af6314eb59bc4e6a0929f602799f0ee3df29dbb68e90cf87b3956dda72b36a3f1cf93b376f509b -ae005b943c174e7e9261558be6510ff14d2d1305595fb377b230eba34115636d8fea55261677d39bdc4f1aa86ba4cd5e -90b826b68dd1adc48afa0bf168b7e748ce2d7c61fc474e841061dac2458d95d26953af9cea6b7129da87f0e204c60439 -a79ba549799a31fdc4454610a72fd40933de9b433944afece7743b60d69094d724b1573f198a77f33755a0353898fb56 -8d50f15ca4795b65614af28eb35e178f2b3041840a90aa5fdf21c8b9f32dc30c44fff05e6754672ec8e6b03fd3fd1492 -b89fb6cea79a7bfb1752e2c55365260c01ee1ee59f47d4813af422a7c916801ad0eaf3da12132f724f5df69bbff8c552 -b98edf63b77155e2be84fea6154dda6166372eccfae5512eff71b4cb01782f7039256685347553e462e76f42ee070c9f -b78b3e6ed58ed909fee1069b7b9561cd5a85991409b0893c7681ec009e7c01799341906e34613df36038a37aef181694 -8513fe1234d81214fe727ebe95aea5b879e8e44253b256b24aa1065490acf69c2f912705d2a41b46446061562c0b4e57 -8f4c9418ba3edd861d8a469113940aaacca6b7a7c284a18f7907f43fab8645fd59dd4758db57f31ae0cd37693f011ceb -82d41bd0c435409798c7fc9ff73e6c5ee1b65db94a224a22cc9f856697f2702beb450749b780d3dbb72544c17297d8c5 -9536399cd60b384362cad29b39ab6612d193146d68a967c79bce92e7693ebbf44a8bb8b13c57cbe38e35baa671f3879e -a4bb4c18b9d08ef81fa0bd1662dcb190d45e65a1c53dc96bf6c00dc20fdb289d798097aece4cd3266dc64cf3c86c9695 -a3f768e2a9b1f27fc113743f96f9167e064a28c9dd3ab0ec95a55b405d82ec6dba2f2cb3bfd8ab2a636e4ea268f3467b -a1d6976ee4ed285a4596cc7e84aa0c6cae21901d4550331c751b6319b466bc0cdfe2ad0e382819b8fd62c9cc3dc5f59a -acfa4b882343c1cf116048af0e21b91ad303d463019cb882491be205c8b2004f5a8c819e2f2db3d672f5c0838e0efc03 -8ee9a2c3cf12d864ffc45bce3a2892ee69d50bb6dc35e37495b69e25e71081fa26b14cca05defdb79ec0b76796d0a626 -b9b8008a9778da52657cd0bc8f27a655d9fde615f69037aceb8b1f535ea7f151e7a8d5291b7b85798d704af2491a3908 -94b3df07054728e622163ccbb200e8970ec1e2edd3c7fff3f9297d6119c7e557271a9364318dde606e98d5b637ca221e -a80e7d1d6237056413cb6379285704f3aa432c658a5cac2f09025809d97ae0a1606037005758bc8163722aadc56c95db -ab27f855c23a5cd24a4ebbb771545d4cb0514963ac165ad1213172155eead92b6a540354a91f61367efc9807a679958e -8e58eeafbaad541bbd7ba046d88940d8856f15a1dfd686347bdfe815fedb8d74f85b8aba243bb7d39c44f92c303495d3 -8975d8f6d1de1028ec744d61f25d9068358b0b18081e84e8a455023f2b620789fc3fed03f3276ea712f4d3e5cc180540 -b96a7d69810f963cf84b2ade95cb4a8fa9605c6b30d61c70ef4de9750259aa4c0a99c0e2de8039eb11fec98fb522f8c1 -8686bfb1072b0995772bc013ff84996017b7629d413f0f5506a47cb86f3a4dd5be4c0b2db6cc6f12d8d57c36cec35e87 -a7ab3a9e9a1d96c436ec06e6252aa88896e24b176c19612069c4fc28bb768a9ee624ff12ce7a4bea7ba1aa4a99cc87f5 -aa355aebf12ae1c737e17b7c066619327ed821d68d09a5dde2dea6e1fc833fafb1362ff24e4da109ebae8b858486acbc -82c6927f0238ceb5b3e07b2e7b7dd52f811add238420a34314a156a4abbfbc1aa0dfe3ad2fb7db6d01f7d47aa7973daa -a2d344ac3d4c963b7c4281b9e10c223b5e208eb76cbfb2c5ff436f37af4a39c7d9e14d9bdd6fd49fa21c6877edc722ac -96ffd354c3b8e1ba4eafdf9d5b7fe9c15c523233129f0cb4114cb671be16c8fcdf0354e09c3a0cc322367850b64272df -8d7199456755617c7d2f94f2ee1a59b9a097eaea4b379fd497e302b2a23981d5d213761ea0afdcd3cd107eb09b900c63 -92dbaa1f38999c82817d963933fb5fc9cc309da895f1c1a481ccbb2210b62855e2e021e6d119df8a39a7b0e6748b93c5 -805d545b4986cbdfdd0638884001ab103909e5204859192018180e0f55ffbe2ee6d86f9ebd6be3e76009836b3be75de3 -b17b2b0cb94620a93217deb34430e4f1c331bca272ce05088933406b6823b3ffda51125232e33a03d230f00e4db75cb0 -a4005b9706c21a0043922b9f8341b5a6efb77db6b3d3260887077735d6ac5c04eeecd7c738ba69655decc2f6a4110baa -b1320b58a52176bf6deba6f60cb30da9e2ce5815ccee503207afb6e70a7fd3fbceddc6133a90c3bc419d2e9148f6a1af -96f31693981425ac9ca46fb39b5159f43d2dcd38c001c95dd2b9138f78c2ef98e632986d961de76544792c0d4d0b4fbc -b1d01ea3234bdc2f92ca1ca9354cd3122a04255068edc386b66b0ca958e9b30f48de1a49e61714efaa276789c8c3d917 -987997835d6ba590ff402e0564e79855deb2c31e29241dc0d4f3a84d6416b8815708a0eaca9c8d0e9da9ca246d708d26 -8ba3eeea9e015def613543d6bdbbd917ac3859fa1b8ac2062e5616f575cbbc888bcac65f6b8d2f75dbcff0add39f7a21 -8e54360060695a2af4f8de39ca50f6455b91b0ad146daca7eb5d773fe2a99d50480bde665e8183f3e41183a39f72f141 -ab0dcd6ec9289d591ace4320c63bdaaf45a712c51e652308c2a3e9a33eaf6d5247b0ffb5b04b3fd0a43bb18e05a8542b -af96c7de7b16537f8730d189207a55283aed0d0aed39df9c02b774b796aea6f5c56b7bad6ddf4a33c48f7d98f63a1216 -a0428b0b467992b17a6a8a8eb5dbaaa9810e7eb3699ef0fa278df344c4926af02718daa0b6b528a77e3f980d8d99d605 -a9dd4edf04e040a2f12f9878704f5934a5a5823e72b8ca37322605da0f947b072b3b73657f56de4b89526057358b9512 -95127bb6bd207db0ade92404768b2874614f3ae33aad5da8685d3ab896f607238a21a7f3b9d8e7a09b2dfc16bceac6e4 -a7988372f4d47973dc7ef7cf15a3dd405b02da7c288656cbacfbf515af0cd43b972824993fb88ed8ec62b2fbe7de0b66 -a8e295d5a26874ed10a18f592e762c73c508ec32ea74f9c214c65e9e7018f37472e1c97f0d4bf865451cc7c59a7141fb -abda573fb81c9d890525c161b466c9ceccfccd29b5451a864f3feaa6f5d4e5d2cded27c06031469fda0e5a1a4396b698 -87741fa0563a75ab12f72030d4a18326b90104459c12cc0a775e5fe06590ee777284df6213dd9fe170cd972842265545 -ac084a5fea6e3bbc810d4534a83fd9ea6d603c5d68e4ba5674d792f222c1d055e5b8af0d21b19d174ef221ca77414505 -93bc255910c7812c41ac47eec728646e8385d5a53625664b669407ae0210b3b4209401886837eb157401e459ef485e59 -91f703d1a5ad97799c8306cc1c5df1ba227d7aeed401b6b7c3779cca64b54ad993dc6c7fb2d046a54c63a2e96be7f087 -8fb32c25a5a376ee0feb07ca2e2dd1c643680ee57b642bde6f6c25632e9b0d8ced0095d088e72ec5b8e5a2dcfcf2328a -8c2e7ee2279625da667ee24eb345915203d35e8913fa54fdabf341afa9ac336ba623fda82114c9a9d8f3a746d374cf81 -9470d790b0b0fc0db3dc1f9feefd7b37568be3a7657a4d91cede9622a7da7c90e0f961efe4f37d1efaf9f96bd4114f29 -8a4073e46b302448892ca2c64bd3a4ef40ee371ca987533a3ba86c355c88804ae108aeb7d1ec66098e4c4248a92c3500 -8d8bdd8cdf8d0365826806fa89671958af091ab04169c45d7cca6d4dabcc47febe3698896408820f4bb7f243772fb4f8 -af58744540ff1e86de1c5376e12dad7a841a929ba0951a1ee3dba678f6553323fee62c79aa6741671127344973f8d5a2 -959b21b4642e5b0035acc59f0ae64a25cdeefc436fdb02cea97625c1c6e147bcdd77c2555f2210f9e88eda6bdbc6ab08 -921e75d2e857d32933f518840da0b13c5f3b6fbfeeddbf3465433bdb30e506bf05e1b79706235b522f843c87936d9cc3 -b2e4cddc742b5bcf2e5ff783d3ac797b31514fc5ad8ac9b9baaf934445e665bee16345c01a4c04999520cd1c41567a7f -aa10650bfa5ce3328028abbd06128374345d8e6937f2f4a02201b1b305350742e0f67213b1c5f69a132e97e3e3967b59 -a53f11ecd11affe5cfbd174f63203de8e4e358ac59029b204df1244e72fa8cd600b99fcd2806e05b60973cc4f65d3e53 -b9581181eb4dc0a4e1faf7cd716f32854f15ec98853f296add58847ed4c4036a1f6cdaed4acfdc6422fed05264bf42dd -88ab901304bb861d0a864b67096a6afeda10dbf9391c9f95a8b226541873e6a6d707cb652c7c7dbf3610b3d2ffd373a0 -aad6aa83da7bcb22ac4ce2817d3b0f9be1d81b1596aeec56758b6501912e50f7bc1557add13f03da1c7c083559a3e9c7 -a02d483d8f12f74d6dd3f45e79bcfa301dbbd7b67d7d0c158cd4af625591c2fbccfb27fd52449ba6da1544f885aba1cf -878def0ff97d3e38a9a0c9307be4f557d3f47f4cbddeaffb9be86dfd268d1fb643df0093902e3618c5cafa033403b439 -858b952ae1b1b5a4e3285d8bbeb197c6626c8a2a33ffee06bfdfef531118b1b4983561d6d25bb94eeae297b2bc6dbed1 -88c798d495c036f6856f6d8e1226e522e83b5cd6f94d9dde41821ab2d203e2a8cc340c88f687494292ecf9a84fee0708 -a7a391d3266ca5c17239571397b48c2db71f416eb8d4fb8a015424cc9c55d00009fd1dfdb795bc5eff88c900f5d17558 -83a081663150f89cf796d998a0c9442b1136d762cfc7ece4e70b821a102e0c8c248a21f48006902e3bfa706219d5b456 -a20901c9c06b828347265074af47aff0bc363de5abb60d0e64a1387b51069456b62e2f97aa3cf4c3c6f8cdbc6be4ebeb -8287a4f1b24485e726d426e17071bf65bb1996500a89d5ba0088d21919957faa47ce9e6410e346f608414c7da7cf085f -b7fd366f4f8bc2a318551e05ee1103ef9cdf93cf6c2c63fcf0046028b91e299782f3d1812aa6b5bd6a5d06f061632c6b -8ad22e713d6633b7ba8f7af60ffede735e2d539e2d59720bf73e17466d69cf6503378bee92ce0eb3f8243ff42ba3f9af -b14339a24ea2f1e4b108679e1d5524eb312396bb496762fad31648dcc4501c337fc3a0223315560af3c20a3e1a0094f9 -8539b0816f3701971d7fc876baa4d40f09e9993cde5ab3ed79584361a598dc14c67173b1a6fb77fba79bc3e0f3a7ec09 -90f0438edc95da3d4fa561c071de828f1b59a7234d5773d55742e3adc2b7726fb93182a8dc1fbeadee0387daf962197a -8fb545c3d291ded7aea40a5d5d36c4a75fe2a121e77954db5914266ac6a1f691bc8c619d5753d64385d7ca6eb053bd85 -9339da27f931f30fb4c5b5d9849eb40bb227d9e83f2e85a8721d9ed7f3d88f6419271bb20a1b89c26f80c936c626cba1 -a21c2dfacde8a657e5d7355ba753b3829bda7f9c2dc7dc5ebb3da442d2480a8d87b3e4e23b5da9dbba980c3ade01f1ea -98c0c1873047a740591c4763993cc4131d6d64ff59883f0d9cfe0c7404ca98172e5616572656451995cfd0fd8d159169 -a891915dad75c8b2868379c7f040ae906ed30e69b76923d4343222b5217837b773364917e4251763b04c94f2ca22840d -94c176e9b1e65122617685aff3973855aa1e0c648f2dc35f3c4c1fa3863a28c3301a260d26489a9755c278287c4a1253 -875f0556f2695fbae7736673a0731ee70a0c2953a758110f7699cc7221c46b616eb4e439f57618f154f0cfdff57a0148 -8e66dfb1252adcb59f3cd4c424c7341da5b74c33dcb053b751bede30129014174a556bd59270cae0595c669c092731ff -ab749e76441eec1469b24aba8ad3b76937402ce158794539d38cc8647558eb9743c96038fdf4d001513d489a2dfb48de -947e5a5af1da37ca4784005caf8280f5de2b69680feacc0a5789bb4444520d64ee40299d6492e19fbccfc39040f6274b -919b01a297de7c979d27b94879c1fc3a6f5faa41c85f9d4647d2085c02cd0896eab1e7dd2feaf2b9c3f42f4dba5342a1 -88727fea0d63ac9198512eee5826aa69141c3907f3c172909328105d6c790eea272a82d1e1fe27e7e8ac5280e842a28e -828d08128899a7bbfbd7fd31e4ebbda5ea3c66c1a177e678d46ce4937cce804cae81d3e7a4944239614e8f0775edf6df -aa11487e1805eabefeb7a16e6b2c0a551b7f049067d3c1468b33df877ad1c50de0f1e279cf0bfa88d7f507fe2bf53b85 -8a45ddc21b8d232963341cfae10a0d57b9e65fc3b017f9bf2b5742eb4c45a3c11341cc3916f995b4a30d958ff65ca421 -8fca01c2184ffb86a22f4ed757a1364a0f37a3a1ea7c1a055b4e993e01d352748f6c22d902d28ee439ebdaacacffbda7 -b10b5b055a769ec45011a31fdfe3caefdf889b7c683446f41c4b775c74a4de192ac68b319a018c2dd434e69dcd40fd5c -b5a45942fb9e6e83758ebbfa15bfa1f2cb2d39033f2ebe038db29eb137739f5cac31f35555bd8b14ac04f3206e0f2998 -843435a2d791c4ccf2ff9f783fe7dbc48bf875bb9bee845427dbf79755fd6d09ff6b14193de0bba3996ff17b9a473aae -b5838d60df052f8febdcb2b16121838b5b228ea39650d89c2cf6655f06728afe3a323ac45f1c517e8bd1055067fd60f1 -98a1c5a8824e2f0bd33b56fe1bde5175e1f077b0074c79ae304df4abcdbed370a44db82ca7d22bf0071305f5b3ee3e9c -8acde9dfc9c6d02704ee756f8dde1aa3e421b006325db56fedc8519f633fdccfc9250edfc6009b3bca8f6c2efead7f1d -843b1ada23a5177028f68cc59928e358e0c90ec60bccf774605ef6f79869751129e84684662805ea85aad87e00c9b922 -80906aefeeb2d69ec8736149f8d19165143054002a16ce26501106cf5527bbf69011beb6f867cedb088895c6195c7627 -b8b4d45603783ac7325ae7c2b31d8a1f39cf60f56f9c7b1c7e9a7bd55363567f9eeea30f165713eacb12c4fe3286cd1d -9287ce137873050a05c6844d6aaa1527d0a6dc9403594320624ce72063d6904fecad36fd909998e1c8376379e6bd2f11 -86abc48b1d239ae6091cabcaef10d2786a990b72c398633d831d669199d9ed3c40c347617e2c07f028fcdef057c929a5 -8c4cb5b4c2dcfdb5375a0df15c6c024373513d7bffa5fdd2ff545314b0c6b62870a3122a692db8e820e3f8ca1deb1772 -8cddc1b6e030c89e68fd2ba79feb2a63f11ce60cc534f004932f5a2f08b047dc5adce8491fbd0f19a015420e5bffb12d -b4d56b178780d899c28bfac8894a28b9b53d7695b5c36b06ff624877281a502e5ed8c88d48f011dc8beb7816b70e29e0 -938e52f73596a253a61095ba2f84bad88b44949a4c1d903047be11a3d2e55df61c3b99073d3ced08242f9c3da50a8210 -830991af3a7d5cbc53a6d3659550dbf0e57af573ca57f1caae3724fc76e5ad9fe1898b540850d32b55528f4464f2b61b -af9c2f3afc17f5df424571e6109ab51ae9c94e0ae24c041011a57c5b583b80a09b4309603365d57dbe0a3bb97a433ed4 -b823bc6941a9611f32b88fa2b35b9641fb61daa8f64ee0359461e2f55b55cc36fd7d632d7f1e3ca879b6c52d2ce057fa -927086b6edafc055011643377767e075f044d7727ff412f55f45ef83dabd26bbc5c8bd838cacc986ec6c53a4ea978d4f -b83c68c09aee1afd7644e7740d8be028bb12a8a3fb184a1db4614ad65672048f7c9e2bf59694debcf53626d73546981a -82ed8483f7db084b572ea23fccfff00446a604a49d094980bcf2236e1a0565da783701e4c38bd74b95239bc28803dead -82ea648b47f0ea46e66b76b4c14ae771d9e97502d24608794e51eb1f5baa301e9cc3cfb83ed8482d9f55d151df2a11d6 -ae6c89003cca4e25ad780381af7dbe00f2f83e12c237c54dc830f23be8ecba4bdb57d5c69168bec35502074451e4d979 -a541989f101bd01fc39db7f3abe4afb083de5999c5776343940f5704da8c933ad906331dfad7a18ee423398690e1cd90 -83513d748bf108c3018fb0bffa3224c220497e0cbcb0842151b4a8d24e17222bd826ba56f37eae52975688ee2a5da3fd -b769d5256be8c0645beaccadeb1cb1a8b585210fd78dbf92990400070acdee073f6ea6c0eeafee081a95e2e8c0cf5f0e -8822683c7651cdba554d9217b9d5433c8b8c8c5bb47421293d6ad0e1c5af67fa80714c04e58ae5fb0cc9b5a583f66123 -8b3b8255767f58a6cb8c13c711be8439fdc53c8433e97480b892e58384eeb2022ed7aef62fc6127c93228f5e3c7cae6b -90f08d28267c51261b74f172b3dc1abc6a64e5056dca42728beff82d8539105621588a30cc3cc58541d0075320d6db82 -81245b834e0c0dd511894ce4e83eeec96a49c37a057af74f6d4f48fa24b48f4875de1b29777857556ee78852f40d0791 -a349072811a920c64116afcbeba12e34c7df0b6ce427b32a3ca59891d2eb15b69e852e966387c409329d359351f2b000 -a1301a0379264151b8320ed7e008cf70b22d9a2d188bad3d0df0cc4ab6b5e7f87392e87bb107781b3db25c1e023818c3 -b665feee8563ec8f66a346ae078c475fe480f4d11182ea636e4e95a059de525ddee7375a51a31c4166c6cecc93387fac -955c20633e2f9f51efe4a8f717b0a822ccfb668ccb2724731fa77ee7bdb6a48f33bb1009cee611dd55eb42661ffd4d62 -b869018c7cc428b3499ed8edfbdae4e308e0ad2e93ad9a5b53a1cfe795a193a1b3c002f34afd98c7b1832c2494c21a6e -b76611b7b43cb468cad7bc25e82b199e9e71c29bc6ed313f9b3edd6ee4303e200607820456a76b19c5334e14238a97e6 -b36dbb2e3c470d7948f3f6b22099be191988708ebff0db472e056b9becb3268ab2654bac9c61ef10af0ffc853f6165aa -b9e4055e663401c3d3287221b2d3643a5001714f0261323af2c41f46d7220b5547ffbcd978fae521b0c71630dff4adcc -a6415ddafe472a5d6c8f223bde24726b9b91fbd19470633c0a83ac2b64f4df8b0631ef4e6ab8fc2ddf1f708133d47949 -8914a742bd022c01ddc0a6a212bed566772169d8c3472ed40fe9708addb7ada84192c5abd7db23aca16c789c646d7251 -8e99ab9aee29ec3cc719136cfd735c122b037051cfdf09c5788fa34e8ec00ef6fdf6fdcde066ecb254aec3c59ff01697 -937427eb1c6c6f207f78f8a0ec71a5691eeaa3be14b8223f09f69b1ddf0e23dfd5d104b30dd3bc8e8e1596954a138256 -a29510302e473a00d02dc7913820946df3d6a28b723e8fcd3810cfe755f9f1db9f2fab7960e5a6a6fcd77ad0f74c5afb -a6a2d8e915eaf1c18d8959a9527c253b1788be986887548510f80901386edbdcbf38d75adf0eb1e5076b5026517d919c -b8cdb7094a221193be91e1c7fd9ab7b214410e9ad8a8c3ec3b672aae6b9e76356365b484d00545b85c7754b4e4703764 -8b96d96d83d322ceda9758b6efffdc12ec8b4c1450f1ae6a8bf5e94c42ba6d5bc14adb7fcf6195396d09769c50ccf05c -974c86627bc5f115015cf5386509933ddc3dd91d9239df874761fa99bc894075ddd975ded95c8a83d862ee50951836a9 -af006c6e0778c1f97212363ff330ac0757431e2e70cf48c8ab2cd18138b1e715bcbb791d8907d30797dc393734335869 -a69f34f3a3886bf663b5c35172626ccc7d5640ce909a1779c7a62bea449f25be561dd04fdf286f872b77ccb057ee2555 -9932bdbb24a5dbf570e0ad97274421f2d08e58ff22fb73564ebfea4b77f6efdf78190365cd0cccdbcadf6df9f9a81fd3 -a3a772522ed9b62c61927c66041c40c19f0d63a5f9cace57dfba5d1f1e3f1b2b883f09106aaf8e2cccf2c2b454b490ff -b1f17a262245ef9b03ce22dcfadfeaa244dc322a1f5da9e6c460971f2bac8bc072ba58e674051b9a9c004da0176733e1 -a18a7d160ce3e26108e22ab3f07dcc2e102691b4d1160a52362c778ad540e2799ba5b2228d39bc20f29392209e6756d3 -b2f1b158e12f6b3eb4790901bd37416b5719bd10d1bb181f540196e3ea4c38c430eee6bb1b049f606c2ad3d1d293f288 -894fed7dd85665ea411748c86542bb27efe39653178a41d5d32cf2496dc01175301a7100e04506f267360a6107e343b3 -b2a5a33929ccf9f9d6b57e0836aec4318f4b1183364bdfff822b154d2a8c6a791a9d1e6b01eb9a53a3c3b7962808c16c -a3178509cc09849896264539b9b6c6eda142542c49a975ed7f1ec3e71240c15a7039a1a651064990712c0b1e9d0731c3 -93321d32589b5813e8ce1bdcf4a098fbc5196b3438f5995b163c7da4304e44f7b4668289e00a7aca22e2cb72ee058adc -8c48852fafdffe3512759211f83041ebe47099da257f985ce9c4cb6b0e5f27c1ce88dce8885cec5f319d1ce4a1e971f5 -a70989d4dcb75f27e4e081d5432235c4d3894d6cec8100921ad31f797c43d4eec5974def4253812f72aa63a95dbd3ee3 -a2c1bced4da53f6158d4c13977f08ddf40690edf6a34590e1fde0b81d51cbb7b293771beb2a42fe496852f1fcccc0d01 -b5d70551355fd2ba7763eab19c9ff2f804e0b3f07516f69ce30d5c211fcceab5579e1dffb510bc1a9c63d7e08d6e345c -b5aa934e466bfa04bc85fbbeac4be9e2bc3873dad5da438a2e3e62815ce286df9a25d8d097d62e02950e971c67846ace -ac8a4b063890548aca055497c6ccdae82558434ac545a6f274345184b60c054f9c3d847b7d112ce2d4327b2a6422d818 -92c145b9cd7d2800386992e9b6b8ddefead0e8042a53cea2494842981789e14d680ac9523db01cc43594ef696b75e7f2 -8a5c2675a4df24549c2d5bb30df3c539930b360a653491a55e739054a0d45f6e89d6d4529b78e2c35af3b4853c91a0a9 -b7f669eaa4b0eef12bbae7841137de03c6bd3964accabb1c5127429907b14b0047040232ecba40904292e2a740e294ed -90e594402a82ba13b8e6478d69760c512092cf8a1d5a87bff97c6f7302ea5cf9830b2ea3b4a80b2a8af5117ad69ebd47 -85308607535864a170f50b28616600cbfba5daa9933ba6193fac9344a39c5ce392856932a7c55abbef3c5fd105087659 -93def7c9eddc41188f32e5b978d97b8cbb05a0cd70cdf2ffbe1f5d3cd77a344333c575e830323f75fd77802512965fa8 -958c8d711daa777371e6cebb76084249381a2f8c374efe7371575e5459e7ece754b7d1e8bcef9597db3837b13cb461f7 -8644b8e96812a3fcb80c91f11bc4bb835f661d862541e61bc8911b8e41558d09423017d66dc7dd8624a296fd584b4903 -b5820fcf48ac2b76784a947c08677d966893f38644d8bb9b38299e1deffdf584d54a33d367f1f455b674400125a5cab2 -b46b25baa6e4ddc65396b246afc5b365c5b430153c261506974e74a058ff20dd2ac2fb8ab76720864425b206828b93ee -81333c5faef2fb66d270ebc93b2e97b97d779650a1cb146770376b16a060b0f487d1ab59b0a9361132d3c2cbcd354a3d -a0c7a14dfb78c731d8dcdf7869a8e9a63c26dbc1022f5311c0a19efe7cea4773868fdfe495d9f48ea681d57403ee20b3 -ae8e27522261adfe335d8ed32207d4dff7e03df53dee893768516542e17bfea3a23a5e6c594a7e74dbe78a51c1ba0fd6 -927d24e5a74c069bf7f8c6dec3c21ee3fa2aa2985fe26a02c88d6aefc6fdea6e27eaa51058800c518a61165546732a01 -af55c628d1c9ba0d95165ddfe367d11672dad2e6e71735952907e1f31eef8b5128a39eaea4aa90da7547da154d2722c0 -b1b6c0ad124282138dbbb55aaecf089f621d45bd5dc716dedb8cc96c93f3be337e0b4e0438dbac4cee0439af86c00e56 -834ff97a75bf3db75a3aa313f5f61eaf25862b5bba4bf039f15b68dde75edf4ec506fdf38f925835de419c6aa54e916e -8d33fe5ed55daba07f500364211458e1c2258aefe787d20dd59de1efdba51ef87532adc766be8eb73f328a9800add583 -a73e1402daad660918f22a0fd7e2b81dc465c4d50573ba8fce5289328476a5c9fe855f4de7db3a635fa08952a0dd4b84 -8fa678cfbb278b22e93a8968af74c6a22bf0ade60cff484040fe0fd4fd897a8d428f1d1c31ca52b4794d7334d25a40ed -9775bc71a9df2d8264d17d877fc152b3bb6358f0811c637b9e426afffb8406f6191be4d2f50b285e30018a2b4ce4fa0b -b7ca93cffef6c05c0f185b1634030867e80ae128594637ecace4e6d9c4232f36513a9d92072643ec6eefb61da6468fcd -a1ecff7179baa08194ecdd657ec3768cebd2187dc22d78624deb26f2af6cd059d5eeb956e9c2fe9f2ac387fded4ace38 -b51a901b1ed43b1673fcb592c9339156a58ec3f5c52b2f44445003bad46f8c9c6bf9b686df2e256a62b712bf4ec76409 -8fb385ded0aeac3e34843f8631b25b814bd9775f5522fb5435eb197a10376de79632d983f4a895f3759eca631214da20 -b1a0094caaff2257a81ee5cbf2b7c3914312182eb4ede24f9425a2cef0155a01177f9d439b8130205ac8e4b9a09d5f18 -84382ca6052fafeb165058c86fc7b9e09b01bd691075c80c992f5b43f533bd37e07d178e2489fabc8db909f27ebd5627 -a7a8a6ea8d49912d1ed1d8d0551cdbe9e70af07a3077ec2de39a77dbe237e4bbbc5ee7c838fa61cdebf4b7208bfb8c3b -8da11fce90225a64d27da0c94cc8eb148594152e92aee5efd4c053ca6ac2dc29190bfd5ae59b4c7ab111800f723b97ec -93d81c1f743297c7ef019be107ec6f3808c16f6232f240b1dc5081adc7d0c92dccb2478c2796433081d064b11d76adc0 -b300abb4d4c4992dbd35a1d3178565ae645e497ecca9d082a1fa8aa9f8ac44df60d37b8a81393c5820705dc242b3927b -9293d80fccbe1b99a33cdb165e44bb6e431e33eae18232bd2dca2f66cab5844309854ebda1d663fd9f7f416d71196f82 -881091b811e332b56fbf2782e6f0e19532a4ee873e5b04815643cd0a5d2ea50c68fe4bb77a26b13c19b1a877e1a425b1 -831505afd8807e00a0c410bd6791d2789f48313e2d776a009a4ebec661305402824d03653590dfcf3b9e913b6da00bf9 -a16e023ebabb44d616efb0c7dd56314597ff1ff09dde50126e56a03bcfc56ec67667ef523d178907b8fdf75997c85dc9 -96a674aa933f64bf33741c145ec35b12d45886f60c2998aea60b107e157762ebfef962476c807bbbce55cb56d1bb70e6 -b49068129004ca04a00046a75d9eb51b660ba40b73de22a05a1e4b9169fe2291df1264e787de51b3fb9b4b914de363d5 -ac7390f9df12a4d60947a9dc63ba1e52ef424db9ffd969b127916a70513a6a9a1745e26ead31726629ca5d97bfefff31 -8116a7842b601ea48d4f2365b54f15353e86ff4dbe91584cc8c3f73c12acb919ef75d0eff6fbc2e98cdf05f1981aa41a -8253665db0fda4a477d9eb6a21ddc4858367869aa88dc5797ac3f475dad6b4a29459dbb89371a79ffd3245bbf0ffef22 -8983db43909aeef8c9a8f9eef60e15fc0cd2eb6c5e58de40debdf1b9c49d86cfdf38a27e17f761ee64eafeec2ffec8f1 -b06b4f3435b4feae9c479d17f250892fdff00756f5e01357a553226dc928ccbfc822a49dc19cf230893f0b80d768be2c -a1ed732f34153d98988b91732e9864e7686bc72eaa854a1343de46097e75966772283324ec2ed646ec3e7c2a20198248 -91feb47c3d6bcafc2ac69a23f5e04856440d6de47381ff3ba14374f8ef9fd6d98dc2d43ff02536ab8dfb93f934d89eac -afd1a2fcae5234b68ad08d21d111a5aa71d73fe62db23dac1f2dd8188460e5352dada58b71956c0409147963974591a1 -99be215c619cc975fd98c4bdad9cd22c7efaa9044f310674cb52ffec23564c04d56c5af802a1052bda54d3546364f9aa -a37547519a5ce60d249950746a0fe7db16a4fceb2ebaf93e0d9885f182488d52969e13960e55696b0f6dafcaa3f5a35c -8c48b22f59110f4b2ccb2d3f5f5e77bcbf5067fccc194b5ed6cb83f8fc7326b01d6b62ef2283889d542818f6a744fca9 -ac531de47ee70c346c1bee7a25ef9d075fad69e2b0f2488c5088c62ca4a13286b9324ab1951db0d49cc3dd0a4c43ce1d -ab2b51282eb8697eaa70d6f13e6872481b88ec2a60a042ea03a9e807cc9dd198fe75261b1e7d1694f667ee355fd300f2 -af9c1c93544bfcdac5ad547403515e68f6a976c739620d31cdd641a2ab188f1f638f83864a7bf8eecc4e1c817880fa46 -aeb84265097d015048d765258494bfb5cfb4079f86212810256614b46e41dc5e4f00b0e656c973222e42515e4d741fe0 -abc53294a22b8f0624a8a7c09d1d60779a8591a40184379d94276e8d9726d2275a7dda54aa11afa1602380414074e18d -b5262451f7c0178449c669bb1aab6ab9b8e0da1ecdd353265b2975a01e1f2e4fffcc78fbc25815d070077e7f1c1e79ab -afcef28d2751a083e4cafac04945792a32b53c54fc450a7e5b73671df8494953d3663f312737621ca3a5fb9b7a2422fc -b4523991e849fa91274595a531f2a59cab43f62d38feb65da02aa6519ddd1758e5e292554bbfeaa13706b5c5c2f18191 -afe60f5388fc69a3c35270c0619d2d9c935c6e7bab91b05b56d702dacc672049fd9499a553ca4854fc63ca954ec51f6d -b4ffc8820766ab25ec8e7de7edb7e3424ac82fd456ff18ea3a7bd2538c73e2087034368914875bad08373ed60be63a24 -8ca97af6e2a9ca415ad3397a88f92f4eed39280da2dfd09e040c163ae105ef2b2b2e6fda89c6859d183ad6089f758975 -b62bb47d0113c0e5c2f0138173d2b1a39b845dd827f21ed30ff4d75721b489782c5723857bc4258e111761b60ee1103d -998e43472722d8b34e6a1ab963fffb9922f3a73c08b616186b8535a306c8ead0f90f9a1f400a6c954a389885e36b6105 -b5e78e5fca280ce9c0d0a76109119a271e800574bccd8bc0d66a621fb013a6f9178372f90f215b001b880d37afb8741d -8f1b7dbd91996bd833107dba6c8d8b4d4067d1b1c15b941a5c8918659b50b4a0797f638528ea92a8506ac8e2f21a26be -9968d2111b7017f098ab03505a517163a960ec792d7a41f5f40e617512d9f597250ed13d609793748be1c4f74e779621 -866ee7cf2ca9c66d765ce0c8b4cf45b94f6e7949a8542dea202a61ae71dc59a5b65e5eb2cd4290ca732e7cf009fd9b24 -953e72b9befb4b3eab3cfa3c5147aad2a28b32c51f261435f8481b95721eaa6527ab4ff7fc46fcfe228551b82f1d0867 -ad91d7b4b6def42c17b28fdf7afed6fe0fabf160fa6294f63389024ca9303f249fd6230917b86d5346028e8c139d6481 -b38ee62228b06b416c49fd527e25ec051f38a5df50f0bc1747dde107ee289c33d7c9fd20dbf629f72a86d859c488b0b5 -8a5af101ad8c3d0a0f43130a23e4b3c2825bc90f27d524c424d5575c4cd5b1536c14c4f0fef03093b0c0b47b4eaec312 -87effe6fbfe38cb8f08defe220fbc31951b5cc18d38ede1c545dc20c5bf8025e82eacbba71890e0f811e60e10dfdb36e -b3bd26dd1c411676ca8d015a30a69593f5831cf52442062c3161e6c7343f4dc9d7fad8013cc4e41b613bbd4630b190f2 -9210c6a0c594775bf27d322f732663d63a0ed763c4fbb22df2309deb8c45ce12c2a34ff88b462a425368bd8ee13b2c30 -921cffdb2054e84a059fca5b36611a79a9a467fe2f3477a4b3184fc5d027b44a09dabb1c1729726dd6423e14f8e1130d -b5b31caa4ea31b1d410bf7acc371aabd69a6f2fa31adcc6dce0a5e6491ba28a7e7303e058cf05dd80a4116a35c77c7c8 -afe1be264eceda023fbd780acd936853097b9f337fd3500086f71773ee0055bd2818207fbf5415eef33f18f387f557e9 -a2cd2a9bebcc3bea8516c68ae6d6539b5b3c4626b18a43a089ad88fcee8dc36eef35f30412daa6539e9da877dd947d76 -a8f53e2ca8b5f01d99c6cbd27e772713dc63dc509a1f786a1d7be295becb14560ede28a7d11341432a49e8f93088538f -a4f486dea12b6c6d31c4a6345227bdc3066399cb9d0de5e0147bde1bcb5a8f8508301b8fab60f80316a52adac4db81fc -a8e1b70bed423c1ec3f61f3371e273b1fe40a31ae3583b5f419ba8bb78f3704f8c4e69c249a3456abf74ded08993c84a -b4f799b7767e71f4543109993457525a7d59b501080beae27b849d8552d9524cb5e58fa6fed7137495dae02789c29fcc -b41d8ea06c3d11fa9103016e350ffdcf3d841c7da52a69646eeb798e01055795821b7ec98e86eced3b1e461db7f320b5 -b6b8d7090eda974164ecdbf9a5ceff6c45bd08e485644a5db46aaefa440f44eb7a5f2a3250570dc30e9b91ee3a57df5e -b4da6623bfb4f65175c75d6ade848d4865b9ddee2084dc504cd1dc6113a976fe71da3c3bb938a1dffe91e950e3ab16fc -85130d000e123a2e05b0a01f33e5e455cfe06141ea5e01e2a859bdf9647d8a61ea40429ba0436da4d6377fd75bfce761 -b3f91c6694a2e120fbe952f864c414617cb78c37045a919d35fd9cd2d0a7d6a655c0c76c4c35d2d59c2dbc36042ccf27 -b620c2d9ab94461a236fe4acb77c4ded3fc6258f8b3b72501a5fe8c1f8d5a09dc140dbab27d6954782917429be4f1ae8 -b36e44a93567073546568b399b471707924a71a918098129151eab1aedb5d3e3cda771443a9f17737caa29d39a415e34 -92f65794f7bbfc8149e8251c9b4be8efd81057b1d70a2f2d223e15bf2822b462d7445fc74b45157deb079d1994df23dc -aa022e8ab8fbd6a6eec929b0462980d3f4a305084d1fe8a42e3e7b2124594521504fcd20043b7f078873c15dbcf15568 -b1af8e2492f72ea1aaa9b565110c60832d11ec8cac343f8998c04365259d54a72e1e191a9bcee25435e1c6077ff6c4e7 -b557adc4566fb9458715c02fcf126d4f6fe442eb1c5d1821ba2d7aef933250a241735a47de11148e52c45c229fdbaa20 -9112b026feac67581b4727ef78bcfa2caf2ad1a116dc3921a1a8249c397739c6701198461099e625b12dd55e20407f3b -a3226cee104bbdce8e8d0b37fb7512a357cea6377a17126c89aa3ce3c29c8eb414762957d5a819cdce3137f84e7f06b8 -936ad86b123c1e277feb52d1084525269380a8c7ca4276cf1daffd2dcdf0870670376900e58a1e2ab361e2a8c80897f3 -94398a4244cf86153312ffeb888b5b8c73f0da07571e92364e02e015ff47da21a11f0fb390cf8b57542d3f62cef93a94 -a0d9b5748940bcc69d39a60a6f383903333687db85cca0ad291ef9d36b4d05d3f3fb3e126dd48e0e8aaccce0a60f2436 -a5ed10114c2c1102a9b5e1305ed4897c147c291f2175936448961495114129bf52cd30c54c7a7afe7e45af8abd9524f1 -800f57202c8960649c95e153326dc7dd1b6f8a332cbad9c8ab7ea6b69ab5d305ff92ad27c2b6d15c96d89541a814852f -811b5a4d0f3388ed907810c70e42524e31ab14a209255af7cc2d47ec64ea076127470526a8478482edf2dcd60db28833 -b5ea43a78f4d7b0d05da9f7ace8bbf65386803565fe63c61e1a1934431716c431ecba66a0b4f4bb1b3a1e499187a0930 -89cd76d5d6e6cd77ebda0bd68b5deac567e437ea6249129e9799a9a02d62424dd5e04d98c7c7ac468f12d6e11af9a3fe -8607c76db5fa7a2b058e40b5417ef1bf42c671d074cbe36578a8bb4b4c0ef69e5c2082f56b452586236762efb19cc8c4 -82009127f00d1d66e527b320fdba6c0895e0db84e14726d9f78ad4e00e3ba05d800d996737b6f5100f36ec5e0ed016a4 -a5f79381ce1f55085bc102a67e7cc4a27fb632e8a83b6e3e9d515d8dd2c23f5a4f2b79b6921aca19e89fc402d3c0b8c8 -af76109cf5d10384ddf9d9c18e74fd2a27cab4d4f749656e973275a3b7de712ad6929bf1ee4524bf9583e9b47fce454c -992d1c3e15106d70feb0f557c14eed3bc9fe1a1616a1709421769e516d318229ffcf093e2d3974d95095966fe960a793 -8dd3e845b5432c567549fcd7afc569fb855fb85b83cd263369837fe8e12faced5b6f6aa95a490145dab1d96ce0ae95c2 -aa3d65abeb588b48e470564593e3b7879aabc3ce4bf36158758e73cede5d98e6cb365d661542e621c1646245192f31ac -960b08358315841774f957f5b2b4b063a2d1629479054cc9a976a865efd4c6c7a72590321360a9c330512491801c2f65 -927efc6ca88f1c1e013039ceb968667e3fb381540c83435966341d3acbd77260aeb124e28f3fdc86f9c778f7f203925a -b1ff1ae028d5de9b86f329d4795f9a41e7617813dc4aafed19277f8662c59228483ce3b2841ee48cb136b83776af4f59 -97e2deb04777b2b0cf107f09ae829b11262ae7f7997b672fb2fbf301dfdf233afc87d13cd3600db1ab4616c337e85c49 -96243826579e2edf6abbb579151e4dda81ab5ad8e56c29a69ba280c5f0a0071be571c2b9f1faf3ca189688efc2e20e78 -a8a82bd2c8bdddfc9ebe552866c704a1358c8524fcbb2af824857898e1816ee4b28c59a16a90cbafaf06369ac8cda2cc -a49d81e2dc3fd2d41ee97dce14456825e5e5b55ec9d01447f0217c18d71dfa7fa3f3a7451fba91515636aa873fb67768 -b1aa85b302c0f1bb6be97affe6ce393fda7935cbe76b08bf632b891d11653f30c7da3eed2555d0fa2b068170275e1c10 -a9ca4ad1c30a5b9221a217b5a0dd155e601b1f479ebbd407d28803d373890247fe9c799c01adcf6b33948c4397e81e57 -87f101a43a228ccee4f2bf74f011edeea0d257bb270082191446c63a565654890386e593c3f73cb92716145a1dee6018 -b188017117ea3e5ba6ba559cc3ef45eeae577e068f21572bf0f6b4325584a458e51cd496650f1489e791b66f78fd0955 -8967a2bdbfb7eed1cc3a2671562cb4dace6286fd694c8347446faf537b5859dd8c5748de91e14231bb21abf56e7eff17 -adbb09ad50804762c79c3afe7c14c347249b564b29c9455cf97ec9a5d6a9dd758c9a9340588da23f7aa23848896be036 -87f970be41e5c523eb3176a97fc9dbce11c8dfdedf3e8497103f7db365ecdae3b463a874c7ee82e45bac6f3a09851ee8 -89d599bf75dc4ca47f7cfd28562fc9d8f4c16a9e479586db74c85c1008c656ff047cef1a39f0649adfd0337e3c0bf43d -96bb53bddd7fe190da498fab9600e2825018463671eee0fd14360270223410f7adb1065e23f7b9453ea8ed97c1356db4 -a05be60c5188b922708139bd11d0e0bb65a6b2219280778efe2db6af22e949c0ab1d77df2d54eb487816e52b1c717d24 -aeaeb5ec9e425abc405a23e68004cc1777ef0ab94f34822c1d2aefc92831e5c14d649a8e01336ebe9fac670e38e8f68a -a4507eddb52238dd8eefbb1c8479b3fd648859c9d44371f8d605149502d7e60fa2f3a2a1675e68639788ae1fa39ddb7d -a1d39bbca54f0a5c6895b6d122bc4f68ee1d29e2064f91778112d3c4eeb895a4cbb0a2031cb7a468eeeadc7179accc91 -86d7f4e68e02a6f8d0d88e39e2333c876992592fcac7732654dd362bd5602efc8a0f70bd3454f43f4fcbee3378ee5b5a -995dab276322f3055312e38acf3ae9897d9c179e98502639844c4ec99718543b9ac8ebb2c66d1c9283250c7033402d44 -b89f131422223d3c9b479164b96d27876d41323b6046d07c0533508ca5f0b0797751a6d37fcdf1e0a8e3d864dd714c8d -a37cc6c9565d5eccc4352776a1e8183bfac56dfabd018b0630caaaa916584bf627cbf48c7b313b8d05209541c1abb44c -a3bf3ce979464f402a0cbf8badf0d3866b8733af548eb92bb0aaf2055b32f439bfafd98e89491b688039314878240353 -916248d2b354028914886ea6fa8760ba8bd8fe2188b069e8e49959b122509ca85243b97305b3282c3ba5bcdd4c7a6bdd -94c1609958002a5fce80bf55d825e92ad2cf486e5d4d0b8bf72ced15488fe83083a94d91f612ecda3a80c9883715a23a -87f35fdd96b1f0531c89732e932aba166acc76221fe68aa1bb6189658b4e23383445a22078c4c36a8ae0adbc3efb5647 -8ff148f1d6dfd1badde791c32f6cf01112d8c666fed1778f7933ef319f553f204cc2261815814b38986509488f80df9c -8ffb29dd648cd8c9d502691723e5267aabc390e7e7e9d112916fdadb571221f68d4036796a7e3a4ddfa6325066636fd7 -837f1a9d723bec4013bf005f49e3c0874aedb290a3762eb2215211c22d73545343ac0936a2d29e2a2422af62df7160e6 -89e6fc7c04b98c83a93013d8545a14139a56f478bcec83f5acec71970110bc8a0b6435c48f6e499213dfdfee84a7730b -af9713d86a4bceea0e6563846de6f7a6050d1a48f14d068d8393b730a496e19249632c6f9e9b6fe6de5ef968aa3f502e -980ea7adb8d80d2ae48d66f5682bb9c5e6ed246e63662eec9215f965e7f1f0bdfb6adebba78d2c17df8276f036c2df2f -8e09794012712823a4effc243437786120d7eb3a42cd771e9dc5d7b713c830b777b8e1ebdd8c48efecf9c63e9af36085 -a5c90dd9cb1887065de156de7dd24f0a0215642646448c802cdb19b57713ba7eeb11174bf282cb626e000e5540893b54 -88acb1b813bc064b11f37f19e5f87dbcf8e270c7559867e993fca4b4aa10a395b3a473285439f151323de4cc5bdce948 -a6d030925c95b0ff75a948e1d1f3a6d414ebe4185d3e5a163d41865e7dd23ac3e14c791ebfc0722b55eb693270539042 -a500f2cc00e5a5c894b6ff4f2115cabff056be9c3075f06706a892d69fbe25bd25cad71c302ab8f237168e12e5cf69f4 -95a61840aae356efc98a9a1356e9e5922182348cdd5a0938505005bdd1d15ae6c047269064400ac0ae0aa67318497599 -a3a7fc9fb312a32f04df9fd8f3e1d6bb2a50efcc0f5b3ec3348756669b2a05582a6dc16360f776cd1e12ed41a5313f51 -88bab74790c699950f4facb5b1ff4b0e1e61e38d23d7956b6a8aa88cfb423bf5cb35a36aab66d0384e89bdd3e3daf654 -abd02136026e4b1d167b45afa830f435efb2619d22e00f015208e156991c74c0d14c06d1994a3032dbe114e06370cc72 -81620a6316b14c80d521e06a9f0e7971f1454081de20ea24888653b75f3c0bfd5aab8b58d7ba7a6141be9eb03bd7c1ca -8baab042d5a0522f704a5b3c362ca939b06820db8e35026c890eeeceb00dc607b088dbcc54f8c7c89b04f0703c48639d -b5493244928669273037c380a280e85e8e793d3f2d21d05e4471bd0307fd5077907f090926b88b2ee57c9c0cf217d181 -869932aa4d1307c910822c2da57376e64fadee2180696bcc45121056d63576b8a47c87f3859dc4cce29fab14f5bfc581 -a478015851be15bcbcbb735ccbf1bc05c482e5451f42898782e69a300c324180859d325cf340ee050aa19a25c0a46e6f -8df19bb1ea55ba4e0a26fac6b25844828d30550dab3cf869856ebebb7f045a79201b63ce0a6518884fd70541263fac14 -9438d13c62e5b9127d7074f0ab9266148b358183958d53402b8c35b8fb0191e978ff62ab3b88d50a64ee6e38a6033576 -81e9dcbeca58d8226fcdd27418df047b640fcf53bf13bc34b7bd47fb749eba5d7c5c3eb249b345f1a253b45b188b4a36 -801583f8707218ead0c4e215051c3ff0e0323a712dae13c0dba0e3e82a8dc7a69dc016bae9e31eb4cdd5ddbe47711e4c -9083e8c0508088fbf963bbabe7cb5ee4cd13c9513c8d15bb58f732aacef2d480441025c8c9ddd07540533dfd839414b2 -a183b8000ba2e20cc00d7e1f5b004a8b191ca41b0d21bfbfbb61d8c0a37925f6495132f5f9b240c411d6f40856497243 -84b5eccb5375180c56551d262875f7694033f6f1e1da98ea6e54ba75d5852360ceeff9e04c92b74b176c15f0255b8459 -a38bf79e3363c3e261d487f4c707d346d4e72da048dcaf750eefc846bfbe3f832780b9197c521c5f633fb434fe762b5c -a24c9a171757f95a7c87fd30f5dae6e37eb18a0e11285590531cc911d158ee1f6863fe655fdd4a7be8d3e41ef3b7edf7 -96c5726534bd2e9f0e56704829fd684d2cbc1bd188407f88337eb1a3280b97e917d7b1ecda34a7fa64203351922f42a0 -873f2b6006bbd86dc17b4a9cec6dfff10c820824bc4c10e5d8b85c48531384cafb7d3ebf8e77557ee6706edff6e52484 -ae3a5440eb7849cc104f8ce22a55d4eeaa59b242c9088401b3ffe675921b4092e19db3cb4fcb1a5d79596ed66caeb832 -b9f21a31f2870ee0590c080efba434a76e55b03cd5e3ab280a2a87061a38093603a84b5da676359c5e9654613059160a -8b58019e7b17cc02af600b4ee426158b8775f7a1922a1e216c5ec96dec57e7456443f3de84e7d035dcfce36973924106 -927fc1fec68c503918b860cdd8d33cbde51836209726f7ee79d58aaad8b9bfd81cd0020e96e7da36d5e72928525ee887 -841f179bf2297aba7b59354c8db4a64b1714806f3f33175df8cc69273d349932d58d86d742b4538a9ef83227fa86eb5a -8390e88458b61efc64494cd01cb9b278b1263cc8f69847f1c20e117fed45f8fd548680bae1df8bfc3b43ab52e0d8afa4 -9867dc5030f9d1265bb1a5c6bd4a192fa9b41e8bbb6f1468f54e7337029c809dc8947ee3990e8fcc54f32f8bb8e89780 -a97999c8994a202f9eac7602faf63047310e103628bbfacb20be74739cd09e49ec26205bedc550d41e8487079065c56c -aaee1ddaf788f80b93703e7ff19428cd80b83574d0a423013fe5217b137968355d4b24830f0f22e474f4464da541dba2 -97090cf4be99ae50baf1471035ad5f027a80889f89ad2af4e33ef23c6a789c179daa34f802c1b8ffc4c2a5dbdeadca0a -ad0a19986b97ab377c9f9c05eac0fa335277f07a79aa6d26d0638c26b37e6a319041c8b90a13a9af83e26bba87679412 -945f6d0148dd09cfd839ff0933da07c9797e718c9303d3e37cd6b74671c92c555588928cb33e04f01eec781a35a19874 -b3788894f44f7e54eef966c11c7225d95f97ab3700f202beb6895500587cdb28dbfade3ec3c9694398b8042b16c867a9 -aebfd343848ae92f6782bca7bfef5d25d748012bbf199b2f54cbf655c1644dcd8cfebe824ae175f12acac8e7d9789343 -95bdbc98a3a912ca055d799e288c5c786dc0da4fbe0cbc6dc57a609af777c78fab1c7b1e4272bb2899f87b3e494a92c0 -99f9935e2515780999e2cbd85bb8ebe4bf09e99c1952c2843a4cf073dcda39b673f19b35b76885cfa5a2ea4ad13a5ad8 -b8b622c30b16157341b19cd2cbd762ecfe4d530aae4738406ac3c7670b566606796b075d1afcb236fab2323c850c9343 -b8bc4394c0351645fefd3f5854217bc30247f9079a0290d31831a1c44759e367b231bce707a9cf1d7f105cc56bceb6d8 -95548b61bc1dc7de0561fd4aac3c035c9aefb2d6a14f8241af92aa5b77a51f1654f2e1596299b4d86014c80ee82003a1 -b1f898a9e9be8874e4b71a6fd5f39c3b4998f03cfe15275c14eab2afa6049eb6e606acdd6b25dc87b74dcbb2d0da6e14 -aeacf5cec4447067d4b3697d9d3351ebd75d364d95aa92f28df560e1ff5ac8cef957029d950899ccaf53e514d605d148 -a97120dd147fc3357f6668107fa740b2bcb1241bec2f8a6e6777273cffdcf59c5e16aac952d894d95976844e51e6f04c -8737de60bdcb31c2d2f024c1f39b3fc780a366b62b85b416d51593511d8eb7198f2746529a58b63e22e85720e74aee30 -adde4aa20cab0d548fe86223e5fa3bf0da7d8ec33dd1d76c86619c7788c3812e1337c76ae28cb6166bf5c761aa746fd3 -955713a9bb719f8f4b2f33d73bc8efac08eb2624de91faa5c6e36a765367830744471c34cc2962831a395916bbf349c7 -b2eca76ca5124f7b2328c2ce3acb87a07aa90215bbc9c481702cd785cf695b7901c27ea407db8d3a027ea2cecc96ac93 -9012c21b867a809630952fad4afcfacb8c4e20298b19a7c1cd060002025b38f9d34ea97475f761e3f9f59d3f7e12b927 -83d4f757b7cc01226f1bad2b404ad2315e0290aaa732225853677fdaad2baeef6acc64e1c8663a7803031f50302d4c16 -aced79069c89b201776926d1ef4c4fc822336faef9d5fae13e1dc935321b4c0648943cc8989871b906f387c46fea59c3 -911c240ea7e03df08465a5b5f4ff76878acadc38febde08bbbe031e5fea0a6f66a16ccb6ba2a26551aeb491bb17a90f5 -b9ef1fd0cefd5fc034539fc59c84b8bdf8cb2299f565124c883750426109e99a150cd2ca7681c074d6b55b9730606f77 -8031193d50402cc84152a3b05e361c66ab389e091f653d8b76f164881b36fb31813d3b011f5d5181abe8626fbe3c2204 -b9929c18c80a3438d03d36005446790814e1d8109a07c62fe3ce8d4226ff3872186589f0164e039b50dcfc80f2c7d85a -a340caadc7f41cd535b4a2e0fdfe4d82a4cbb3a71399147c81e664eb0de11409347a4ceb48be3fe5aaf7ae516f336257 -8b5cc166400840c0c16471fec23f7c7ca541568ab7755d4165810aae56d10d08742b6acc82009db1d0625b1d7c872f1a -b3ee860ed90a93db011d3b3736fbdc33485cdf341c72ce7d6efc44dc3ff1af9d2d8d8c915fc9bfa5bce035ff28bbf78e -93d9608f7043d6c50c912cb94c54c11605b2f0bfe73e3b7144c68ce3041e5cafdc4c4be384df921a8ee240726321cf45 -97b658a607029fc0bcb25eaec3ff9d895269df869e35aae003ad4f7844b711b46479ee849124acc88a85c8a10d6c613b -912d1b2f1fed1f57f64c7ae2e6d6a20b073ad2513f81d2610b98a76ba9ff86d9ac54dfc710a000d4f3cb014a03c1fa27 -9306587b7b2df4d2f9562c918ff2d98e9b68917847c51427b62392eab60dbc91697f224bc0548c56195c7a446742d702 -a86e55ec5bd24d68997f39187f75f75d00b2a289a856b9013282af945e424608ca7ec78227039cf11fa87ab9ab740d5a -9782e3af956e640f62f12ec3af390d8a7f40d170d5e171eee3f2cd5d04e8711728fc3d5e18c813a83d608b4d3da4c18b -ad44365a38ace92680fe0f54fcf901fa4fdd8f229eb9176dc1182e634720bcaa6de452fe2a31d7a4aeac5af7890c296a -8ab5ccc21ffe87c3dc111a19e7ca54d9a09ab86316dbbfa50476c1fecfb707d119c245dffce2d0cdf1ac8b07d25c0f89 -8cd763b0173382e149a357569e32686a93cd39a872fff633e48f8eb45d0c5b05a3d73ab30892110249439ded8fbcfbf8 -a75c40aac57ba9bd816f6c1511d5a5236d876285e0ea1b3f36e57824b2d114150d8036cef7aa8eae26072b9802825e5b -a49362fbf29438f6bcd3cd9ab6de5dda15a8b911d5a82d9d42806a0b9107b22dab5576dea8b731f407e995815ca90ae0 -a94a534b672181a8fcb688165666a55e42690046771b134ff7c68fddcaf61816f08225726198c4a252f94d52b38203b6 -a817438bcba5313d578bded71d91d916cca778a1d668b3dd1a58c662f8e7cac2fb4f5fc6123b4ac9f29755b77ed42385 -84b6d4d3feaa298fca23593b33c407174511377862d182a6a67967ba30333359cc16af2e96ac89f20df1fec8284f00cc -97cb96c771be01dcb99c41f3fd847ac84bf37fcc16f22efc7767c5d2f60a7eea91f4aeb8422fc74a97358b5c3c05c789 -83a820968ae2adc5ce435233e81791f401ab4daa19f69f600d203eb7480787f7add771ed7f414be5b8e9a5c53b477e1d -8ea8a8055b58ed95bb242444c7d736410225d5842a76f9db69722f98c48366e511e4001626f8ac7695dac1068c3ceb70 -8c9bcb062d9395c8834a99ce0620a7aec7e78c7fedee91ad2a1dc28308b12f34c4ca2255e453048261518f021c534aa9 -b9f39f3996b7c593a0c4fc64c319082466e6f3ca17cbee1276fe10d2eb62fbb6ad17f7d86ff92609c83ce96e260d5ae5 -b39f10e2a249243534da2a0a424f2e345e6092690bcb39aa2c5867cd8a86e70563b3d5c537a79ff0365b1326147f015d -854f94bc11ec5c09eb3e51cec1a4e2da0be6af9679287ace99de0183a4523eb69aea00058a1cab4a3576f89a5da7cbdd -92c53a9e985362be27923449e797fdf0fa36f925fa4e24bafc1506cda48258887f693dd4fffb48c03cf0501f08f493d7 -b9ed043637fbf1ef9fe1bebd14b38b37a78a4acce4ec829ba5ec15fef444a10c5c7d37cc8f14248545cb413bc654227d -b2f50ea51925529ffb4e247e1373d4d325da79df8cbba8a0efd0b9e36d98f59db624f4162c9ea67c78c46b155f41f582 -896d49825c7972c22bf4685700abaa2daabcd4c15867e0554a643823ca84dd825ae9c08bcbe51dbe94a25e5f7b7f148b -98a3e529e4b3849f20cc8af79e6bf3f85e862d4597bfea69c3286bf5c6372ab4b60938e194371eb7b91e0efd60b47e2a -aa821aee646edf6f004b5ce6a07f14541691dfd709d8dbf9f4b70a358b887f00aa17d781b9358a8e4c950c2bd6f978f7 -a12033fe8e65452889684632cebbfd8254711fd5abb5d9d3115a7fa944000490061f8452da7d1e05e81d69c73db1e812 -ae3a93f6f7a672b663515e93ad7ec14d074c33de9238ae7ad4442c44d8585c5b36e34ea287d6bb9621b7b50fc169aa00 -a182c7004a82c7238e0c4bbc2a1d2162b9bad932747ec26bc09a3996930595db5864b174560b89f2558290fae51fd159 -855d38e9fba71089e6983c22e6eadc3049884ef2edc3d75cbab7b79a910c274ca9530e759add2d1f9342c29e161438c4 -905cc403ad93bb385fdf8ca28896c4686a3d9a7f8b7693e90fbce68c7fe9bfd4283f4b9c1e54ee246143abc579fd20f6 -8e135db52a7ddb31daf59632f1b52041530b03d84cead9e69464c940ae3cea3f14946b78ee7a9b8ccd1a94d288c545b7 -b337b06f800560b99d138e9b580a48875139b1e499fb0b137e24a2892efe5941cd080a4c69ec7d483a0dceb7303e257f -99a564658e3c2d897b59f555f3d6000a91991d04800a450cdbe8f4796ef76c26f77d1f2ba9e3b8e56dc707e70ad0d34f -b8bbf9cda24020515d3bde3edd53ed741b60e68274acb62c2ccd911463408934725e2e1f902f9358eac23d3a74cd7525 -a35ae3a9878c3535f9f8c7394702cfe0c9b30eafca92d69d3a49a942840261759e4eeaf77c1761529adfcfd0aaf90eb4 -acc63b50eb5916ad5c26fe8c23800ed4d47e391b4f61b3159db04d3bb98921144bf8f2ea06e2d40f50aeae23b5924feb -a843dcbcb97f1d2c250df59d3d35e3788b5649d9845da3048057182469a41a4e3835d3da3ea5ab215c88a39cdbad0f29 -a8b58413c71da3fb575bc80668325d42fbf7f0f7c8396bb142ec903f28a81b2453987e70ce3966f7583f3481947db6d4 -a7058cf788fb7e6352839e74806e4361bdd6cc351d542697e590224b74e1e9477ed24aec8b7660b9133b5e3072f1556a -a09a634d9cd439c60cb9ceafb756ba74945b6bbb4e8dc9d49a4fd44ed1fb6ad53bb943f20175905bfb39a72ad72b511c -b216cdfe8f043d84c9b4ab7048f278cb8ab5037c39a50249f6ab0343ec4bc606e4f464e814d16f814677376fae42432e -a63fe5214485e79ac7f110c165908838abac708c47c568a900e1fb98f63082827c0f798802242fb75881293caf3c3293 -84067591f0aec8c588443a919b549599959efd8c9297672c50f5d8a95d93a31b91e044f53cfcec65449342a5d28a0761 -b9c8d6f4232929af2f7807bf89f959da437068499ba23c5af5a3f23ad4ab90a8969238bc557673678a4f05e53e0da712 -99024d488eed42eedee3db5ebeac63a6ae5765c775155e0f4deb930d311b9d4d96bfe26a3609ac180778f0c9b13f0081 -a0f83967d92b4ad4736732420fb0a1cedf7caff51542c912eb24906b67e156ca222e83bcd603d4e0ad7f9aefa203b2c3 -a2e39b80dfc5a149172262ffd8cb79d8b5dd6c953b2b1de03c72291e239f9b7aa3319e369ffa29ec5dbf6d44c14108b7 -a84622d73da4ab80abf2e9ce68012645ba5a299e164d71e2a8778a5ecd7b5ed92f2b612195095ac321c1e515d4018d60 -8e3e5a8538530c8ab13a1d7a1895cb3588eefedc3ff02fccf776170de3d5e0dead94588eb7d77aac03d7571e13c28480 -ae008dbd0ad4ef043ea129100e94357468b892e274e6f786a83edee52504377938e294dfbd3c45e755d15184fde03623 -ab941cfac2ba6d0040dc297bcab5f8b0c21b6e872b45f1d2c817d6288ed81ad3c8e9eaf15477efdb4b20ed5d5ba3c15d -b066f588357faf04b45e9834f3186ae9493982ee0b82fc9ad853a3dc1509ed9a53e96da3cf396970348a4347ba56a686 -a1152f10212399ab38bb5cc0db3e633437787bb092faa97138afd713c7849d24a10d59a17baea39b8ab5a3dfa3abdee5 -b3b9b9381c6829d9ce09d4db06d234264cee3aff62df4028451599c83d88aecc0091141261f446cccb6f5e66b6b1c734 -ae2a336a95836b3a76e8205aa26737ca10d62fed665b0b64511a657320fa564549347d416b8adfc5630a3f7d3f51544e -9308905cf44f2ff58860a9feadec52ff32604cb4525ce86c420b6d4b5b04adeef12b1992646ae299c05b9bb5e344a7ce -a866f694d7c72cefb6fb28b91a42ce811e993ba027334d79e4eb52fead55d1c659851c059289d22a8dd3c698a6be27b7 -8e838ab58c94bae5ea60eb229edd4d88dfdb12fbd3be50d817cb912507e056423c30dd07c048b7c83c7dbae7e6aba5cc -93b51cfb97605ae6b476b2cf08cd5266cc7e701ddd717816b63980ee81072bbf33f00ba4a0466ed2e11f5a5a50bfc003 -ac82f49c94b55ffded6e9df7d1e3032cdd5e0c163c534ec6a20b8f303c4b27cfb57ffe34fea6a0ddb3c1fe9c59b29e51 -9105a660cba4c41eff786bc546c2cd62c7d83a652f4f4733d3b8cf798ff3bd212b26a406f53f999d523f0da93e0df8f7 -86b25f109246050bad54406d233930a4c280cb2fd0215f3af03b382d680c940683aec1f18f83e9373297836f189c78ee -97fabfcfc7f77864c80ffb36d379a1e4adc211b56d1c2fa71d87f4f28fc426363ba99260dbaefd6321da910422513e93 -b302bc1b17fa98531cfe8599eb2428128df0cf6bc548f5c4342002435154e303c83574940896335d857dd9bb11b699af -afd1c76328602fcddfe2be35a2b00cd939a5d883f7b7afbac676683bc214fb157052db60b0574a6e28b4ad7c1cadc7ab -b738c71bc8b4693a7c1ba92bd6db6ffc29f7cab84ba9db38ef5b3c117ee8ae529eed0c26809e9dd78ce34c4b4447c9ba -86501a7d58bbff4ec59f37f21f060d453fdf688dde2713a7ceabdfd766d5435cf0b2ed9c3d01e8d752e231408e4bdaf5 -a7b42913242edc8e12e75de764ceccf548189c060ba55e487df108dc0da0ab96f4beb1638c1e292c1e0e7ea21a650fb4 -b467e5f6a11cff057965bd6aaecd4ae87548f71e8cd49cef07545e79a9136a7f95815d426b784451160d9e26355e0225 -ae70f550098bd408fe496c0fa76c263d29cb4ea3b027ce2747686ba7e179eeb1f8af1c5ab18b3863da5eb75533798a0c -9336662e219ac87358bee22f3a27b48977c2c5883d416f7d479a165134aa13a77145d90721b42a0287e018fb933fe8dd -979b45e3fe95c75b49b075e0fd2a7f1b3a3c7b742761f1252feba0ee946283f9e6e14f61eaaf67a79f4923b15bfa3e41 -b5eec26acc77f1fe0ee621578d7f72d526da2d09bdf493f17c653745c0002f729ed66ba6625ece7ec13bb566786431e9 -92bfaa50bb0abe7143a4efc9c821de8e450482bd5b7f8b5fd0f27d335010dd21933b29b36aec5ed0335c45b7065abbf7 -a45c66fbdd358241efeddf91e0c31b84aa274724125ae6d8be2a798bfc39962ee6a8ec2a5515463b5e28ea35abed4781 -a24707a9c44925ee749a069927e64c317629aa0b0f78bfcf05ceb447ae58beaa264c3f3eeff9dfa176c26171ffc3eebe -84bf55ad211ee3cc13ea03856b4dc631c26801a75651155c1da26d88c5bac0af0d22e4fb17f8ee1af76aee37387dd8cd -8683169f6bb9763b46bf49a57ddea217a8b6d96080150aa95f9ddaef756538097cb2afb88e4e97dbfd9d9998acb2f65b -8c9373c8618c54828d98acd0f14777d1150a4af1b622101bfbcea1f9df5a4d20047a900f2c26ed60b6350f22232511d9 -860a5b8e2b98a4ffc709d6f4c9024ff4ce807c2c97e6fc05c45ba8fc8a62aff7c7831fc911491fa139790e3582ba9d12 -86d108c5c176c62042b02ba3e552de7759d14b424a31b86925d4fced4ac271e91009609fe50c46d9dbd1389ce77f9ad6 -b2ecd36e1c0c74acd095dd255b101691e564301c67f59cf693b7a2b32acca3107b986689d9e9333d53b87e52f0864a9f -a6d49129239f4f32474c72ae84d3a80141596fb72df8ad5d2952fc5da403acbe53085b249d38bccae43a0c9bf25b4965 -8565a6f889c5c06fdfb0e2bdf788bf1df6033d0993af85bd0029ebf38eddd1c3fde6de100a967d24268e4c722c1451e0 -abfccde4ee9dc18f7181cbe04883ed774f96a3856324bd3b0672745bb2bf4fc4aa8299fd4dc5af11fb7478c3e1f0891d -89ba832468dd3a8b62180c2f823f778d0b336cc8e8c0b11ba8964616e0798c65051e52a4644019b62736d987181f2cbb -aedbedb7fa647f743d0c697314b840ec8ccf6428c92a7c5ee797727893a72015a3ebeb95274d031a7540990bb994eb5a -b932b1315265f49ff4db15461a8ed9a521f3bcbe9fa0fe2595ab0319125f1763f8557c9711eac809081a044aa5b9f6ab -868881db332e4c46027dd7cff82e59130392648b983a7ebb059726ea0ba951edc087c45c72efa3c0ecd791a2085bda36 -aa4d0de0cdeb70a4e452d9d369939906a0930d93fb20d6db8ae3b1bdc6d7d4726ef2c7c939591e101c5fe6e0cf8cc357 -a052a19bdd2707f6ba59ae728a144d79992ebcbdeae69a99a9f4ae00edbf1ba23fd2d30059b3ca9790766943ff74a346 -ad5b92862ed7eddf496318ae7943db51d654f6c7d9365283f6f3a3f3b5491f8d2e23e86f8079e5b944e4132c8c4a7a34 -b173f3a3e0d4845fb222477850534ce1a66e7fcc43680533cd3bf4c9a1a942e24dcfa22c54f032b3fff856cc02f09ec4 -93ec8e7b983a51b42dce1ab37da9d2863cf5aaddbb1b97cc0b33a33a51692ac9f26c6ba0794f868edbeddc8a03b21ebe -a97e8c3704fad405750be1c89ba8bbabc4b8a9465c8dc55206aab0ada8e0cbbea2563c37043ed1169e1b792cb0b19b68 -a3e190d789f48e9244fa1dfd2ca0019c5f5ea66dc463cd683b24aac71cdf8114c3b520ceaf8a2f9df8be17a7a7bb7a93 -87366c90d06453142bd80a496901f4500168ea004d78570c4fee1d1fd4c8a9cbf8d6e15376a9abc038792893f5caeba2 -8362b37b12e89b75c6137ef809d33d3c0ccb3f61b8166aa10c209acb47535bc2638fe2d15bd34f5a6eb6e90c98247ff1 -8990f1ab6e3da208a07819754772fd6d679405fe72508a9df6ff416971c51b749262fccfdeccd9bce051823b0a399e9e -83f2d23a2e6a82ce87add2a7ecec0dc6fbe6eacecdaec8f5273dab91f422f4b2a22d278f10a72fa679903e39828a6f18 -95340f5c35769af7ec7daf3c63ed8dc812117151f644aa221d132eaffcdf2a282ff294b9b70f59b0649f56d2276b7c3a -a8a8525c41a039846c2dbe5f3ae67b21f88ea96b1bf2db8429631d1cd35d2ecac9aba567e78a82f002ae63d9654b211a -a379e0904ccd44e7e8f00a895de5843c04190ed8f8321c69f8dfb1fd2a0c130721812bf627c43ac9fc8139f17d29d4b4 -954b29268d81560aeb1e6c5f9e40a556d525d53e64444870c79225affd7cfa9550d02b22233ea3155dfbe23320b61165 -861ef250357eed2322725ed3f0a54faa178af238505bd8297f478679c146c7e80d2fc4fd26f2ace8791cb1b9ac475540 -802963ba13bb958d6671dc628416fe495682f8977ec295a584264afa0c883fb510c098429be9a4bcad0749ab4a330e89 -a7d1e6637af0aabdbd6232a76e19322b0f475664f5546feb43ab79682b7cd9c2759607bd26515d446e35c8945ce4d1cb -877f2e3442afbb07890aa79765fbb9834da9e01c0ca268ffed62b5557f226517aee34d36e5b96973e2f388dc14c57b47 -b08bec12a00e48bdeec12192169dd2275ae768025f1eadce58652f81a449de44d42a2eef12722a6f53f48d9641272219 -93c8cfa679373a9c181679d0a995d74beeb1ec5d8262fafb0a8d5bc7407c534df8209877434525574f28e3c65d265c19 -96601667870868dbf9eeaede138aa33886f6f4ecd457fcb108d9b1bd2a3ff92bbf2c916c8f80b479aff6d911cba1af82 -8b298b1d2ce662a265d9d666c6d70470bd619505fc37d955b58d55150646fe52c707ded2495ca00cb68a33c938940bd9 -b2c9bca6e5f2dec4c4dd1c71cd4ee0e45914a33c01f7d7c1bd5f4a5d837f90da6b6be4b4e3abc1cfda727ae046032aaa -b11488471dfd7d842a78cac4c3b8edf8edd879188d20f3fda06b24f3ab450256c96b9e02c34fdb82b5180a7efeca81be -b70d876171eeb9ecd5d86ec792a537a6632e0a052d6249bccc0faeca2988d9277c1de4785d56b4c1b3938c4d7f0b7454 -861699c27aeff5f83068593bbdcb43719ae236f1642f68f1ae6546f56ea18309f43b97c985e1a85a8108ef5796e36b6d -aba7eea67b9fbed1383b38f81fae2edafb000253bce24b3e55bdf24bf9b3a1e4d3df7d1297438cabae737fd6ace23037 -b88dfece0f6cb12aecf6fc13f7aae8f734ca14bcef14546ae2c60ee22ab54ddf2dd261c1b66ea57a326d272af0735ed9 -8b55a43820c940ca862f6a56dd58612157f6a1ae498d4068044791f684e8ea37034a1237f64043226a30d9359ffbd978 -a426b5317c68c415eaeb28f74e408971e7e54b6801a6ab8370b2be81edf6154a04e3e708b9d72b8975cd27f6f781fc60 -827388f3e7e832415ecf52e17f17ebc75200d08599d7b10a1a7f2d596d4c107455727d9df5c26c42e23759e37927b715 -84c454d14543d1260bfcce81dcdededdec6ce1246707e91129ed8de78d04e4615d1706802322f4ff026fdfa7ef1f4b88 -836fd4f0e801ca2de2d83d3fe83370e75ef11345770d4b69cbac688384e8eeb0465a265aff1c1388c7a9ff2e8f1c8448 -8f39874099919f326be7b8d0dc84031c28eefdcda6c53ce1d0aa9d63d719e3447e18496dcf7e2b669dfc268b06a863d4 -b146f954a29061034f394dfb6649b019067453a306e664d65b3533906fe17dafee55b5745121b357330014c71b636742 -a32481dec0f77f6d6a03e0752ba1a56bc8427c7c5bcaccc58e606805d8ea2503045c97ac1675c5a2254b53aef49ae9bf -b9a2b5b2c03436fb87d37245c9edf505af8ae0b88e7a5e8756f0e620a0e228fb01acd68d5b334d770c727d0b6c4fd172 -a9c33916f4e5b50807aeef1aa200c9c5c2844ea96397a10684f68e0e84b233bb40a3b6c326262d2ca0096f4a23586a05 -8caa5b91f1d407b868ae9b727ba4aa2705b5cfd0b465d880f139ae26899cc3d98de31875e2e78cb994f493d3e11afa40 -af9bdac94874844502c05ab64399f653ea6fbf2a40d410787e2b4feca681df3d02abfb930a952bc969c8aedc99baaeca -99a96e0c0f7e25774cb47f29954ec5cdd98e6c24787b5272c8f0a6452663ec50ab1e768cc70fb560dd0868041c4eff18 -aec5645076eae4922fb2b938744358d559af37e3d6818deff7bdacab3b71216b8b9487195e5a641db2e68cfbc685f419 -b264b75a75e783ca885213346e3605670d096764888a70fb949a99ef5561afa41cd173bdb80af1fa9d6ee0c8b97f344b -a46e606e947db3eb7e25c9c58ac90109b69043ef447509c26fd716a34858ed2e161120f762df4715b8050e4573e9b347 -96b173f6d3122763dc93d8d9bad0e952bbc0cba53d2c2aaf79daa3a2516cccd74f5d8045504df59d69cf9b37106cd37f -a1f3822e9987ace4cf457f80346fe17287a43ff589cef90e2aae8b52e0bbc651f8824f56f964f1d6e397c53e0d69052a -889303ee671a1deb51a7b56a736ea2b7f9d2eb7301951457217fa0fe0d4c4d79abd3c8075a614c4287bef35db63bfb23 -a5acebc9496cc462523a9d38c675b51eaa4bf555cfe1ffc57cf4b0b38d3bb1f101be1c67df5647e51a1d491a3dba139f -a5c47813ac9fa5c0732c6030e6e86e2db48a32d97b12dd2ce8d92a1a26945557828b8b1e4de05277165af45da104ff77 -87f7131c63a8dcd0d74baef8ab91cc5bd3f6367a6b5cc1f80293d9808f91df173a360b92621b240f8b03fe91c3ffd239 -b483cbed238b8d2b11769e1fa5cbfc5ac8bf14d4ed87142ae0cdffc04984b47d9854cc291daacfdf21708dad5a152e14 -a654a05cf89a742eb1d0f21d592287deb274e23b241dfd48759dcbd4b035da96b921db6337d0696d09c2e9c7ea98fa38 -8c3d475a03a9bea864ac714bd31a3c7dbe5ecf2a94bbacb054fd262602b9cfe7b55316d7e0ad1f932f733448a0948f54 -97f7150932e0d9fac35a4949b8e9b5839a70519c0ac08419a08ba4e45c34228e8df00b64f156f36512cbcf928d86e2e4 -a2aaf6efe0a8c3f67deaffad1e4dc4142f327ba5be6395376c56952a074e2a8816d9d8f0191e1aac26b9dedbb194376c -991b37e00e1375cfba4e46e1e0102b5edc900b159ff8a868a5e578527acdbe9df1b6aed996379bce624fb23f12082bba -9829631c25ad10d03a13586d4509d4fa17f38c564ae49f97ca2ce57171bab650b95151c8eee063d995348948df87a83f -97865cc65b30c8da34dc650af10756b7088ba3128381e024f405c84033587941380df91e1aba53aec4145a62afa05136 -a518a4db7013ff59a889956eb6392a63df5e6940f96292ce929cc42506c203f36906a7c46a1bf20ce425ad4e919df551 -9563f074897461613f4416d163255b3d40be15a76898cbda59d5fca1d18b175ad826f807c77b382bd75115ba7391978d -855e16b9f9fad0e227ca85a56c268c77e2d1f07221829e584dabe9caa925439db8289c56a068a55bcc2f1febf5cb8f97 -a5b88cdc77fc4320865f5a58577d81ca4204c87fae0520d480fd8dc346ac87a6c306c643293866e62c359c454f9fa210 -9949f904e1d44559ca7eabf551112b0e5aaba897c25f2eead5514b6131f8acbb274bf49821a2cc230ef1359a7545fc09 -942f37fb1914dbecc43c588b414ecda4a10b6a7dc378ab5df9ddeb6b2453233dc6a26415fb53eaf10904167c16600a44 -a1540bbdf981c6071c7b0e6ac06e2641088fab0f8856ae847c80479373d526cf6d0ee9ce47390ab468e298d7f85b4321 -b600026df69e114237fd68a945c4e6974a34765faded99b1c72757ac15e86983ec42a504b796c8ec1f004535cd0fa8d5 -b62244d25116ba73ef1f177e198da10e94af2660bf616efd9cc02bda2503ad979efa1d53df28b55f4042571881feb431 -8cbcf56edbf8c76bdee89cc88bd55bcdea6f2c13c1cf1bf2c0c0a26792ca63b72043fbcd46a32fa1d7497d363885cf3b -b4162b1601954df9256362dea851daf2a889efe83c57a2a6bd1e1b9022417bfd08431ab532296c5c320ab4eb299677b1 -a423113be8ddc50bfe92bc9d6bc76055af3024c2b320b909adce68327f9e5012b26d8672d3810191df800b99a1d6274e -8fb97e0f377a64c793591d889cd2c9ab26e6b6fe3bd885390ad6884f86050a38f0d34e9249098f070474459137dc21e8 -8496332f7bc848aacc43f0c24eb761258a3bb5d67447098defadd788e84863226115fb43411484ee6c86d341f1adc3c8 -8033dd2e37663eaece28c0849a0e2284d4cdfc90d4f03ddceaedd5b86c770b1b5eb48751ffe3fe623793021a6334f2ed -b36fadcfaf6a277df14a42e02a3107e68986db35da2166e3f492ed3d6db03c6018d92bb34ab5dc30643b2f165b4135b0 -aa72a29bad0fe78dec3523bf692956d07086e82c56796908733a7dbcc801a7cf949425909b611421da1b01c7c3233e1d -a8f23bbd39ebb4ef3ff37a69ca114d412d0e82ea27bd9a2c0c8836f6b15d773e98d43158652cdfba74855f9bfc764dad -ad5cf7c7c1a68b52cddf4e64cc5e41eecb90d7d191bf24f20ef5978b31be4ac0c1b9da7123cdfc760fc2b66a7c312f92 -a0bb840ee52ab624e1ba2bb5c8ee72625c62479b361531a3172a7b5cb8f53310cae9ed4c64d4728f40f3beeef4c51266 -82a81d048e8c19b7e7f42b4125527a9541f8e9c4995379c58a8968665d2b5356ed721f60877bf815ae247e6aba8ae573 -8c1d8b6f01c3d22ddf8c36f1f293846bb1819b9d81d02bfa146d0b8594e62b1e0f1b05f763b01515691de1b1bd2f184f -aa74c1fae5f97b58b843d804ef1f4acd1267c65898390f2a45d72f8cbcb22cb3b1a8b885a424b104366a945c4372c303 -8673e0415f1b4db544cf1fc39adeef6df6819e890ffaa27122ba1bacbf2aad312f94a140bf4d5253c5e090736bae310f -ada4292eb29e733cd4843b532fea78edb4804295772754ff3f20fc8435a53ddbb5a4088bd05de217ef651bf5058939ba -9362eb2639f4812cdff09baf7917250e4779b1a14dd0d5bcba109f825ea3ba76b2611a84bc91e21ed8364351573bf473 -ac07bbc11a784e5da3f477d1f0512cf7a0ecc0d993f2e80f9259318e6894f5b14bf4aa61aa318fc0ca8c210956eab5c2 -b774dfa8cbf6a784434988549f72aafa15d51ef4dcbe5c69c14b468dead0248e75fe10510c236c8900e4d4a4cc4d4046 -aaa5201e045cd538bfaed5162ef37939b75d17adbebb096a1c2f2b63ac593b55093fef72fe455f8c527b78f5d373078c -a8af4682859a30a3c4db527cadad2867118be32afbfddfb4178280747c5206cb4a827b3a2bb817f9397842a1d1637b18 -b1172065b24ee54b77afd5dec43980000db0ba8182d29933a7d5dfbca6fc9fcc0b34f950527cf0bbc077373ed1e3e668 -965f0095ef53d9c536724d12047cfabedb311f67588d6152b0724d07ef3275d6de87dc7d8e613de2fa28ea38162f0308 -b2fd003b7347774288575c65c217c497df97ba4a187fe35264d2ed1d39e35d862fc904a206dcb11c181c835ab7480200 -8c4d0588ff2ef693ecac5ae22a312d94f545686d00c9ca8a989155cf3360c46f390f3e8a6f521163508aa899027d9ab9 -85db932750cbbb7cf46f72c97afb04bcf6f648d471fd2b6ead9a692c93ee41250d12dd21af0dcd23c2ffb68ee0103016 -883cb8b1bbc38f7658aa3b0464d8b04c141f8fad442bae3af5675103f452862b9a01fc06c2c3c06e607756dbec8fe59d -b1c645742675db17324a7454126760e99a7424c9a889627db4670b5a739a2d3046782ca54dfb44e1d741efe80774ff9e -a6b5d4fe4ff92a050a5bccbea768c65c595d9cd8ac79045934245131b8375cb3baf14e306dfab158dc19826f1f46c174 -a355ca87ac37b82f934d52ab75ac6b8d23c38a9a9409697b6f0adfb959a64ddefd030444d7c96424762e347e6052bacd -8118148e0f0682ac8ade23c1212c24fdc8b75b643dfb86c9f862c0983b14c22dc514f19ce940275700a0ee9a367a784c -8953c4ce63d343efefe2c90184247ae9d3d04c8c8077e46cb481de1b244f80ed1d0505d613f027b40f2567dd78fb12e5 -b4218ee61312099e9f65c865a6e697fc6ececc11676fec8aef5b9799ebcb9a561899e073bc0dc22821165184bcf1567a -96e53184516e849a92f9ad6fd9fb2a0b1dacb6027050d40e7052853f14f7f725784fcf68d8d66468249d176908aaab6f -af0309854bd495639c7426059e5f2cc7f3c62b96684c507e913839989b353f4225162c251296f2de471c537f7263bb2c -98d5b1c0135e475b5a4a13dd2424bcbeb3b0bbdd40be2818b4f95af28e95b43dd3561dc194974981afaa5e3ee9eb1768 -a65f3de843eff34dc413a6cc3dd740ef3a71902792a1934bfa328bc185a4e86e08a61858b6034546eed6ca8d1b36a3aa -a8eab8bdffb2feddd4b9b7853cba152f57a54d7b0dbefedf0c581f620044bafd6318d7e6bb7d0692b8b51e44ce4bcda6 -aae01d858392cd53fe52c5cfb29274f4826a15c4a6d9b3fa1fe55f10581e559cadc5864b99ef1d9460c54a236887ca74 -8aaa676b466d9ad6f90eacb5c95c43b5d8a7c161777a16a5ad05db9b85d5395bd6a827ed38a9341deb1761986791929c -b9a659cc348db89f5037d1adaf47b3d617a6ff812f66f87885dad841eb306d5f6609d65fb045a92751d99b82808640d2 -8a1b5276c08409672ad39a5d051ef70f34fde64cea77fb9c46124d78af67163ef219fed9e4caea228115c8e5d13b4d6f -b46ad5c5c6de77b5edec17ed38ada6fb63ab7cd66be5b57a4e37a267b9259f3794ed7a9662a6ba3b3ea88c3cb5e6aff3 -a0f683f9fdafb04583e5c3cdaaef18c1756348e57d1868faeb7a091034993874d38a064c5d7ab7cf77efa182c7e53d03 -8f76435e23cbc8dc7f5a87fb5ccfeb872bfc0fa7c76c19838f2c5465b9b60944378a7af5b37ade81614efe9573ee7711 -add037cebcaa3c78a5e860b8971e6d4183e6c8dc76edb04e959dadacbcb2ce2de8b1c2307ba7835c2d6542764c2ea080 -a2eb0a2d054c159332d5a18ef543c1769e037ad5d9fbdff224a27d6fd82e80405a529b37ee21f8d3979bbc3b06fb6326 -a2baca90282fd708882fbb0668e8d8b8f83fa51787cd45f86704a9a1579e0b5ebf91c0f8af24c2b5d7b86fec7ddfc3b3 -b1d6fd2da2ae66ca4352f50684c909a34c9b99640f202ab36bb89bbd6539b579b7a04b48a3829c2430c5940ac021a39b -b1541deb6ece54c26572f4a4494a5f474852ec3588820005406269e442fe9d6911240fd64bb2ec36e24c337351e568a3 -8e16aa6f9c49d3e9b273aa8cc29ecd01d68922681c35c82abeb5faeeb3fb0e9df89b473649e28c87b16ffcd694d2d510 -a2f06e7da40723cd9360e042eb36aaea98e1e7bc464d3f0693f091ff55e417ff6a5450c0135457db5ee31ccbedd4c09b -a6edd0e2b9a06d0caa3afae6a0be76af246a192cf5f93c219b156aa5c175d9859b2a0ba6ab654a79227d283eb5cf6cf9 -ae6d0ae9a9d1b941f3a150deebdc6ffea11e9caaaaf5e5557d9e7f66ade224e67b028d41b646e9f6b57e7e92749189cc -aba3b61b423b5a1b744540c5732b4d6c15b3a20650f983ece43264901e43b776cd35caa01e0ca1586e60648b8a2a6c10 -ad79fb54357484eea57ca4ec6b77a142e138662dcafa36dfb978ef328a723019092afa7fc8692434d84f28176b5ad969 -997c7ab0a7514ca2624864a1e152d2130adf235815a12eb0e006216c4fe1b984e02fee5bbe58355aa55998798ac5bf89 -a9d81f9192a62728ecaf45bd308261c2f008af1e2797e223250ae62cac4438632e3fdbe8fb15ea62ef8478b1704cec83 -9168127f09f30200e9187e13c0067fc2481e1af74df49d22b5de7b48b82a56d0f2c19bacfc9521ae0b1520cc3dfd3bf4 -801890010d3b3efdce0602f8fbab3658e4a088f90117b099e08eab19ab1aeb837e20cf93b78c06b4a6b223444fb6e216 -90a30e3d40c230c111251320be19a02e7d4888078dcf3f8869ca29d7be724d1a724f087639e134525cd7e0a81f139550 -ac303a6337d5b7af335d853ea52c13e608b0537bee5b818b7c9eb2d63742cc3c7fd2856d0b996b9a2e94805c7f87c114 -a11e4b6e5585a51a556132a5aeb565cf86b0d2b2c983d033efd653bbfe6472d2dea5a66a1c67acbdbaf1cfecd0de37b4 -946354743a96b65cf60c39fc5386b7ac026a1ed64ce30686965900a73cc594d0964588452ee5cec08ba079cd089d436c -af645f7a4eccff64b4a38fc90a57524f37bb809f0df45eeb2b58e7b850673f341c7991904f48f3dede366f4d300e22ba -83196522898abc5ec71a60078a2c1085e68ea744ca69baf69fd3f6db2704aec328cb97cc81c8a9171fb3aaf1f7b24178 -a53b710c8f1736fefe2ba041735fff78d20662978810489841406b6ae8923103f342cbe6db436f3598ddd2d8f591fd1d -aed77e28baf473b462049b53fd19ea0a7f912a59cd52ee38e9ea55f07c263a4ff60c74be6c06d9a7ce56685c014dde63 -8994a271bb2801d57c7cf42ab1387e66412c64746bd1550dd5f2b7d9ba4c89397a5e645604cdb92ecddb7e78918e08eb -98418d8b3b334672ff391840c370a3cf8cb8b0f0b62c94dd6086d20af5a130573ec696ee185688327c115890648c5414 -b7f0d8ce87216871e6422443831b846247cd5720ef12c04c8169a23ce22b596390677f6909a01b147a45e69bc54b0ac6 -990da5648177d20c26dc3d221811343719ee26b2b53552696768fa531914cfd3b5327b480657655cbaf83a8b23a7c017 -af6c82ac32c139e5b893f1c2872f47f51f286486aa48b80f0ccdc4a8c04d7605055af57f645fccf89b1e8ae047069855 -b6478e1bfa11d124ad200c32164655bd01270df97aad817d048c7ae751a161240ab9ef298ca281c9f5325ae76c166f0f -80656ee167fa8d4b78e966a98728dc222877245fac085c4ac36d620106e6d9557ec1ddc4379214c1a33c4dbcde81a9a2 -b16842af2e0ce8f6902a9d7acdd0b47fd90fc1a9aca19521df0f566d47dd8a9d9e0bd8096976e2580ba49ee5c6313e89 -b389d5d3ecdd4dbef69fdc2fb04d896c63d821f826c52519143164126efa607832ef363306c366535c18a9f2381058af -865ad1888cb52019627b885d6acb447c4a9bf3114c3cc50a74b55601abeec4d74db5dae73f8485ff2e84367f5fb30636 -97d1dc43963b02d511b5238b74db8ff83a9f18d6e027bdb91bd66d051bf82d801c28b3f76d5425f89cda2a73841fa9e1 -a6686f0701b6c34ed66edbe945518c01321a31e3c2cfb18fb985c84732930a73e9b6fd2f64e11ee77d2a805b70af6526 -8e6dd566aa4efcd154d5cf5c34aa001fd02094e45fd8403785c15d49636f25c296eae1dc547ff3078fd9d9265e50f770 -986d09ec01b649370b824f8f92e5f980100009af221465ed7c14b1dcc5fb0dbf5935d066800f827aba839597048c4ad5 -a2a640b38f8559bf84e17b8803d57798b1398f645636a7553aa5a0e0c1a6f46755b7e77077be4510de9ffc8b7bc8f275 -88549651874af0fc68da48ee222e88dddd764d709edba3f285db3cd03afb716d26f9135907cb642db3936f922e7268b9 -9037bc6da84fd59986eb0957d804aae030dcfa78998b2150a2c378647b8982d208dacf436a1d0c64edd766966b0e81b1 -96ce84ed7d68d8418038f363fd254fe1b965f4a334268fe45a7dcd1aa1a62972f64c0448684029e102c34fe9ec61cf44 -93ba99e10a41e77692403d0594d692ecf4217642de974eb5383d1429985b9bea6533d1485f0813ef4e7d1de32b8ffb9d -98bdcd80556812cdbbdd8f7a69f6f1d7cffda6784015cbe14ab19dfa164ddd88cac55edf883f471053992c681dd4344a -8347019bce5475b7f1059be4f01baa85814acaded272014df819d2cb37fa6e94b7869c53bb82d6992bc32ba6fa20c249 -a253ce221af89e5e24ba2dc3522116e10b7f54a10f829eb0ea121f9b2f8772e080a5205c70e64650ddbe08d2d6526e50 -af0d9fb9fbbb7cf8957cb2ac38d68ab21ee169b2d02d45b248ff2923b8a10aa0f4189b199aa0edae15d115f5cac5a82e -b0788499e6f663ad1da549f9faac5c6fed2fb7a62133fa7b04248b5db8df90c1b2088998c60bb153e09b351692064069 -a516362a13e88566ef3a7031315968b58abf53cd75ac3848e810a9b3fae54ab35f014a12b4bdc281418bbaba482ba0cc -a49c6372635fe1173b12c750df547780ce41f3cd87fdc8e7815b14e663e8532e9eae7d3353da2725e83108e4a75b49a4 -8465563a21256ab7140f08f24d853d3c46b52a42c3b396efaee7235e424a9eec92e36a088b7fa7237d710d6240b3d2a8 -b5e689aa5f9eb85d424324b120af75449d068e832fb0a2d4a0ded9babffe977b40aa42af5c3c08b0805281095ce0d85a -b11fffbdb735c9fc8d5ebcba5bf300d1ebd2315b2ec77f76248a864eb4523c01c4c66827e6638253d9cec06f10e8804b -a2af078a9c2a194dae54dcb427c4ba6dad6ee747d271f3b6cf7ad601d2d9d4df6d81b3d422e7a2c3cc6ae7ddb02f676e -809196d33d7c1a6e0389e79df44e31f95d721942057ac42f5b3a8102aff5faf9337c38110f316554c80c6aa98dc55803 -878380fe7ade20dc6d9ec52aa5e50f0dfd34abfd091f0d9f5e0a291a128d12f9f68cff712570ac1c705e6b92e3af47e1 -a571663c17e5d175c80af7cab390bb4321c29f775350a32a210503bfed41c5dccadca6bbf0c12ca307d4519e0ec7e3e9 -86c82c693cb491093e5372efebb71b4d4208ee5873d78eb242e1e4fb19739d00e7c404ba4eea5f0d989e7e05085140d1 -adad7dff03f10fe3bb23402d89be0006894013790e9c1f70404c788ff4ac69040899883fde6da139f600a12a5f979d0c -8e07a2fa09c14943d85b27902f9dd91e8f9e2b36a016219a42841e733df73ebc164760f018c727425638230f294b5d2b -ac967a24b209ba09c68128228639ded0e64bda4f3ef55ebdb9823ec0538ef3b14185ab7fbd4237496bedff13be04b920 -98217ab6bfff5e6c1ba271e288d8c06ac745aa1ec8bdd27f0d309ab1741f2ca21b6a5cec099d7b5bf072203e27878f1c -a0489b7bad0a4d4838c2eff854a583afc0b38aaa3cc11ff41979beb9b0d56068da6d720428b5f7871fea0429a693c902 -8440520add696bda61419dc889d654d14e96fa2a76b40a4025a834ff6e0c3091747f4458d07a09f633ce36953d17cfca -9527537d0f5766441621221d8ceafeeabd6c3d2de7e6d9826d7f323b87fdb58ff7280639d64be43c664ac944c5d2ce73 -94164c9f13fe33550db673001e160354c13d501df38b3e275204745395e558378d6c040611067a9d2a998f6ba01a14aa -849e51bf310c68200d918c842e222727a49bfde514bb3dfbd7d50b394b7b1b879ab0b263dc03b3067970fe1b1c6de946 -b9cf657519dbecd3fdebbde4274741fbae8ea9254836460bb31ab2b2f80e811d2da3db977ac06b37e16b70ffe977a065 -b6597e56705376ff70b3c569a07d329e8c24619e1a1e795c25e04ccd1ee8be4973cfe0e320728f74b90e991dcf99eb87 -8cb69427a5398cadfc6207e6e8c33fec480521e6e32f34d8448a85d013db52860643e805e735688dadeb0adf2c8146c8 -8c43413357c19ced287c67696925f1a158d4a2f97d97a0ca52e0e2ed423eabad837b2e7f245b6bf71207b8631a77e2fb -b158821f160c068c587418e6dac53dde6bc342457dd9e34cee9655534185edc5e3f31f57e38f22e8a1faa57a0c662ab7 -95a055aad56db57097e1e911fe567bcc31594a1e431643c32bed2a6da5bc4df4435b2cb6a7cbaa71c5ac63fcf2a87847 -88a9ae312b7edf2ccb7a866dbd8d38951bae97a11258c59955335c0b14e9edcb2f4e69b379f5117f89d2acac5f4b6942 -90eb01e2550a27191a22eced09f999ecb110acdff34d01d928f96def344c944d712d3303f8694aad070fedb6603163ff -a9a85ebdf9322ff818ad3f7f21687b2059a67b85f60b1152d10d848081d012891b9ea1ad6141a2ab7558c67e35661e95 -b25f6657ef674cd5150f7f49a10c29d61ce52fa5dd061aca7e4787434f71d3b89ca9326140180f7d9a7f61ad2c896c56 -933ff2baae013d166b7d702a970ed2736c3f564a8ce739059952173141992aa47c3ae470567240de585f8c5fa015b96a -a3fc388feaa7dfc5e0010d50fee2a2490f5e7009c098e1f0370468d33e301fbdefcaad83a20cf7fc7a714c75c6537ca9 -b097462c549fefb8369f621a865f2bfc93d8ff70e63c82998b1caa661516e1140693c28f75e5189394371ab557d0c605 -8edd93016d1cfa27ad7ee8242800c8706beccf2bb7c949b0dca2f06c3b5c9c07279d85d3b0840cbfd5b757fb954b21a8 -b4d71375c9e127d9726c5e9b3ff8997223e023571cca32842505ddef567c6fa628c62cd23ec058bb98a1def7ac0d8805 -956317c00252a2a3e8ccc6c3e46b10dd51195de837fabea2523d4804ddba47480ac814e1afc0c0c8c8a386c3551d5799 -9750524692428b3ecaaf6cc64f7f9eb0b89fba94f5ca2e10224155bfd570de837526b2e653a70a967e0bf774b01adbca -ac62f1c1e190522974592b0b1c6c38b527f71fc91c20f9257de2a991af4fb4a46e7db206698f3bdb0f368c186a8a82c9 -90de9bab35eeedc160183e83fc460ba80e3c97a4f21e8e707a002a6304973692401a37c041795eec3cf40be928e80939 -872a90e49b0c246fbc3c48687b250dd6e22057956fcdf72808bba99d4f175fe4bdeb5576ae7d1e18505a900927fe5c8a -b9f95ea64cc4a81c52c545e80c2e6991db77e5202d829f2205ea596c9727aae55cc6551eec1e5f99443f8f8705aaebee -a4f7eae6d374de3da210cce1244f959ee61a49d0a87a19841b5b527b4aafe1b0dbe8f919d6d36ed9db6fb2516df97c72 -ad84458121874036d5f69b69c72cbfdcb3ee5860ecd62442dda4503b024e817ff913b6e3564af7e2fe1e4e3568959cfc -ac77fffb0a942ac32c5b16188b09dc51c7fe098cbc147219cbb72e6af0d913a59fdabff6a2b011b9c33522cddb37f689 -846e0e513beadc4c0b5b73b7efe5c5bddcccbbe399bd0a4513df6f37c56adfe227717c7fff91f9b6b4e26b3d26a06d37 -b131293a482bb503c15a9ae1bcbbd141b415780b957973c8b6c2bb789278c0c861152231e1f8f6452944f50a057c27eb -aefb847d417709a67144de4eb60d37eed3a46ba07454ed30b0a3f99074cb8c26981b4c66e9b6efac79be350d0ffeb93e -a85bc60ecd2993a950e35f6fbaec65835e84f8092d13c4911a533ccc864dfea808a1e184ea402a7603e7f4e8bba086d5 -880a35008a1ebabcf882750bfd957231c561913e13148ccbd3f35fe0d6d0ec6d5d89db450f00162805d14bb91f1e6759 -8b76a23a94d0738ef5e456ab9cf149cdc918254fbf672f14b3b38a05874d842570850dd8e24fc5f3e3ce7cef6c7d40ba -b4956aa8e986007c066a1702fba0a725efe57b8ad422f049008406a0dcbe33c3ba2dd516ed90e9c278fffd020aa062c2 -916f6316ce567aa203e87807753f92fac58a9ddaa5e4d6ebc585f717456914d5bdda9bd806424e47bf8deff70a418d0f -a45b1e0696955a463cbb6a15ff33e1f638c381d2f51ad4de68026d8dd2cc6178c1a99f93011b2b27d739920dfaa66022 -b42abdbad1b327352dafa9c9a6ca595e7c8c592ba9feed3ab53f37bac5e31e8e2e56a996a8ad9eecfadbff8e36afacad -ac4044190ec2080a270104cf16cb2cc5aaf02d251dadcc74e9326b674bf03d3ea74e062ac2edd8517c4d56345cd006d5 -942c1be47fadd306854ff046d84b46aca22bba52256541447adca324934c831186a98ceaac8ae31bb87ae9071b9f5b91 -84cb1baabcc63c62772c4ec78ced4a231ea19af7aaf63d0eeb10799754cbc391a62cc363441f8d2329debc13f11398c9 -b68f9607c522375a1926c92ee5d47e24b6a0744ee4266c13054794e50222b8537a199efa61a6653240b8bebf66b7b6cf -85d90bdd90e476ce808c4327c217d16f5199c8f5f80833b79361afc45f98ad839fc11adca77ca85be7d7921b6cc1753f -9244ff67da9d389cf15b6d7d063955957bccea82c403008e5d3316297f52fae384d9b8f64313ef036c51ac010f5e9eb9 -b5c874e3925774a47d28444722ee1720eecf1c273c09b9e084370d5d7c4bdc28412685fadcc564758b1749b77a1df4d7 -b3db13701cfa2170207c95d8622997fd2f1df206116f7e4884a6e4e42da59f854a46e2bcc1ee4fb8355d02aa8d6c20ee -a8a4eb1659ffd9b0ab7196e7479408b4f3d23a3e36ab1010b5e770772bc5abbd2d101bddbde57e2b88e1ca03c39b2781 -8aa5737eae2ca4aaef89584205710bf4ea84fe6b9649e9d0b3e56d064b218f77fd70b7f16da5e9c00585ce19fecf86a4 -900f6aeeb79f6dee31cde510ed6b6cf667782cd7003cc598ca33100a058d4f34ecce24a76048df8bebdef7d3395a71eb -a4f95cd10a76bba45d2db43a2d81d1b4f3b1aa68b32d0556d87e1b96630da5519d6665d36cb3c7689c26647115cfaea4 -a50e67ead8499efc0f7e25ee5e49fb8d171ec6201a57e45325b2a4a504256fdc7a85f259f806361973af9a716596b33e -b69947f2564f20c65c9f784e235861cafefd52c89f0430cb4ccf43822b21f060df39888bef003e2923ddd459bf08728e -99723542891b1ff1ef283cadbda31140f60e0796bd1e43783a41512b5845277b403f97aba57eb3eefbef408c76874e3f -85eff0dde2069e611c0ddb0c8fe3b5f65a3eb62a658b82b369f5f44638011d060d92fd900db126707b6d84ce4386386c -a53556a76b057f7580194d4c0846135807a434b4aa976f9fdbb9c4879a7f33a6f8248c09fca121331a7eb29ac53199ee -b29af20147a2ccdeaf8da1b5c7eb1a472d530dedddebf0e0c6c61abbfa933bcbc7cb8d93e3d0aa27a5bb1e0bc526e7dc -ad0907661bf039a34380e82f28fc89b4744561edcef73246eb8dc7cbd7b045bc804fedf448ef573bc336e963e43f1254 -a9df6297e309b6b524d338bd0125b285ec8af09e440fc42a4f82c66a86aaf061cd787f64878527f4c677e6eb13a53e06 -a6dde1b3c6a927c1e16edfd29e310d91a4e7f77ca513fea532364063d8c4f804f5f405d11f26dc87e707d4b3631c8113 -88ab16820cd37290d9e99b6bad1fa1a7704c0f828a35be31554c8ba0f1da2923bb17b5a56ef015b798b99da346665422 -99335b6267f3504d5878da64ec42c850d7bc848459bef19fffcd8562fd25981b779cfd1485a2c67edb7a72d3f40a6e49 -806e39953f2f3eb2471a1213021cc11f2d7ce7fd00f01bed239b2ccd16dae6846a5a05e9e7f3729523fd863983367aa0 -a8049858311cd62b13c8b104713d4c32d66284b9986d25f214d5a1aaa4dbb2e5f13ba25ce84c2d3aaff76456dc5a56c7 -84d8e255f875a8764d2b11354985c1939812c1eabecf364d2bf15e39f5df5e4c2041659da4ecfafb9ff7c4be861239a7 -99d2380183985e7a208e4872189023520d2201d16af92c0f08f677079842efd10999331c00289a19be6e6e86bcaa5ad5 -8ffe7b64f9567036f97866c6b3f7c9f9c49ddcce2841e8d40adb42e64cdd5c15e744b9d0b88d5a0b24662288d0b1c621 -a1851770194afd1225eb8b589bc0225b70530f8791e2df8a5fcb1e839f91a3ee0e7fa62757c3a2f04e635a55165c0543 -a233d3d62824a21ad0a71f2d0d5fff195ac7d65ce06f2565e50420b7b775d4d5ed9d3def6a2d6ca2ae8f8f9f11bc8166 -9644a96361e2506e84eb7d1daaf0ce471603e9d488b75b8cbc049d0877bef56621b8bc4da41831593b7552cc78edc158 -a8163b0bb4b7d860610cdefc4d7cea1862565961cbadf9dc80bb64b4b1a9cf29dbe0bcad510bc63e3b5f07331292aa85 -aed2d795c512c32fb9c020d0bb6a4ff16a5b0d3d43b2969754a7d619c353233d88bb334d477bd73d21a60cd278ca166f -97ae28b31690e5acdbf5e0467aec83f17f988161ea15b4baaf613c77d460d2b4b36d9dd3bed1ea9a54c6d72887fb7ab4 -85edb3d4772eaf9985c74913dc1544af6fce60a18555617e1535ae512a151451f4d86f6761330970e0d86d32f6f3a4d8 -b1165b1c44acae6bc3d8d8261ac999c09e1c82f85d5731990ef3fa932724e5825b9b98dea4038dc55ec6dd7f22e918d1 -a5b32863d96cede51b7d18c9f0a8c1f369eaca9f893f74439c0071c0b22fe46fa17ee11b57473a936a34e766d71abff8 -a853384b8a0b7af96c86aa407b4fcf2130533cd9ee4e79e11a8a4b4f4b81906bb1bef7bc31cb499687397766795bb8dd -807ac397d46e4d6c5db395d0c340edbd3227d380efb3b6a1139e151583295f3059df8004db0e88ffe786fba5b14d192a -96243517993cec738c82ce64401fc24eabd2ea80feb5ad8d919b127d2ad35f8214130a454dcf9b36722b0c7865b56256 -8d50f62b0e1d317ad8ca4eaf188cf5deb8328dd0fbab71b81861b52e97f669991156aa143d95e0b11db1ee0dd23932d5 -b6200a9975e18a2f39ef6acf2f01442fda3c7e636a8ed966599d7006ebe2585d252d93351be99a988efb02117b74f995 -ae8ec1ef4306aee61b4d24e34de54ae49b1672a51497595455049a6414a2e9c960c82c09b53fe16ff32e03db210c94f6 -8fce7f1a40ae0e3a65e06bb95945e8a391c6d78d8b9a3a468154062cb4bceadac4bfa0ea3f7a9cf769acb91dd03462d2 -a26072945b36df44820a7d14d1544d073700269443d8debd1c830bd07773635117cb2022448eb37b581acf7a5b68f4d2 -b0758113625d397d96632ff4f751f0e9eb9fc8d7fa95701a52bbf6fa9e2e620ef1dc327b8495dd9a27ec7964105ffaaf -8f1b6e9eca67bffa5fc249e8e27ed24b891a1ff4ae7b57c3a663b8601ae41a0562088f927aa75e6e0e3869f6f197e106 -91111edc465291a2cc7107d6dcff7b08d2765c7433082a28697ea67f72f9b9a7550074c693feece0825027bae9e393f3 -a962233c0012f45a4bcf4879e5feb32218ce879ef33db766bff01026510bb90b6a16a2236c65a216cac8708991b7d6e0 -99d958e36cf64171583455922dfb6efcf170a4dcd71ce2fe4229b0ca6275a3d0294281a67626edb12b4b7bd5a20fbf12 -a53dd036a1e86e3b613fd3dbe25d9907a9c308431b34c3d9be814a6be6dd1604deb2426e05a280488cca65ecc2ab89b1 -b16e964395c2810e66c822c6bfd413e3458aeeb73554365fc67a8bf1b6cd08467424c74cce06074aec1f5a5657992126 -b0dd4dea2fff95eea4f32127562cf174d8efb11f1f6cff9c4397b188171be7964f42f246f9e3fc0272e8c7e4f6df15c7 -b3bb0cca54a8ed932d339932d85e5889e79b632288af160095722646ff2f8e12ee91cbad6b5133052e628aacb17cfa0b -a18d1f4e7ddf82da940625a661f1f810c89baec7995ef9cc93fbf892c3cdbec467164c4013b73cb2c4ed9da8208cc8c4 -8c5fdf33a996c71f907f1bc90ab75b3c464f7a9eca8d24af8f1ff283f4814e6104228cfe4844ff69ff10b2d0b20c2364 -afc4282baa65c302195feb2649fbb53c1c0b3b7e7ae0c70a3342b11a9af290df9df4f20a7d7544014e3edf3cebffa820 -a45d4b0ab470f413728ab94acf048c47ad08d825cecc631c06edfa9aa0d6c33ff02b2fc47503f721b86a03eae028315c -8b8b6a7c45b222c8d3b6837c2689380e38c93df27ca5b5f02d6c3b299dac4193c7d4ee79b079bc36dafeed95967d68d8 -95ce009531fad05f74f71420ecf737df14e906f1fde4047046267e9774f784f77370cda0f76871ad953a2c47d55a90f9 -9574460ee565dc68882d87a344233273fb1b8d7aa008b4692bcdda50fd2ad0049dbff033d35ebec446ec58a22febabbb -8034ee95602c07c037e1141d3d5002ed6b692d206fcd19f45a0e9827c1c36bce8dff0169f10bc8627061f860f26b7064 -95fa6cc99477b603e70fbc536534f7d109b6eff2dda0ff3e8e5cd18a79dd54b05f56d653df6990c65d5eb970fd43d425 -98a0f4b8ceaa63caa0dc40346a86442cf1bf03d4686d5430adc522c46db7aff953daeb7ceb9048fd59490472e84f8c58 -b29003c373c5d41193d52c83ed64a5b91bfaa6de1493d3be85eb15cab6d7dfde74e01a53c44c331df89cb13eb4389a98 -963dc5cbf7f3166947cbad21a7f7e3ae58f74bbe4f1c425c80a821f85baab7f812af95c4e8f4e403246962ebcc00e1ed -9783b623e5f15d4ccf9d25a2bdd95309813d4fcb5057281a27ec547cdd755adc5ba890ec8eb3874fdcc04f66a51b384f -b7134853b9712aa36931d84122e80e959bbf6b4129f9b196347ee6fe2c4ed35d93b2e52d4c2b7ed8d97ca8565528d743 -b59f48ef6cb8cd4d561f8ceb0fca576ae34a950725a67e294253eb230e252a9a0dc0bb7767e6aa73dffd0b23c5435bbf -b8258e1a77859c26ba35cdf94c0b9d9dd55a9f5389783f22a3b62f8a50f536ddbe1a6759973f74e7b454808cfd08c6c7 -b574e3a13dfc7645a31f1dba975ef2a34108984a7a889c86fea2b9374d74bdbba0b5e595e5af97d22413b117c1d2cac4 -b7d01b73ab2d37c6c4f623b891cbd9f49cf1d95b82dcfeeec1c076da87cf86c258c488417363acd2d7a9154b7dd278f1 -ae6bafc9cc1c87556c78ce39d58e9d8e8bb627716970f914793de49842d6b9b50401471c9f70bd0559298ab693cbf73a -959f555d27b78bf54cb28f5294a172cc3104abcf0dac8a01a1174e09d97d789e49c2d16c1edf77c0457ae196454a8d41 -82e43b2090c11c7cea141b2e95a1a536a4f5c2420f953cb1fd91431e603450e6b3c88fbef6b0bd027d960cb892c945d3 -b406417316a21eba0da34608f4d050c74a189df953456bb892f94828ed763a67d1f71e7ffc51e8080d8709043e35d29d -8b02983e18417649e0e07dcc44c686d399bd67a289c934cee7e1f92032fd06163a1fc825b5dd4288c796416fe399d3df -b64a101687eae9d98b609403ce53115e471e6ddcb6f4ba47c237609b6a9f963a6f90114ee619e75e2b128058036f4ac2 -839ab87851c8edf4f2023a8ffe9d9087f18fc87169469dffb575a78d1184585255ac0ce5d55e22293bdf84f35fd642c2 -a42aadf6ed8a5fb2492489b0b3668cf4bf8454f012c960d1ee9a4067bac36e4f8c51274b653f9f032aa05ec7b4384d4f -851470154b8d5c8589238d0081f2eaefdfc0d0bb915d12680fd9a2304a3992c1d350dd9821e6272949d3324f3252d8e1 -8748b4069365c2235440f2401136647520d85d4b9b4a901b714b40a363a8888f0333fa44fb7e8b500a409653a9a7e089 -91c8ac7b0f46a8ae17cba495a9bb38d3b41b5b5a5b941f7a7381a7f9ad1370a20e795057b24767afa6fc0216855ea720 -ae0c08b6578d11a4622321e8e78c353613988f035e1e6a13389d53a8204ab8fa2b234daefc7a125481d06f9a775fb0d3 -988f5084ba69961ba916b1e388b0cb98fca8fe8deac78bd7a67427aebe1f996f8c79b4169da671e3f4e7c42e5c8315ea -a524e54d1bac182dc82dee82078d1f3a4619ca19c66b4d2ef5a225a422d1a6a233c304b22f408353d29e05367cbcb233 -943b4d79f90c04841b2746f4b2d1cb7aec594ed6f0299a821c3c025d5d9084d481e137c6d95c07a97e0a5273dca22f4a -97d59b2b84feae099e71d2d00cde3865edb35ca0c97ce037e337d763453c33100e06819a214bad69a0b41627234711d9 -96082b0ad8d75dc9cce0fcafff082a235106d52850c1ffddd5629f07736c0422cb266f4b2189ea2da9403ab6014eeebf -8a08352718f0081ac3308da0070c731ad7d5a8c72b05541cf3b20a81729ffac171cbf82c920f48f02726eb3121b0adec -93d061ceff8c77468d2f787351e3692ee2f52042190d7f860bd542ef5a7e37bf8dd925036d7ccfb673fb734eda6601a0 -a72fa4fb6f77f03774ec42b8c3e53b1cb22a86446d28dc94dce0f117281b7f6cf249902e7a4b41a9d16134bdb4d4f2d1 -b472f53ad487af04f7fe60eabbcf246f84d159ad6b120be7c9a85698d331f705b822fd82a460a8e93f829275ce2caa21 -8028156bf31ed106bb2f5b0ee2efbdf59415d77b22b91c292249966376fe95250139a3bdd28ab32579e8ebfa36a25b8a -a1f43d0cb9f221f964b7d8a00dc81e787c9db8d9a85da462cdbb3de88e704d7650aea4286d7ca1e33b25a7606e56f822 -81c8cbd8dbc0ce5cd333849fc85e5cb9403efbde519e38755cf035f992c969d6219e5d212955bbdb7e2ef75a30b072e5 -a709e193e52b481fae8b32051523feb2b7ce5fde57553be93b74717714072e992f529cc93e3087a5b683f91c47ab776c -8fb3de899dd7a003bb35a3d3ec2ee12ee1674d362e95c7ce8d8730e23e5ed5c79e909b4224930baae8adbf2b46fd4dec -8056b7b2e2b10fd5d48f9a8a1cbf844e6654da3e724cb17251555d5baa0a4974cfded12319c9d18fdbdcb7894954bc4e -a35f7b486956357d0dbc4b2a4104cfe4e4118089095018527f93b282646e3eeb85b07cf87acefcaf325a1a6b30e66801 -a0708e75513619a454971c48f111740f710c870c47c780847f16959637b097d6eccb9e85322b10db0f03ab3720995323 -8ab9f45b870cddba63d629d987573d106a2e2fc3c7653d48bf89645c87b4c57607c79bf648d7ab6a6e8cd29732aa7625 -8b61b28758d246c74b5fed9608d92f03f664db2d421c4ac3ae9b6021930a879a59ec8e61d18b275987f5d7bc3e80f4b7 -a2b3ccc0386dec926c907a0d20416dc2145b5d2776d1155de7411da25e81aac915817f6eee4bd26af4c9cb8ac06dece0 -a9d45649fc25edb6b192b37c669f48db1ba950b72ff49d9d1ddc83b3c6d7668cd10f2d9d41e1aa01f35176e0e83e2d21 -b2df2c7f21bc636572359fac7c491865863ad10d09cb7f4a199bcfa246e1dced483cf2d9439aed421605de694ef21216 -b5eecc458082e18d949dfb27caf0482f0e3ca662f2d42f9230411a0e57bcb48f11501ce8b8f0015a0318eecc956fc7bf -813eb152034300168446cedb27c55a1cc2c85c6e7c3ca7e104bf7590f1fbd667b7f59de3a1ed89643493bf6b58ee8de4 -95b3f830e3dcbec1062d57a3d760367c9129e2fbeb619d2e24d5ca0c31b7d2750a835822b8953076c8661cfdfbfac522 -92501a1055bb5e2bf3b506a7d20919d555d6397e12a01a9830c32b15f47b66bc233fd4cd3033fff2f4de8e5d527e793d -85d1de62e2389b0a54bb66364f289bc7de6249fa0bf3acba56f6842f9bcaa79ae3b25a116d48f56aba3bc829caa916c9 -92acec3fe9446c0c2fee3c1602bf3e447a5c2e2dde6aa81d0c641c1d9718464952cca7de4087de00a1d05c38ffaf320c -8906ac02aa464a563c05b615b8fd1c3383129bf6c589b707aff1ef28f8981ea55732c9c76c7c7909aeefe2d34ed859f7 -980d61aa44dd326c7f63cd06fa3d1933de4bed43210f4afcd139b75a09c3807491eec558e614a7dbcc7370c63677f94f -81371c929204b3dd8e6aa1b6e83370f944c8aaf4527bb297ea4c39a6c27b09a121d10dbcddaa3e1c257888f9b508c275 -b6ec123d9a3c3f1a998561541b396ae1ce6d1258dbf2f2d2a1a102927088d4d3a3deea7d4e07ab51ed8a474f15a92a0b -98368213a92717383708cd8b3f4e829f3a6c7f325d5767b477d9d43b3d888757074b6ab34edb40b607faa7529ef1aecf -875a5535c2f8a157597e285d9f103ad59a5ce00fe0b5d6b2851ec308002188e11b271c10427218695f94bd76e9a01cd0 -831c6701291554b78b6e7a73982706a21660c8f3b65e6c08bb731d4af287cd5271b71ebec38768dfc5f28b1a38e7ea86 -ab2a6d4e3d28bfe0d28a825f9bed7e7a26419540601c2a51dd746de5ecba9bc06f4879da2b1ddf79a4eab0710b397f4f -85232f5ce0db77e4ff13b0a3a808bbcee2692b58b2641c2b8c401f5ac2d23f4a22eb694e61d15337e5706b98fa35b147 -b158b2100ede7d122b16d18f635b91354517635b64eefd38429451eed5c6b8a1308c922e20bc5db6d8bd377356873cad -853460bf4206c194cb7d1b749c2b2a44655e192ccbfb1ced7e38a8409b90e973a90014a502f079efd044e20d2eccf7ad -95441948c94ed3c98478d7bc11050fa4e68bd6d0320f306407f82459db5238bb05e4a7bd00faf05f032f9edfd77a5d70 -87d563ee65585d9626785fbf019dbce9f43442abd2259c5cc6012fadc350086655bbb9efe99835e1f2f90c8334e62c2e -83473c4a7ebce1e84bf9c2acc567193ec21f353a6c658b6b3c1f2fa108eb1aa80b8e6b19ce898f1e7eb7255114ce7fc7 -b060a9f583c5f5ed3dfc0ddc1f0fb7c2f62ce70c2c0c6b3c5c1737d277d1dd0d6c3ebb0c7468f9890098454ebbb430b4 -b695327066765a477abf8e47d56e7a70d602b9f96055d01cbfe848985b263f845bcf9af787b288c4a424006afeccaaf7 -9576c4f921ac9090a1b6f8050e1db5eebddd135f2611f053ccb7fb6db1525a62ca19a68679a68d8b2094c0ae5dd9654f -a7bd1bebd1aa82034dafa9b850a8713b01fae9d886fa33017e427de4ab4f9ad8c77f96d7a8ccf31d76ccdf08cb2b19a2 -a90f7a48aa60ba7dc9131d551e5576ebd092ef8c60b33a44fc68ca7753f6bac2837ea44d154406d0edf36d38b467616f -889abad81855ad90ca13156e6110da0edd8917f69fe57941225f4d37f0bc2c0e8629f4858e5eca2404467b2d0770a196 -8856e8e2d5ab5a549f1b9988dcb45a63703d4e60d2ba8c4bfa63529ded407bb9c35a741fad10828c02e3b98fe45f3fc5 -a12440e3636f03c573cf59411ea99fc95645763a0af65d5668047d1d235c2e65d850fb8e7012e35aad63410724b2d62b -8a2c5bb29f2e18ee9ba155473d2702721a7780688f917011bc11430b2ddcbd96acc519f568ee4c4868e7af64f083c28a -b22053c983f20054d0badcd0910388f325e0046c5a123aae150db230a9a669d8cb02249c9b45cb1e95fae6b8256d951f -a4d0e64e3f1e4123c2ed9c5aab5b0eb6865e3f7bd53c80b29cefcab388e2c2c3cc58369342b69318fa2255e609415fc8 -82788f75d9324aae66460f716daaed61bc5d5e794f104b48ec2dee0b0a25a7a899f560ef41d7466dffeac9136c4249c4 -926d5c134defc9c7fecf9323d49fcbd7335961b57a97c88d1e782baef198838e2923b6f1b43d6b78609596bfbb65f6dc -a6210531f3480f2392fb733553dd544fe4e7f0064ae3f7f18210d7d221f9e19410e95a17ce89d17471ffc353f4d846a3 -a08bfc7ee45a90d82a2f73367c40d9050a78b35dadc6180c07274282d7300ca6c379948601d0acc435b78a16dbce21a4 -a85ad9b69951110bfd288a29ecc92ddb804e17416628c847d4c21e2eff6c5ea6b7e15e57ce0250ff9047b45ab3932458 -9863feb37d7f0929c59d8bc78a129c573161ec97e2130b836d3c72a3c3e6918620fe2a6feeb74f4a6465ab314b6b7244 -a9e37cd529cb2e21917acdb167bc2ab126cfbe991a49a148265e3e6b9a61bfe9da8b0e69d8bc34cc4c6036f422a2ee7d -941ba451146ae3c0388e4a398f44aafc3bc462a705e29d4f5c615989f76f559527fb85537de359fb36a4a167fc13bfa8 -89db35c2b6bc54495dc41c48bfbc940044ec0f39ec927c625842b042f74074e4999c8907862adb83fe5e93f27ba20f1f -820ff3255a5ca539217ea5ec3b1999493af1df68656f2d7c6b46bee636517674c1347af15be5440917c86855f9fc2444 -b7364e829cbb6254dd06d331692c2f99d22e68105aaa443bd3f492eace596d93539aaf83c1cf91ce40f541397522fec2 -b58bcb261b108989e3c999c4db3c5a253cc30c1441c0fab9ec181f3f26581406c09302ce2cbdc1d843786a9403023952 -af4560dbcd82314662f6ce2b0834e38cf15e6d7336b3535aeda976c664fb0a86153bedf3214e406e2e9477bd83ed60e2 -b7ba7a37f57a6079c3592b6aa6bbb9dd0bd7d1089566d744265a0d0c4bf815962d943740db23f225c53062f9b3caa6ba -a34b4c068b4974535a30a5915e187856a5bfbd8d6497ee41c16645145ffc08c27afe3a2bb11d2b65d294bf5ce5e47470 -8b00f16aca70cee2cceccc6f38e7c6e557d31b3ec44ce045eaa25fdee9946477d8157f6d9409e868ee151dc0499e2fc9 -aad25d2f68199dcd5ca056377db1254613467a760635aab5ff5f97a9c713920160a4c1440336e6fc027abe50c443253c -aca7ea8dc24d2289ab53b6333244d33a5f7b5a4dee44e71efae2952b00e84a438fbe8f66b21b89f5dd19b6cb9b3f9471 -b1defb61ac29018ec8aa4a78b89f5671c2cf438bf87e95ad7540fc431e1a8d302aaad3fd65c4afb83f5367720bc3c168 -aa7197ddd86bd09faffa64095dd4a0b98aac2db25e4b48806a0493f4688a47cbb92a21abe9cf2b92561973aaf036d4f8 -b47ef0359fcbaa3fef1a81a36ff9ef60ebc2d33fc387c365910be74b1dd2ac03014448096b97f6aaae16ab1588b1d3d0 -a77f86fc37c376fda10da5bcb49a59ba57f432d4181dcf5733514f9a3d82c873f5ff0f85eedec4917b11d83e0bbb0334 -b6c2832496892712c5d00bd6e2249c9b2709e5600b9bec71592503d615c291ae9756b7f9e0490995cbc49ff55757ada9 -a220b78550b4c516528a5a3c05c18072310199b8dc68b6b3459499551ee58355d29de01f8410747c775484bd1907f08a -9646d151b92c5685f9ba1dcb213b3deed40858630f42d5c4c94fe0ccc897eace1c5b801fdadf8dca06dcab70a5164d36 -a430ddca81b2cd8b521f49cf62621eef15daec1a0dfbfabf54718bcb9f1c3e6675a227ed60bc0dd113270e081c6d017c -96caf62e3f0741c40644d2287e23459f61d0c6f44ce5704b102aac845cf9fe7738a6ae56eec270beed724b1510694494 -b91d4cee532a02a66f6fa864fb5235620000051b7d17d184b3b5251272130c27a18abe51313fd83897333589b20eae2f -8bce1637e1fd6a1855aa28f44c20f07c92ac818883d98757e33c0b66190e3d9d17fab33afb538001641a7c14cd834b86 -b26d24a08ad0fb3cf84565d4c4e30b24c7525f310cb6bc714da0daf2c0ec14184be1c7089584b8619eadbc9eb64584d7 -af74b366992c2773378bbb8a5dfa10241fee606dc94ac848a5853e62505d4e1b5e0de4fc299820b58ac5a8df3743194e -98f73920a0866a505c53ca576e150590ab7c8cea8d6fad6fb6db6eba3a60c01f09b33c91bc221c972f7acd1d45ce49f9 -8ecee9d71cb5faaec3112dbd0ce6f0824b85a250951e0ffac49a3324a46530e3d7c3fe6fb67336a70597f8b7bb6637ae -b3cbfad7d09984d6652540ca77c722563551384b8853e73a79b2fa1c8024da9710af1cdd165aa6d0488d41b0e191bbfd -b03a031e3ba158c8fe32a0d5d0bdf4c53a97fef4c666ba79f5ba99cf26515d1d84c29e70145b6033f4b68f3c8a271d89 -9794219b32ec582bee819e89174b8e7a3f8a064ffcddf42499c947ad69fcd3d18fb5d1e8e27fed18ad64bae9a7d95611 -b286e55596e81fca030a90c9cc6e85bef89f192f99a52f06f35f88584dc68647a351612f9cb413ad670746f21724296e -a46ac0c550585a5307da57c205a1c23e0a74483ccef10f9420c144ffcbb3b77109d48f9a5536617990e47db2e987ad45 -842e5ad46fd831f1864527773a4f841705a8be22054ea0bb3bf7b9f130120b1bb530e793841c28922803d781638ad6d3 -ab70deffb672912026f02f8b3be75e5c3128f30e9ece35347376d6fb4bae3c83c4efe4c6544da43e9f1a93760e993136 -a8f3b4321c5ad29c7cfb7e27557ff073bfaac3a89b1c531337be0d824b55a2fe391a8f8bee6853f95c10e7e80662daac -8f1c88624135c1b6b34601e7ef4eafb4c1d825224b4ff9ac18ed04062585621068d872a7964fb79e016f78a2e0aeb61a -82610794b2d351ecf90a6a6da26fbd77facf87ada4b88b4b2c3065bf5f42684893e72eadaec9d8c36d0c8f8e86909c0f -b92f55a7d4dbc9e864a3fc5e6fa41c875a5e3321f29f0aed80d974e550e352e7c29623e9e51db17cbd111c42677e6e3b -b274aac6b7c93fd65e53a6fa4fc875bb48ab675768e1504d74d5ee7c7402c389419328d596bf7658b91db7adc1cc596a -8fc76ac0bbecdc5a4ab7e78bb2a2be1c4c713db68b70b5550f54c0062c9c398acc33c80a3c7c3478995449fc9601e8f8 -899f4babe86f459382e0fb1be838906dd6cfdea77508b6981cd0a30cfdb74b893e021e7b2ab6bd3f025c994a33b71c85 -a572ff063454eb1efbd9eeb2234c5aa593c8d2eade24b17d192b3bac2592595e770c6cf5d3f5140e43065283d712ad13 -92727709f08d27e432a529a9cb80462172fb8509e1c7991df89693f838e82a1638a7b7412c5d04b11ca215766a78c775 -8bcfd95ca0d9b6a57b18447084c243c01618da9b3e6e60567b9003a1ea96bc8af4064aeb2eb577cf94a770a9fc05ce37 -91f9d0a906162b40f74ae3d356aa9520881b4b496713bc312cd90114d0dede0c4239ac72382172b44da61a101e12d932 -b756b1ae8fd50508e2c552689ef6a7bf2d0125260646cfb58ba4ce18d67a6871585a1054d9736922e86afeb548cc7cb0 -b9eb5e3f66a9a1eaf058b160b2c24b04536a2f6af8037df749bc1ffdd7b1e914217b7106dd9c0603e1f0b1c26369a256 -8b9bc03d8774335ff7024602342083bc8417551b924a94d4ce1e70c157326f6f2c1be9028b522cce183fb53f2e1226fc -8200cfd1b98eefa4d98d5f89d4ccefc728b0359b345f5e766e84544acf42c98af5ff65c7e07c9b4a2a6cb79434772bfb -b250dec37883d06072f1cdd26a1d7082ce85a43338730db37ab5718497b3610fcc917c9de1a1e2141ad5434faf4de50a -96e368defd6860c6854ff2c49a52b9cb0915099ffb3a6725dcbd25d1d9bda4935d59c72f1fbec7f245748f0f69552e40 -aa69207aae055d94028af14037d1ebab86533dd3bddd008977589d9a70e47287b8736cf1f3f5b5cd3757b1e4cb6bbaf2 -97d674162b1a67af09add60b9fff98661b94284a3b67edcd4c2535ef9234298c91d5e2466d024f609fb40df8b77aece2 -b966f875ab4f59238163f3399f72866666c6245eef6a164f31fe874342d6388704038531bcf0aaa3f374830778de5a5e -a927194b4e3bb0185d9267a731d8c5290cf9b4df7cca16e9894b2a1f6cfec8d5a2a8bb3b2baeca2382939ddd1dd1ad0a -84b04774e17d3383ed3851ca26aad77b65f8bfe030469a2ea388502a051175729bb2e6c9b8f245b20c1b7ee2bd247095 -8066379250a64a858e9ebc07e2ba1daf8ab3676f17207721b5e65a2e56ae8dc04403877512494e8ad36398decf31ebe7 -b65c929395693915d9079f0f92c6cd5ee6707167d9c1cf3926eed76dd2c979c882e1bc5f0a19143cf26a2feecd0c5b8c -a4dfe26787c5d40e9a92ea77d72b1f5978f475d33bdd4a8e2639af3f4f2078d5e3205eea3d4ebf1cb8fd7703b75f4f5d -ac4d46ae8c344d4089c5ea2cad3afc52bda7a8744f4546eae53cd60a18eea7fee758f14fbae4a24d97ee432eb355cc0b -b21f051f823cc63124122b5bc209ff7e9e2d5999fbee70afab37a9e2a7b0ee96c9046c78a0996da2d5874bf16944d7c9 -a70ac024842516ba2550608f099ffec0a862fa10444a0f49fdfdc0c2e81cbbeca242b729abba25babeae69d3095fc449 -97912c70d890ab3bbbdeac9798fc53f2ffd163cd7ad287ec894cc503dadd1c077b434d33510b6832c4b7198ecc22f2cd -89cf9874b6b0c4b56981ee63917898164dada5bc7ce6dd6d156c72a05326cd9a8e3ea3e224c3ce11f386b18cf6d49892 -9339ded5500df3eec9b0f8894248223865b44c14f093a41f6deec5ab4cac8585857dc874526278104da70a64cbdc3aa0 -8fd85bb2b7bb51c5257b63352e922ccb1ffc45095a59610027ffdfa00b7c19eddb0bb4b2934933fabf7e6240beb50188 -8cacc7464294d3067703678951aca3d0e569bf1af932609f05ec0b858518137a960f68824574d99640b48a95c748b317 -b6ff6a7d4fa3b733a053a64105d4fadc1751a9743489b15de1354d0747daa9cd2f748c1373a9716ac6db5144f668bf2c -a2a34fd06e4bed3af82a6605f63102908ab3215366cdcae4225fdb2eecb510571c702f450e5613f7daba92754933f25d -924b98a1037b287dbae6bab1e27afc54f72126d185fde40c4ccde3deeb9c3b44ef97a7f3ed7d9a134be6694ec6df15c9 -92f8616aabfa0099ceef2927796c74874a1b8a1228ffded92264ab5194b58e1460271ea14ac1de54e86313ee425e0cd5 -8f7a82718a03d18fc0da76887664926d5b3a68e6700ff2ba3ec46cf6953da75f7370b01e015d02a6c11f48cf7b013cb6 -80d5f80a5df53cec9cdc1b6fed5b3ca8702e5f77163b9ddbad567ced09a4627eaa66d10d2e9e874d0b8dd1aff4cbb00b -80e42816628f28e3d2f2331428c49bcd29fa7eace0dc5b991133a3780ea8ca78c0804e8e0f977e933d159741b467badd -870e25b9ce7d14503920e75228278005fc90c1aeed4fbf6c444d4d79e3203524cf3948408cbd0a3f5e535ac676554a30 -a9fc7c0aa72ba5bf6cc5368ea1c7f6ced95c42820b0168cd9f3b7d4b7b35c8e2c2c75ca6b33707a4b4466989772f34ea -92452ee144ba6e6c4370d5f943097a87bc4da72a84335f130628307318be9915024aac2bb296fc16365e9dc96142aa02 -b1c9cb81ec027f63a1ad9fceacec6b71c4c36413ec01376f71064f1a7e0ce222c072821eba37dd25dea22e7b9a4dccfa -95ef57c181a0cc9f88b3162a72ca45dacdd9b149d93e5daabea378530e41b01dc70875300e7636a3c6b201ebe0ee47ab -a7f18a76871212138fb4e5779270704bfb49668a540c13e2044e46a500da6fb8924e50e7af450e67c163ec44c03942d6 -ad77e31f643424c4c57b04bc4f3dacce61e6a25d43590a079d02ce18b46ec6fcb181eb4f494fa8325fb3270f7d937b1d -aa0ededefd32cec31f102a90c4f596d04f18d1a46272fcf12b6a2e76cfdcd7a7774099727fd3e9d02c9d8a9587bbcb5b -a10b5a2dbc85f99674e59a44ed9c364fbb17483bc4aea21f728fdff7e6716a8fcf25e3ca19c74d0b2b5df791adb2e7d4 -b7d151b4e05b8506cef8d32b3d5df1c7ed9f44072a4b74d42645c18848a1e1be3909a9dafe13b49b53e1a232adb808f6 -916585c147acccc1f5d0295d02dffa39f1a2b8261c6b717f650d7b71622d381b39ea581b6dc559397b49184666fb2357 -b294d3d63400a2e2ae8ccea317f75ca3c3edfd88b7c1b58f0ed5e78c936bc854f032deda7dc7b288b580dffc58001e43 -8791a99221dc424ce26e43dac85d0f44c6db77f362dc11d79f1a937fb8e251dba45f0eea42261b8d3459c11c74e9d06f -862c1ae7c68d1a03ebcbcace881c8df9a1c89e29e25889807ac7761030a7effd62b98a0be7bec0ce6be08434f777c2c8 -852793311ab561a999277a9a48af659c2f9cbb6f45edd7e0dbae5e5c9d15ec4573df3790cabef594ff204238bef099f8 -8332048a49b95efbcd4faba014ed92532fe8be3f20bc352812a068d84dd957c2faff7aeacd8b81d679b38a964ad9deb0 -b2fa5fe77f60a24ffc569d2e679c81b1e882227d3bd4085fe4cebcc69036e3a002a903a99e1dd99d8875fdf3deea02cd -8b246a00ea29351641c4fe18874792d206da6db8fc0e9cb17c8746cc857fdd58bcb0e026ed8f9af3eef7cf06790f27d0 -a1d3b979a2ab624071d0289c06f2ebda76c4879983225bf45acac5ddb2f64b4db7a5d07bf21db930d4203dee28249746 -b5852be715dc25bed15fef741b678561a4c045a4632bdf13aa4b24b5ee0f8c605aabd373c99640dbd4e055da83cf49c8 -841b82b23de8d85cb82de2bca010395be1e8ca1aade965532cf8199c200565576f2750948a058445e95a3fa86067ea6a -b6045d1afe64011b941bed44965b2c3155581698d96891d3fc8dfeca944ad73158b7796777ffe3e0af634b833b632734 -add836141d5be809df16be64a0b1c88fcb3b837e1d6ccea72fcb7c6b293e88648c17aad2a6cc92426aac37535ff55761 -b7ee1f1317397ca3bad0f53f6e043dfa47da6f2e2ad2cef300ec404d7a0f597bdc8384fbb689022c794bc9eca936ba00 -8333d0fa12ff7beaeb839c039d9ecad46478bdc13904b70f012b86df093226c1759dfdbfc896b337ce462c5254befb4d -a92f21b5bb672f3b1581a6ee379b5130f5b2b709f167e48e61a50afdcad96c02caaeec50ae4efb3ae5519fcdfce97100 -8ff6c98810047b5c0fd90dd1440ee7b47aad0bcd758895beb97e45d11fb1ccfe89d9f0e5cd78fa9cbad6ffbc30a4b480 -b4550f7fd8794a5b5b1503ef30d389e0c5155a5e6ebc848f6f80031c00c21eb695b224f61e2d2f2953d8faf18ad27b1c -9776959e34c10934263120a520e36b3a14cd57a395a1789c74d180ff29c68fa73f72bfd8434553e6ec07c9e4026278be -894da0a3369b46fa4a150b166161d567ca7f2269a003636af4d23f95140dc9a3ddae4adc2adb50c8ee49120745c06e5a -a05f644e53fdcd666d58ce85df5f88b639aa199d608d544d9493530b73e2fd74d3099d49d849e629b2db1796a632d1b6 -aa448c499f334eafef76999294fbd5f2f0d9d2a234d083aa8c9ab38b45556e0a9184633933b653f5001bf19a2946e0d1 -ae924c24b44d01d5240eee021f7023a3416351cf86a0290b2368dc2e4b2abffa71bc566f17c7c103cdb0622954d13ba8 -a001b9350a80999ba41fb01848df2577306a86620ee17f08361e84eca12dec5039b6e5a764ca7a665fd0dc143f71abfb -b0251416b702cd48b81941fe2e5442c70e493c63c7ba8d6dce588cd4e025284fe516d22c950d33e4dd76b6cd597fa865 -9651633ff255cdd1b34eff1a435f4f3951df5a048a3dca3e5815cd84a97c4ba89f6e62602a9f9601dc350cf224a64149 -ae20ec91bd6fb11558c41179d3d14a8ab7380ae1b5e89a94949e64e7127c1067099d996fdcc5624f5be84374fbd1d0d2 -8fc0cd5738bae054cd1d68228c4c8f1fdaaa6d9b5328c91f7869188e24d5b42f8f9d28f0617cd318c8003c0ace5aec9c -aa85c436e1b4d38f2d9fe22aa7a2f4d62a2a9bd3958b619e1ad5497e48f03a6af4fa4340f964883793a7cce7ecccff0a -afca8b03c92697bb9b8f24edf223d4f85768d0ff8e143f1b17dc7126454d96d69f1a2d7b4efd08bb2c3242d80a965a08 -80de51fa361f4b6ec06710c60cbea24493a539154aae8054af9ccf1c7a9b5642f1365de68aa66ae06945bd9ff4bcf63e -a66bbd638651241f9d754bf18fcee086b263510c43d4547a5b517f46f189504d8bf6e2340c0c86360942d894d6e55dfc -b3ee246530cacad87ea2f65b25612e94a4a77aac99f3ddefc09341948cd8420b69a0e41a803cdbd53d5240adc73f73e6 -863a9fa6a509f5e3669453697373566bcc50eb3af892eacd305c411b586cd7317c51617a12337b9c8767d7ce2a91141b -9826606e2f178e727bb7d32bf70498388dab3801e1269998563e9317a891fc2145e549f4440b7e3a73b377bb6552d68a -839ac711c3d448d65d2dbccfa74731a8a2ff9f430d884da272c6d301e88284ae4ec19efea46830323eaed13c4a122c33 -b7030775214926dd45d9cfeedba0e575bd117cf485ce4bea47207a9c1411e1dcba34d891600e62235d2c48f5e57183ff -a930e1d2c0ebb8ab28564f11767b7454c48c1d96edb46690b04398594f15dc44d7eea9fb0b2230e04b949e9cb7e4eaa6 -8c26df3156b39d648f5446b5316e13916d3b1c3743bc0fc6a98f2e8a3869b3ebe7b327a1b29c588bc2060b5d506a4cbc -8286f511e5606e6a4d6eeb2ad665c319f356e4d6a8b81e13bcaa6d80a610cfafa3cfde465706ac1e7fc3328c7440ec10 -b4b6ab6c87257c54c58bbabca500d0054c9bbad083825d112fb6c66d5d080d66557fefc5587be461605fc0d5a947b672 -9894e3af61113c4a1746b2fc18a20df938ee99c64de1da27e67daa3367120ce3ded8a338f05f4ef6600fbfb7df18d804 -801ba201c919654e86c11b1e141a3f76e036f484c99fccb6e9db1b14512395659fcbc799ce526c6686eafa383d8e56c8 -985638e96a7abe027700c1cf30921d55e565151158a8f7a25beeb2b8b2745c25b56c1937d45740950d63925ffb49b8cd -b1f2ee0a1740f58bc172c7753988da7c6028842fbf88ff82dc3408adb436993f7fee81a61ef1cc4a6f36f495906b1a07 -89c493ea1d23050bbdda0249137af9d7963e956888a6bc79d022e97610b246e0dee9cc9f058293e4c19d124224f39f2c -8051634d6fb4ed4e9112f02a2ca6e99ea769e1bdc1863bb49e8ea494da17310a5c63e0391b740f065d90710f18669456 -a10225cd0bba00d871ec068d11d82989ba264990c8cdbeb9f856789276b6418c5661ee7d4fd474e0e4c83477ca581237 -a6f99ae74558e426b55972d4774ec0681c98f06e5b08e0caf1806a2bf2c80c04fe4b2090839be5d0f33dcd7b7018f568 -98453e6f44fe89159bec08fd324fa5e1874fb46ee4c8ac09e661c5ab3a86549aeba2d9b955ae3e69f2c104c0eecf8b3c -943efa4ef74ca097a11e5dc8461bdd3ce94d9cd9c67b1e6854cb14b7cf90735c9226e5ea09d8d12467d740d1db4cc99f -91bf02338414ef8f7f1c14ce772f54b9013a029dadd6b05a2f9e0cf25002dfafd9a55fcf8db1922af8ebd8a2a7bc939a -ad13c0f5ba9f3dddd240d8574312205163609cdd518d6c5a2bf3af30dcc206e56f009e8ed1a491772f1f07b64b3dd268 -af88041418c54660212c90533b0717833945a373bd7158cf3d3fb43a8f4931418fb653f3e7533a837c0e4766fc3cf269 -852ef0561f23218a572031fcc76e29d5e75e2b82a2ab1ffe187489205c804a9528686dc818b5be4d5827e51eaf9298d5 -a1bbc950205a77e6eaaabf65dd95dac6a1166ee9c40555fb7a8ed344e0c62e84defa757cb4f3abf96798712e0830a3e4 -81fcaf652daa6e1c7a162b78a2554cbdd50bb437723bd1977eb875c44d5af95ba977d68eedf3bdfb1b454cfbfdb42527 -9941bf9fcd4834e404f6deba52aecf2028a490e6a13127b3ff1705fc5e0a56dc892998d4f0935110d35dc21ff94716e0 -a48dda2c268893faac3d95c0d8f2a15d090b4f57fa0c61dee774832827879e861d79f001dbdf29790f44778c34977627 -8e18505665d6b51db89243e441d3c8081ccbf771a88ccc7d10b024e3a65fbcf0edfae5145c1dacf662be1d9688b687db -b615afcefd8db686bc2672c30a43de32948c1fde99e84d64e2b3f49f0a94120334f41e0019459a54d985164bf3a2df7e -b160c3ab84387b85735bae44f2a006d5a7f108c2b1f864eb7ea178996d6de871699f576423727f68887a35fe7191d797 -8b0f9c9296b4f18e2225bdde1c75b7805d2610dc9bd37a2ee0ec6b367c598911393edadb789b708ab76a237caef63497 -b3e5c20439899ac3670186e79b970b3371aa451d147897e05112243ae2a568a386e18c0625c71487eca89709e704ac1b -82285c1da01a03cbc13749afa50f9409ed6f4f26f7e05f4139dea2d741a8090d03584527f1ad7aaeb58b8f8a4c9e0c24 -a3a5fbd076976de6d31214faae3511c0b3222a55275b229d391f86e463052ab98a511999db879e0fa6f5b4bf70a4a871 -85ede78192003964c9df9f0c2b046b847f844fd946d6a2414e8fb8458402065f4a143829b4a0259cca30052e94148e52 -82325eb2b4c6e7a00315cd26b1ff49f53713eb34a93d2129836009b8615ec67bd880ea7d5f164cc8a0f264597c9236bf -8e4936b0e350e933d53daa3020e3b4f952dcdb42ad674b3781a5438a3899e23ab1853974b9c8e511d456e2f6237a8f8c -80180c3cfe604aac8c30d1cea7e85806f2c75eb52a26a8202459691b511436911232ea0a8d1727d7dc39d304a766afce -858cad2b56bf8e557530a3dab2f3bf888498489305989093fc7ef36cea8ccf7ee83b3974f618506432223fd88f3e01da -b2d3fa2bc045d304f0faa0c58c6a78fa6cf41ba4512bd1eb3d5742ffb3537cd0bf345a9ac2ccaa8dd93b6b85ce032d2b -ae50f413f3b9ea1b653dcfc8518126dc9743399358f560256cee4944207ab03e149ff521b9a3ff97a67edf438ecead0c -a83dbd2fa363200b7396923581f29b03d4e0936819e298aab1c5d3ab24039974a326fda55dede64159d91f1d07f95252 -91f1e053e302ad340551b0b2a82b9d1f317eaa3b9d936c390cd77ce93fe5919c737583d3354e5fea6641b0dbd3bf8148 -b07064fdac4da2b819830b4d1d8845cf45f58025757a3d433146a81235941d8b4cc03707e2f2852980b49c987926680e -a7234cb6b9219b2e44cf44a0ac99e3439a0bd1558d92d4a3ce3ef2852a587d63f68ba89be126de7857ca5295b892a216 -97e0fd1e0a18ba40093b9b5d9fae43ed1c32297d926c15f068ada2a7e6f7fa51194c814295fd14fa8d40db1d7ab7bd17 -a2b26d79c69d337e8c0d1683f62bda6539e85f5f46c12a418df8846760dc92784cc9bf5733261c75c3b475587228ee9c -8b1fd7908c5a6216efb37f4a91f38fe3e8b26d464c39d3cbe751257ac103a6c90bb14cde3dd6f6c34148f0337e0e3c2a -a3b7bd36ca319d53533eddc2c59db18e48a2a97a2aa67d130025bf780d95cdd4eb3f6d4508b56424d2dfc6f40fa4ddcc -8bffe6ae4f0a0a7c5aa4061c088772de1488560a1108bf5f6d4e768437943753096e9dad86a44454b1a92e7d4b622013 -ab3976ba734e3a303812797ebc6692332b10c4497147bf494b1154e38cc816c63b9eb57b9a878f4e4d2f3734c43a7d13 -8661afc5b35096963e48697629ccc05d8684ca5cef96492aeb8fa1fe85daf22ef813d5c83acfc8270ce46353b10c717f -b59fe1532944a5f280f91af49681336de40454c399f67577558ac61828a5a2d0e03c22d9815f0b70a05ebc25a55ec554 -ada663edead029d7394dde0b1e7ec6d8e3ca10c95cc29d1aba12e8648166a217345f0a35a78bd47c56a0aa3d9cd62c8f -a49c18de620623d8be54bfee982fa5cc68717895185e70b84a824fad88689835c533260317b1f05cff4be3400a1b1528 -b8898d2fe51bc10f5aced8d1e471ab7db65a1e4a9691fcc280ee5e36ae2971e1fcaed347000e71d292d5b50543a60dc8 -86eed3fa826564a932c70b610c46763a9b030a2dc284cc728ffaceb26da7d9b48e55c95ad181ffcdbde4a8efea0dfb39 -85117f830da74c05c04794503ef928aaf26017799fe177cb81ccce47f8275ccaeb4456c0f915ac06373fb1caa2a55896 -8b3a3636ac723052025f799089cc758238ece57ccef1ee74e39df3afd0fb27b6269b88832d70e14e33eec9b6e86ff917 -913586214ebd2644ec3b4cecf68bb1671b7c2ae5d1ecee03585cdebb72d0b645fd362ed59962601e59cd15989a6b85f0 -94667f40b6138ec2989d03f078f9dea3f30ae7827127076cbc0838d1beeca36060a2eff63ca49b08e6e9b4d5bc392f58 -b9d96388b59208ba8bf6c17ca3b2e56c5fb4d9e1a3ef6f4d65e66ed1e9edc3ab938768009de32d43d9060e952e336731 -889a30f693e02b425614e4dc9698a0a178538577b48d0f617eed51c93f5f43dacde14f6599c91269faf99c73174f1437 -ae03aa684bf06aa7d32c94888963ba4e7edec683cd88ab18dfb139214dfc28f78e57cf81bea4ed5ff83b9a59d76afbab -86dc4ef045709f7a782279fdc017f204317d5715efe3627dbe70aef9cd5fcfa241531a033ffd45685f6ab17d4332125a -932e005ad5d73664be4826b1d854ec6b65d353477b0f06a9ffc84283d70faa7db784b5a70c971bf74bf09b6407090702 -a69744de3938b7d3d7718a49fea7d0513280473da341c0937e6d03ea98fd719ab3f86c2e4fb15b94ea127436a058657d -864b32fa2b2f477e711069b205d4a24610d3385b67d6d0edcd0fc66098683e6b1e72b2830c4dc7384352e02fd99d604f -87590f7d8766a2b89b653cb61b28bcc646c909a678b863a3de7c62f6630ec4afb375ffa1435cfd08d454c17a492bab1f -96a8be6962da42788dbae496fb2534d7b1290e961cdf7b38297d67ab7551cd5aed49880b5813c9a883311d95747120b1 -acb47e5c1e65e253bd097a3a5dc17ce309026e3152acf8b84728466432e68b4f9866b33b0499a081af5049267efa5fb0 -8fa6fcd27e51cd6eb87d194347aa772357e750795b7f72d39c7b0a065e638f38857d62bf6bad07f9fb57f0ec438de855 -875e491132fb6dec8ce5f28cecc8b26d1deda689e77bc478d9049f12edfa41c420ef624db50971ed72c9701bec2f5e78 -a30ddd4525c697c04427f04ab7a6855cf12ec2c41699fd2dbe85ba282d14647a97513a7f42057dfc8a4db52b80c8463e -b927f38a288dcad6ff839a7c3ae0c4305b2b346a04417193e67b87495c31e51c301b55c9d5f3f3c16cd521dd23ba656a -8c1f6519ffef2dd6ee2a43579ea4b341b38f6e48838354446e75b583ece42b14050632e6340ae43ede0e6c6c5a1f1bef -8e962fa951b2e54f421457b0168c290b31822dcd361d1cc83ac0549650b89d3055a1d9bcd7e867c477b93df50a0ea1a0 -97f4bb5324e54bcfb85096d6c73eedf5a3325cfd2e2f55fb09a26ec787795a6e46f5ea447b0a01871a836b2640cc8051 -87bac34f222eb285fae3b0683be546eea44be99f03d33831be14a9046be066ba8f82316deb63cdf2da096fdc9045ab88 -a568f8305273c8147c1b77608642c02868494293be264bcf97bf263b3d73390aa37c3c0ea2aae43f29788a639ba856aa -b208071f8ece0d16a4bb8721d3d57b338086dcdccc979f2859975af2f87adf7b451c9b5d34c76373496ba0588f6a70e9 -b384dbde6d7bd7a47c7f0ca23b0b761a632159a270fa26cc2fcb6f2bfb64c6be0ccad780e9bce5bfca8609167abdc01f -b35d96b383ad732c2717e5acc3e5e8162e1e1b03182da9d0eddce790dfaeaa9e909db20fa6307243fe37e10838e937b0 -a99465c3423d401c551155f3eb7edc3a431f1b3af07e9a4238f4b1434595f72b7e25869f3477b7f5f188413058bc52bb -807b5453075c47d2bebca0f8528b4b1505eb9937db1bfa20ca663a365e10f0bb14ccc220f79a34d961cfcfd0c8d9e1be -886d7bfd63f00e05e31e43a611733e1bd37998abd947e4819b00bdf839f3d35b45d1bc0fd96208de8e2b4510c2375ca0 -875725cc90ea1c150ed509badb4b4e1cac0e88f7310591afe2098edc27326ca9f2725cdf13fe1b4ddb2dd45f43866240 -89d578a35262bfc1439e277e0becc22772358983d79e24219e1a8f43af6382e7cd0cd86b47b3d7d1b69e7c71e386c4fa -b6003a3346481a1798041c07b7513a099b61b076d61b33134aa7f6d22bc4788d5e62726cd151bb62f9eb9c2e6fd75293 -937a28d529b020579bd2d1169496b6db569f51e61f32da6733195339d793eca15214883ab54b26cc99406ee1ce2d311c -afe7ddbe703dd177e7bd509c7c7bf9103d8fb793d00a56e3e89a41b3021626dd9d6537ad41e71241c3a3e819f01f3174 -809d5ad8525a65ad313f46dae056588809360528815301a9d340fd7504dd90b6984ef60b8ff0fd12b522520734885b59 -a88d6ed70af96c93b1b55b1abdf395cfa540bdd207ca86be691b32bb02f69d9665fa819946fa63fa3a6fbe45c3d9c6fc -a9011dec7ca1942e6a55e517948ebc872d055d401fb12203a54d9670dc6f0c4d3b0b51d6ffe8b8ffb60af3db39457f3f -aff1df03b9a9f94c3afa7147538b4bf26c3cef54038761090e5ce9bf7ee60c3579dfaa1e9f747572cf0a2cea4ca32a48 -b9466d086e9400542f7f2f4e2d403d29350f8366ac20cf587fb46faf1517b4d7c9babb6b95d8955d51b712818247fcd6 -b75cb5fab147509fcdea400f99f7f8acd23d7958fae88404092670343b614cbecadfa1ab898397592736a3b552b57fc5 -9095f8e0eee696646aabe7806a10bcd002717f4b46a43a99fad8e906ed37adccecebd1a188f7c7f3fa2f901b7f4e287a -a5b02ab5a5656a15c189c9fb96da33df0c317a0897455c15da26d01b37cf3d5f5d974737fe114816ccf342796305db98 -9449e0b6fd4a3be1ab17d1d7b73b9d32cf011249331901f47577b14da0af474cda749ceb3e00c0e201c5af15ffb5e7d6 -8610381608500c9a9d58a15b6037a21a58a122a21324580127e6ec6679346b0b0a4e3f7d7e6d71a1d73e8a0cd1640d24 -95fcefba018ed3616525b2e62a6b63ebb61502b185f95ebacd8c289147e830970f6bec3112aff607d4530e8fa2342808 -96d4dda39123108ce629688f7b9ac23209de0344e16d908bbad9cceefd8e3898b353cdaea61f8a192ad33e77de2f24b8 -a4ac38b0cef45b33475d850f7837ebec5b5fe5ab4fddf08eff4f50e3e8efa8df4d911e5cc89f0a579c5bd332375f3b8a -82acb1661f7b17189471d18181d748ee7be1418c71cdb2a116809cc4fd6fb3c0c83d6ff60dc93c753d78f575c08f2535 -ad4e494f020b604f77ae051da3f692dd3d00be106ffa8bcf7bc2477d4015d7f9a507cfc5fbcdf5c91e5dfbf3aaf44ccb -8dbdcccaf1ef351a20e2b7c5c45aca8e225f662eb70ea961bad9d617139a53e57291e7c44576c5e793762fb55e593c88 -a1582a2a3550ee02c95182c94adcd028268cd5f545706ee8210d1517c505a488c6cc2ffa7adb584a73a6cd9b0aa80d84 -a4a8714f4c0c604102d27070f9dbdc3b17d2f39a0df4770f04754023177d468eda82b842bca0dbd1814a8b8a3c6b7d8f -85f3ca5918f12f0d5c3993054ecec5c1d7af0e089ec945e18e0408411fe70ee5b7d6714639e1eb1d08a2797dc108b6f8 -8473d2ac5388d0b5ceff365a78e202f67cd9f0570211f3a871c5bf029a0f0acf202dc967028b4131497b0ef99797bea7 -801056a91608dc72fc6805c4b5fc9224c45da08645c932b64c0e3ba941f100633611314e9be6a2133d683edd44f8b127 -b42e43a23418c0e6f8a984b9bd604de29932d53a5de1e21df212c3208aa2eecaf970af489d2fedd42fe170671cd17ab3 -8e42810296b90ce0a5575a3a251b3f58647c16adab1f0ae935dc43ae69aaeac199786f6edf4448e66d449963ba2bb00c -ac17e675d5d9895a59a80f23a9d4bb70d5f7259c5b54aa59169fc2b202d39e68c1a48212aa42e4eb177d07906e33e7ee -93d497eba141f2204b193c60d27f455e89c8342c647a76848becd19e9cc23f108f2497653c37534dceafc868b8826679 -b277b044915b67e4fb83f6f8b5e08b3b35c89f568bad81f3b827eb60b98a9cf31b21d4b4b1cb315963e9ba49b4fc3f51 -8b52904d92b2008b1bfbaf2de6fdc50c3f5238758dcfae34b056c1bee3ae3a55e4309ca9e14ff3bbf743f7f20f99f8d5 -8244a7c6ecbbaafc70710123a01e7a6bb73c1fecf3e8b4bc620c5a5159ec6485727d9912b07d05618bad92af02c22862 -8cef71c76198875631471920778afa4063a4d05442fe0ae6910c8e4c25a3ec96c06e7b0949af658d7b6b0b3f2e836e3b -b583b9609c6a82ac7f637c96c36e0722debaf911e44a8c3ef9a804f30480b7ac297061420cf4e34cb8f2cacf216e54b5 -aaddc69c1fb29ecaf4b4c459313849e357fe783d35c91324cbfd81d971308d738d079457deb27de6a94e656d8b62fdd7 -974ebd2c8e1fb175611fb5b73d6ed8e8e05b7f4c8ff94d1c50a4b57fedcc86b1e24867262299050fec5d66c0ee161329 -8427fbfc692100b6cb3254effce8ce20dda5da38971885d5151713f909500d3cc0c17052f0277e8449a0d69426a8d723 -a7eb20b1b868512334809025cd7e56036d2479b3addde531cfffbeb87e70d8485c4c893a085739935665b9d13af84810 -80eea8dfe4d9e35c09e997bf4bd00d6be0692adb6d02104f6dc63e9373d38f40c79e40fc8f5855c337f69470940b909e -98db9355dee3a5f0f5dcf386dd96978945e7056185ab51cf4e4f6850fc1a8564cfacb576c6f87c2f66e65b3f272b06c5 -911fcc4f4a8409a032209957120dd1aa05ef9fb7f6ea08bf24e5faa66b3f6bcd41e00bfdaadd0e4bba82d248227d8df0 -b7b39d74f4c213548df4ad7ff01a9058411b5e195569c19a712cb5ff8dd59ab54a9414ededb39c6b86539a53a0f7fe86 -b8e3a9b5663b8c7f23536f20a9eb3ec10a20677c38575a08830e3f10e6bcef9f573783c327f6b538fc61978c2a5038ff -ab8af9b5f085f8cacd77cc16eb3a3af699bfb2e5b5360b6b291953491cbeb2444e388a994e4433b5d6cfd6078d4d9a39 -942dd57203818d4470a751e222db37c84b384352f136e44dbe57b0a2531024e6da8aad296094c9925030a212c790ac8b -991e874b339863930a6fd667d86cfad76781dd34c82e1d24f013a4d46a825114e0d871f92ddea1e2fdd1a050a3668c39 -a1b9d8cd9ac605e92384049a19346c2a4c87da174e9232af4612a22757cbe3feeb8f2a9f74b4ac1c2131f2fdbf81a340 -809a670228fef54c5a404f7192d1f97d520a346ceebcf401cca959ff5cdc24220a0218800346a73db0570600923b1b0f -ab672a9c4a28e2ef70e293f0875ca602e8677419155e9ad05f584d0958769e79df92330205f4f82c5cbb537ff9e2992c -a73022e3fd2d0a721483d021710d1cff35211edd0865e08a4ba6281341dec7513ebc63bd3c0784e4906936639098739a -a584db708fbe97085bcc65f804abd24e405ef0bc5bb9ba52010c2b42997d600dbb9d722c73675e859dd6eb031831a132 -86412ab916967d693d4d848c32a9d8067f46f67b377b3e650644f3ed02174f6832df13e83a158fa1ade9819c1290176f -a113d6805d4f68703bfa2e41c016e3de57ebcf65c70960911b374d95c089b0519b095c7b3ba111c4d889c100e2fd7b58 -89bc37cf8f222ccd05732f7fdd07be06c27b318216ac2aa8b3388b57a74bb326f50579aa5a3384983aba8255c67da8b5 -aa8d3a2611af168bf819fb5949f3a00233625bca8e219cc1938b6177acb9eec91ef755148c27e902346ac6a754c4b3b1 -a5881b53bb825899fad350ca223bfe4921988544a598173f905cb204c4b3f9096cd16450b676214ad6d7cfe132140f1e -a3b49a3b2a6a2d3d5cc974ac7946b1982f5ec04c747f84dff8d07e647ffcd27fe01f1134d6fad24cdac05c4233a99394 -a4b8da831ede2922bc0a783bc593cfab21ed3b0f922d4b8d014283bd012e179ba03840095844ce269d69b2fc947163fe -85b9b2dbc38f8c95d84157ee815570ba76affef543a7a0d172b138d4a5845a67bdeb1fb21a0d4ab41c69253694f8f91e -89c9660e369d4c28818335b385fe4eb651c7c57ee9525917a846157feb9bc21dfa8f7d6a7fdbd0ea362ebf647c9bd620 -878bc5d2734fdc1a4d672d9503ed6a819316270fb144b44ded691a2e2cde63a4a39d21b28fd42768836f662421a34569 -8c2cb14c3b72bd865860876b5f66cf8edcbb7d1d3f6ebdddab73ee71b0a0af4d730049833cdd361d253f0e9a026be6a9 -86d5224e05e7e5c5223cfee74e4f5b7215e8e8dd6c5aa302afce59b024c27dc323a1bab342ba2956708f012753fd3dc3 -a89ab4377eb57adcd27734553a138479e1521f856a1dee153fb28b58281442a248be14a87dfef1f72ef3ea670078e817 -a583b1896969778875d804d3374abe6219eed208007cb3959e2d65e1a20884cdff6d2c5336ea88baf913b608ada4058c -8d4e75beca15bce8bcd22b4cfbf5a38e53dedb52a47a3fce155da875e4e561ed6a9df56a4d3ca84c2f6f5b9830d7e555 -adfc0ab5af6f3d68b4bdb3a7ffd810dec77458e567deb6f4f37447c653cc943c96059022437963a95ac6d43196084b93 -aba8b3be3f4f763c195c49a5623e6657e994dbe35b605e657c2673581c4eb52bbdea4b010d77ef9f97205742a2195cbc -87da9e343c45e21518f67941879209d1ec598b7f8f9c4d8265c0e2e8514ba8a08ae96f84797e38c1409f7021989b18d1 -888f04db1918c177aadf8ed0e24f6a7bcab555ea0c89ed911837b1da307f459de0057bb6869fc11fd8297160cafb69cb -b5d1e1424270bf9b4dceb3b87e591ad54bcbbe879306fada0cdf486e0edb22fb1e98dc827dbcce67d450cb0546df8316 -8aa0fd06946cc152718c66eb76f724e1782d047b1fab1706a3418ac0903676b6f73e5d64e1c4d013d29e552e9ee78ba2 -aec561ddceacf45f114a9e23bde9eb4cfe3fd7473de39238d84dc9632174fbc369408b2b17ef852d6d16472d42c24c91 -abb378b46dcbbf745b3cec2653fad529431c6dd5b120dc441b309bb7aa5a7bedbd20c60f9ed3f54ab42d2af72c2f753a -9721f1ed94bbad718c8e61ab0fc743186ac38e35b76874e3324b888142e9f3024867d8a289a50aede7948de55907f58e -adb2ec1dad7f8c056b314732b2e5511ff7173a050db22302b64b3d599f7add70946afdf46bd2b1815fc6b490603ab792 -b2f016d3b6fc024c2fc6333efd99e2c4707b1560f73f5f243f5fca5cc7c36faa99491515835de1bc2b4f3e00275717f1 -b99aa14bd756c42ec3785e99f09a589d3ada0dcb8de12a2d3b3803d691ad0e4e513fd4f58cefc0f762e20fdaa2cca3c7 -a5be04f7c022f899d1cdcc3ab5f932bab08f7550f967f386b5e2f473ed0c72cce0054042bfe4f6a22a6c20fed99515b1 -a1cf9c3c63ed317f9f638524d20dfaf957d5cbf338cf1d788252f75276fbe5459d055e13439c2a4412a1bbbffd43e0d1 -a748076793f96602b44d22d3ba80c04c3dc931a1813ce80c079118a455095b45294443c3caf236c0c7c301a0afd34c72 -8e02227b6ca28c1a7f1dc4ca55736f840be6455916a87b23f60a516bd096f254eff56a76d0c4d7ced26b13ab11368b43 -8e2975b903a98e0422637b8fc673c7c2012d56674816f274cbde238ea662ff2c729ae8c56cf95a17955833c82aa1da41 -a6b11eb5d8bf4d5f0b5aa4acef26a99e0aae01513d176edc70bf83f12af59fb5ba4c91c4b49bca8436d5b3847ada5e52 -a143b73aec5f1d48bb14d05e562964decb7293365fe93d99f0f71ec1b2636214c0091e96045efc9459a07e20e8398815 -a70cbeb9352452c91af2b0f3429d609e74dd2521982ab15b8a2b706b285a68805003929400042c233ee30b52471ba28b -a747364b5cf81fa96980b865c73ce37a838d0a482d679db81dd0772c0f56d1c8f349a6c3ded476bad047dda179806d6a -98e512dbd622bc6f2371ee73f6e74eaf0363d691bb7e0eb90f959856d6416eaffc2cdd1fe86d3cb22fc6a5a9b6508329 -945dface256b8dbef8ca45d258015f7ff126ea07d0ac960120a89c3ca188f5dbc8e336ddf6826605235866901ddff27f -83d685302ad35527bf3c14f02d174ed25b1b48332fc26dd89ac924d4f598061e505033b7243a9316f3753f9f56d0fe1a -b361bbf4144fb0e28b5ed08c9ee8c401758ba87198568e641ec1053742972c6095855c1388da0a467d0556cc7de20f4b -b8b854dab7e5019ebbfe3e29104e2e1683a7c1877a4e01b5af31f156f903f6978dc1f2706f7b5026e40c01cfa1d368dc -97f5b1e10f1fa40853799a87d12736ea85684585f7b605d0a6747c18b14c1e88fba135fe3d609219672de0076ab68e25 -839dd856dfe805de853bf4bf47d49af77aee5ba52deb627cd99047aafc4eae99284909c151ff6b8f87241c40e006a230 -adaca5f9b03a2a6ee24832ab2319a1441b163748185ca27fa2011f49050469ae79bd293b9700df0a9f7b074f428249f0 -8e08261dd36038e7f0b4563271373fe8f53a7e9cca82ee79ce8419bd1deebbf14b2a11b9b5333d9d7c03f4f3e47592e6 -81f72716c0b548cb503961963d1ee26469fb034c50715ac9394eee3162047fb5895d481f5ffb8e702bf81f7b1bda3694 -85c183f914d4e0e04402313fdbc2c9865ed9f33919a72b2664bce7fc6ab61454e6b54fd911e71fefe2d84e436f3cc514 -94e786a9b365ba9087f6b5165abbcd32c89a79d806ad3cb744847a8dbc3a6d06aa04e99bda162365c6393af4d62b80d7 -a706a51f3f31ad5ccc72dfa1280e576f95da3d6ad3146ec78a88461609b87a67f5d7769eacf23c41fb44c122f8829db8 -8461bd7681f454d60f5497b46d80c37c6aab5e80ee16ccf04a147025ebcd28f79dc6458ca40accbf26e22f6b5bad0d62 -8e7b57331dd6fce02b7d7ace7c22ba59282fc124f3e88f645397ead0dc23fcd95838a10d5bb95b037c660f806ad771ee -b3ff7867a6c664cb34a3439a6e461d60f074e794ab3ee924032eb6f337b145c4bb8bde6977dee7b950562280a154ba43 -96ca48889c44c3f849a753afd8c4a1624b77ea28b5a87ae1924934f63da96c9fd1e4129805a0b19dd7e46736ad0c86a8 -a9f3d34ecb583cda425ad5e411fdde0d3a6ecaa4e35b3a3cafec29d7149c874b4b1410a6663b45937adefd774eaeba23 -b18c894224bab005e614e6c9d318e04c9088560642ce22b7697494beefdf82c4319ca0550fbbf30ba8e8e5fe19e2b4c2 -83c6ee85abe70d89416aa89e0ddc5b5c8907d67945e09c87c673c7aa6b7fa5d67287001fc77f5dab2cbd96b96650810f -98574d68f754d640c4cecdb102dea0454d01ccebf23b75c037f38d3bc4e1b9d53c0f190ddd23258e5f81ecc9d637c84d -a1ae3d5cd807b8987b1b48a449f6e4f470d0ef4c77b1932239657caa11be1aaeacc91a19ef0e4343c00cf690c0c67365 -b6ba6c4ab444a15eca9e8087d58e376646bc1472e94351722a502413ab19fccc1673c0b51d99e4cd80d217c17f8e15c7 -85d6917e78622be31c8d69f265b7e25161e8706975109b1223bbd7057b3c1040c898c6997993eb1a0947cae7a0b42cec -ae16bcc66ba753ccdc6acdd5caf4779128ad9ae9f688b95f708bf7ab4a57083954908647bbee016d621266c0cf1d153d -80edda09ca9ae6bd29b25ab642952dff5e76b5680e38940ac8d68a9476975a52723e7e35c38760f8a75b552584ba24b2 -8299925f517bae8e818499eaafac4ef035f7fbfa4c01eed4381c4daa3f2cd3a8e34ab41c741f81c8a18c62218c1ff22a -939860c3da499a58a2c15783c88c0956b6c1d65613ae56f8281cfea571cc031bd6edc0f2b995d5aa8b8688786d8968d5 -8f22731c310fd000040cc11b825c911ebe8d2fe51016b7950f380cada1c448476afe8dad8fe653f7293dd4a16e300231 -920a733fb80634409cd15707d16af616216a4e06faf598c83c208efa5e0c50e67fada5ce40b1d20bf97ea8b90981e964 -ab82de22219c63126059d47d9f14a0ba9a600a1cb9946df0d536dbafa819333b5e82e202f4a9218f8d631c28469e4546 -95e4b4cc8ef1a6e551791833ebb63cfb50dfb4c7d5b7781e765f2accb2a5d7243b61a457a3d6cf6517f3548dfc5e599c -927020bdfee591b6aff3b8d004a9ab80f0ca477a7ffe79df7bfd70342bfd05675130d8dbaa90cbdb0ac3f77599d03f81 -a49c81688bbf42be01d63fef035f4b30a687c417b1b9af4fb698014a667892da41b09eb469838b94dc0337f7fb244f7f -b02640055a63480991820136a96343f3345bf4d748c784b6b9deb17ac0006e86ce0c91c3f8457396c2376491a2b5e75b -95b471d0e32861a4684f1b2081e7984ccc8405868a461cbfad6e82779f93c1573f99177acefad1dd2cab366fdb21067e -a72018b32aa3be2a319c2c465650d1884a5b101564532c665730023c8da6988d5608173dbd8dfd7046104ae8d7c7f2d3 -ac826c1cb3212be114bb0ded92bca0339b3452751b16a50d7173990862acc120193d3eef0249064be49b5835dca3a0ec -a4dcf1b3c7909b0218b3046087f1427fb9b4f86183fe4b7eae81e907c9ebadcbbccd7625bce3e55cb7366f9bbb4c71f2 -8abf5a881ac9fbfa5e4bf60b84ff489a202a12f00d7776c4d365c34c152ef1b7d0a7a843183d8440454d4e5bdb9c2be3 -b3abeb78b0799e1d2bf3ad52dbacf49a9a678efdbe98ff0e8050f5573f6b1a52ad5c2757bc71dc1435fcca5a7c19496d -95e0df552c6b4f1b9daaecf7608597255daf06cad9fc63383fb23de8989470ad9e963257d71fe2ee25f611d718dc1510 -aa980ad9830aa0ed3a149cf9049ac289252752030b900eda146e2c626ee15940fe2fe0ef7e894304cee646ed8616921b -8248d312f2c662a5045e4c6b2c9c62b7ed094ffcaad94a680695c7bd7b032cc7f5cf088225225dde5ec0abafcbf932d6 -89eacaba980395c2e758a9dcc1014b13ac5ffb7c1dd435111bf92746af31e0ae1e2bf8e63234fa54fb97e96927f8d65c -b775e27d4dde51482e3018279ec1b3c9100051fe9a0196d7cb2e5c31a599dc4cf55f5c51f54980f5814c67f57fcf4b0a -b08278df723c1545121d1bb04b315607f89d3df8aa516ea6f0fa7668804480724c6695501cd725014290749ae4b909df -827e14e2dd39e8bb3f602c3380f7737826c15588c6449dfd327822869377195e1f928a39af1ac5c3a86225622c1c0310 -82201faa981112390a8068e40114b22b64614ff42f95de48a301c480e579fe459d73f86739e2b27ef2a1c5dceb71075b -843081b78ee2e394745b8c811190971dd5b21f5750e73077d31275850df4c1f48807fc4843d5bf4eb17233375babe2fe -b7cc7bbf4f727dc060c433086b7d20b77c47c2b42a7ec10183c30938260a68142d9b3b5dacbc4dae4d1ec24f0bba8fbc -b9f143a68ca5ad8c9c9dce39bec5d102911726d0b6a865a99f89ea4907d6dc06a36d2b054ac6385b2390087604dddd4f -864c7a48f0713b69b49cef5ae12907590e42b3ad45be0408af6a466c6321d70bb9cd52d17519f06d435019107f704ec1 -b2ac2f1b5c4107a6c118900e98da6f825470a9dab5ddcc53383da55de4e125f13c56d6f9c191511efb2656725dbf09e1 -a02bb8b66fb18256e63d21f380336b87476756678a77241e254c53f962306d42e5bbc5cfaf7b02641644e88c5299c749 -814668631735ea6b2316eb034d04012c4ac6af2688c2ba0fa77055e7b2e9c538fa34058ae855787c127d002637a9514a -b4841bc20f52369c9dbbb2a3297c747028f1f2d171d3c93f9590f8e8d0a89a78e2d1475b062f0ab74ce9dec23df18ce3 -9745bfa428294789fceb813ec0eba525295ee07b8a112ad14f834bd641089764a8ac5f820225b7623febe5cf7478e035 -ada617e5431027447d7a132234c1612d7237597bfa54d0cdc3c733a028b319e6828cabad531dc2e94115b7a3a1b571b1 -93ab735b634bdb94ea1d2e1e3760d343ca3e76c045fc9c98a3dd024da74c39bd21cf45815fb63186f6fa1319f62d1d0c -964371421fed0ddd236c3fb639c4156528fd8bd3adcaaa0a5f9121926df6774ac9a33a44d5a4b60d723787963624c968 -91868d72011cc336d15fdefc26cae88103d5df796194dd1a0f9bee4afccc9958b102ebbad068501663fc94ca7a9f220c -98134a70e43ef446493d59de3075a2194012d8f937833f208741ee91fc1562510aea52d99e273415ed3e77d65d6bcf62 -91f2739db9daf2ef68e61b135ea28668fdf4045d3014635a3d13aaa507876c1cd32d8f373b45d00491958a34d9e4ea96 -8ab25a2011bb5b02ea30748d7b90644b4b219baf97ee9dd6b58e6f3008c719a32004f83fb03be7e5ec66eb42ffa0ef80 -86c11d9bc416278036f449d7c69a328075be3bc5eb40606d45d41878cbd5815e54110c04782c7ff11c67e4b710ea07f1 -8d55ae41430af753f5473be4c329cc3ee579d59db760ee0c3bbaa2afa27f663a2f7ab9d5f49123020733a35bc79af5e6 -a31c238ed9aa5d35584f26b18dc36fba97aa053dc0e013dc9fb1d854ce9824f144fbd6f8eb47459b41b94f2d0353245b -b2decb6e70411ee344b1c5c034a82e38a7d7b5039386ab8922b13da9674575139529d7c09a9c7305e0c69452aacfc49a -b546e794b5e49dc0525a1eb86a83166f38313edb6200f3245b1bbc8fee707fa581679495e877a25f6378db7f3be7a93b -972332197ef689bc9f55c22c53f4031147a50ede7f8e5b22defe5f827ee364213a740bc179c21ef281f4cd0c3bfe7530 -b3fcea592a9d6c993ff50832a872c7c26bf28f3a6e1fb51a03d31551f3a52c3059687a2367df7d1001c0405ad733fa0a -8ec187bfcb70e2f6e82c1d9ef383e8ceda53a0a56652df2063fd7c0c03937d5dfcefb906f88f5b7d4c8a632c26182ca0 -94ea8734e2e3632c081680be7a46a7249f29357a558741021c9c57664eba21eaed03bcca1ffd601e11b04b1853ba3539 -8e1d5e9cb763ede4db8deb900702ac3da78c889af4e5fc67bf475f835d2a63ea97e5066444ca2aa4160c45a99202a585 -adb9a0ec32302a6bee76947c75112be44ec670e4e11e50af0441229afcb0d4fbd51ce2b124477c3b5663340e5ed6263a -af325eede54e8a8276fa532d7a7c555672e219ef5eeb7e4000699201e8e65e116ae684bf3749a9722895c345ccd07ea9 -96a71210b0bd0b8f67d320463763b0ad8891fd6b408bdb94b94199d0f1764e82bff6189aad1d58a94ab0557f4cff38fe -b6308b51474c93c075c8884d8e98a018ac6c84206f1675b519b42eccf451680b307fd930736a77b9d84876e762495768 -9651505e3092ee8ac931f41a5e8c16082cd923a64e2994b0c86de6c2b27e71661667ca38674b3bd8fc27778558cb9faa -8dbf231801de8062d03c048deaf6fe2ed3519e0508280d1f5a84939df66f87d728e9a649bd9a9e40f67f73f1ef6bf3d1 -b0cac85a8aad5db95263876de2284b04088eb86eaa05d44f7719171ae3081ac11beb3057f8fade8b36af2766070adc80 -96ee67e8e8d5b465fdb3b5f47b307693361af0ecba5f28292a09e1a84a6e013a3fe10902306554becb0d8cafdf5cf16c -88761bad99aeb9fa1e482158c6187c94b0aa9c060cc184ffeadcf566a8600a506bc337b46e361876d9510d54d1cfbf58 -9452ec5c63e15e26a05a553a1b846d6837c37aefd4cc0fc11c797c8505e2a9545b71565dc5645dc0ebc8586aacd4eeff -ace8ea72f281ffb82604b19881626aee7a4d06dd0150befb60915efb566716cc725243c16d8e0ccecf84789d69e9320c -83be6702adb341ec17439b7dadb70125f1c2a2fc344076241ffca3cabe10c6ee6b1e356a04f9f153413060ac97bc8f07 -b27b231f577727f33b527d6fc2c890cfebb58093174e04fa500f344bc0786898478977ce0a35fb758dc4385542551792 -97aae28188a02a7b336d0ed5ca20b0ae629c8c7cee95176ca70682b39df0ce947d1f1e0004446a7441063757725006e0 -a57dc495f413e61d9eceeb6ef794376b12dedd1d59b8da59b0ca849233a02c45a75c2eb250cb09f75f0587d082e0f099 -97ec10a5fe330fd3f0f4e57c978aef88a4d6535ca8c9074eb1d3af87593cd9180375906eae1c6f2fb7b9fee4b1fef436 -a50ce5b516c5eb6705f90c3bf820305a7dcbe9ca3799eb5656d5ad7039461b5ceb4d6f8bdbbb09a6c8985b728c38b8d8 -ab6e8c25440e4b95c173e3d775256a7e3ea559169782520a8ffd3e5cbba03d5ea72e97ccb9b98fc72a50c67f0719e5a2 -82ebfd3d95ae27d57370142e45ce43ac88a0fe09b5d9dfa6471e480571a971af69cecd94569b2eddff0799b87e2ebf9e -80a38eead9c3ee45ce16ed44d5d56845b238c152574b7eef0db1d4fa06d1480686d9e909369552d603616f7e5dfd05cd -90c1aff5b6bd05f0bd4f2f9de46a7c602241f1f14d9308a7ee1c04b1da25ccbf60e25471ba073a474de47be3e36ff43b -8560512ffd589a00fdd05f7e141bf9122248d1c09a4c1310a09186ad1bc8e25491845274ff7202370e6f1eab9192bc80 -975cf601c767c9cb9e03d2a70b03b3d0e80244ecd748b38dbd408535edf4e643582fed2bf6f5310f8c9077c2041f81b5 -967959b9eb843cca99d6eb1ed3efb3c66fa0ff8a1c118cd5fa4378df645e85cbb9992ba815c31ef605405cc35ea69948 -91af4d2a1241b7f97eb72cd13516288224405c9c8fa4cbee5a8b77d14df62df799291d87887570fba1484e461c14b7c4 -b76b7ba24913f43b61d48ac2be068f85a6473bafcd4d66bd8ad9412b443888b2ac9786c209de253a922c10741c9ffffb -ad51232fd771d1b76b6d43eeb64fe56d54664638720bd78c9ca5af2a6280153a83163f945f4c717f40c145ead1e10b59 -b7680ee2a6e3ce950fc6d4a4194cf82a0796dae7d144a0118f54c150dbfa0d8018490edfa36d72d62afa2f579f1db96f -86f9168c5e9ac513a32d392d74acb951007090946cb834145c56a5eafaf587863d5f90bba429b428564cdd7179884377 -b21d00fbe4b0fe7b38444a40eff53df998d44dbba3c43ff3be30e553be2cd671c4f01d3d89231c460601b1be65bb3805 -b89c65d5886078d5653796790804afd6d18351c35d349331aec70cb9316fbbe81c9a7aac60b42c0da30bcbe394ab6aab -a159953bd7fbfa5f1648d066b778a4c367644a4234784d4e898243c5f5db6817e758230d7be3b8f5defbc6f042a03400 -a2a04948452af186f41aa933d45180fe4694850e12b96c634c246960c0d1972032b4d8a115b10f495293542e10391032 -9733b372d2cbc04ef576e97c16c1545fe508811fc5b0267b01269e0c6d549ba610fcbc37193555a8838602e178414ab0 -a9bff69df0bb98d9ff6fdb659bc695bc8a96ac69ee871ddf4b8fbd646ce59847d9120c45d230ce97527b4457d2eaa844 -ae1973038d72171feefa8d59c25733c8067d3319b125f913a3b51d1fda203840fcb69342577571967fabcbede4954767 -a53a91e242569ce81abbaca5f6275284d208f03f628de99328d6ad2aa90b879f70288f54002cb12af2b374a99d4471bd -aae34146afc355bb2b1e0ae29ca5bf1d00d6ce049bd29f32c37beae89bd23c38f037d0ad18f551d690c53c0892152ad5 -ab068a2b10eed57944c4ecd616034064beae9e82a1016ff3bc88ce565bb41067da5750584bb16c7bdeed9928572e6f7d -a2b6c8441f4359a0b8f76eddf70695720566716b5c0680674e23eaaeb44d2a92cf9cdc892b1de18acd963359c10f08f3 -b75bcece73cf8b4b26028be9bdc36e242da8c8acdc7d94f2db64474dde770cfcd6e02f7450f47f43a6093e9c3cb0b4a8 -8bc131b08248bee7db453206bfbdea4de356dfc7a474de1266b0bd0ed692efd319a96fa362955f5dda2afe3dea7c39d8 -a066e3e41dd80961d6662877e0b70e750eb1b26512c55834be391d4a666ae5e1a9789537a0cc88d0e43e49565834a3a5 -a805141eddf3bb474159905de6139d68c67d8fdf070bdfb4d819eb76e86801019dbd30670c878f89cb74a966a51989ff -962a9520048360c761180c386b2bc857bb30b38546c24f8ca5162aafff7c4d47deb90852fd2b0b280cc9157cff747e66 -8fdca12bcb7ad173e412ae5ad7edfb0bf1ab9c887f648717c26293a9d47b600458fd1f39eb82d1c403daf455b801b6d1 -ad57b4e52cfda70d178fd641717184d88b48ac96f2bb30f7f964ab44e173dbc5f9fd732b3cc292f7a33559aa512deb93 -b9871bc77623c5cae3eaa36abe65b44fe63dd3466084a263e7e14a9ff72a17e55383eb1afc06ea493d77021c1de45437 -ac1a94a0eabfc05958a3532c4935d93dcb4ae5ae5ed40a5afe9e3103f15ef5d499c61d76bba8acc224b6f0c38af0387e -aaae28b61a109dee16b3c3fe58a81d803d2edeb1808ae49abae1849cc0f9bf14ed3227357b71a6f3c90e6e75abe8db1c -a85d7dd3fd1bc1339a0c5e4b1da73f02c21313240dc04248c59ccd8427d4271ed998d89d42c84d367aeb7b82260a2388 -a6ffa50a5fdd99fac785a76004718102dee20fbf026864cf8ff6164547b94d3024e03b4b2bfa4072e61d3a8415b2beb1 -b930b90aff70417a63e8da0516c426bdd235cde16e54f64dd50feea86925499b4e146d56f0adbf3380ea4d27b3ff882f -96bf13d7c897b3d6ee931e35fe515e613cd61a5ca3ef6c5cad49cf13bfce673b3c89fad4c29f35a2a1eb4f881d48c022 -9711c6439154321ea9853fe8af894c41edf9563bbc2693909347ff4578d281f71fbcc29ec1638c35cc1d74755ebc4855 -b7cecf450348f98e6ec472b7b9e5b627c1bcb438e506d93c7cf9d5d27adae8fc026702df0c6f904a85de99a16526d330 -858ae411c47df1211b4ccb2de5324cc57a9c9fdb6ffe6b6adfbb601f66df1de423c4fde3ebe6ef420e7abdb2fa4376ad -b142e5768667ca28f357d46f3fbaf2022d35775d463f216ffd3ec246db4611055fa83bc42b39728b1e3bb4b950066a36 -85572b1f205e31fd04188603ff240fbe613f2744cdb03d881f283d4b4d4efa152ead22d6a3f0bda58921626d5190ff9c -93a72f016f83139dd0ca9ef654887da9e7c67a4680bfec9376578b7a31d0012cae252546cbeb54639555fdd641fe4951 -ae86940a25be8a6c9e24887cecdfd492dbdf86a4b127b66c6c3966b2f4c151611afc1a78db810e7f787844df32863e13 -85bf4c85a21b87d25aca182abbeecc99dda23dd5c6568aefb20846ab0af6b464c5da72b9ee655209069686b476230b98 -8544918a9250f0ebb3639d0ea917920ad888ae3ba8daa8b4f94091cdc7f0724f8dd443b51021832fa9ef8d1443a2c29d -8007f7c605692effd7cacc83b2254ea8fe9342b2aa47d271166cdfff54355b2f82e9f298ad37c42d64ac8ceacb83105e -8d5fce5180a2c657854a6691c2ce65a6ae50da43c670dea6f12f2f1685f2d4a25734cdf4930151088ad64af806ff15f6 -95fbba182f8d3c154d66103f064cdda5743bef90bfbf534fba2df675dc05af4c2ed9e8caea217b0b3eecae699d1e0499 -a88719f38396b39320a92f97e145412069950afa1c8ec276816b010f709e05a43c7f3ec560b3d24adfde9a1f94f22043 -9895f350ccccf4c8f9bceb58a10270fbfe5e1b78e54902e94cca7e29b233c9caf7e9af17822d64125390d4576f044522 -a2d958bcfd99b62181304b84be177d9be42cf36e522519180e6c2ac9ddf6c02f2fa70234be50bc5dafce1fd348330031 -b924e346f9d13e1f9ac12676118104f88afc79d5888ed27dc741d27d37be30639f37cdb67a7722faf5913e44643cd0de -b8be5078e38ac3b84cc8070a0a08adc3877ccbfb18058b79997fcb644c4b1b9f83463cd88dda3cddbaac549046c081de -a97551e3872000e77b158d2e670bba1575d487af850a5192e73e5f93cb7f647c4c38f24911b0ae700770bc08b65f3e04 -93a8831f690e7263d39785bb1a8f0cda144079acd21434e8e40b4e84d6af1bf6adcec0f07623be8ba100bac7b0f880ee -95aeb3d8e7005d820f3bb2ff4a88bf88d69f5d3a189db2355091c2db414e29dff3f8ce14587684ade9321807a0caeb3d -a630df8b1bbb095339d8abdda46f7184ceb0ed09f0e75124bfbd3056ce4b40bf0856564b68a5a72e2f752ad5a6530cf6 -af4a873472c65befead228268b6b7e5f0604ff192ab3d509d74cfc231c9f3c2c0d8bfcda9c02e1c6aba2f3318769547c -90e4d7dc4e03c549eeffa936de2f71dae77be9f2025ea8a72439562ccbdd1f3e6c146d90c3dab8525f1c2c4e130c8e84 -ac76112e97b2150d0edf5e7c7980aefd930e1830de6c6afca9a05a9d9e8bf15736b6931c930731d197d70f1936ac403d -83958275157d1ba327e214a0648b42dca7094407bd480719bd87c0068af2409f558e725d46e6ff923d63a9fdf60f46a7 -8cdc2feee0f641dd4533ababc7adb4a4a7fb0e345a2821008a5f0cca5193df692f4c28760638c791293977e2ec847dd3 -92544dd0ee6c5aa43f0f4f9819b2e98924ca8b62363fdd2fba274c1315899fffdd168a42b46bd49cafce739ec6480898 -84f5b6af997e0d21e42b67fa442896cbb6cb311f4d20e349beb0746dac9331488e269b2a6a8f47fec11682bc3f6d865e -89ec8b3d7b69de8cf8de9ea688f74b6bab6bf50cbba9fdb9df5e5c8b7a0fe3b5cce963754dc2619f1177a4751e3a92bc -8e5607265c811019e9bf9860ef85dbae80c5a88e5dd59190fab116a2d39030656d405d5d45ef26a7ee69263b642fce00 -840c10d3ef360b66bac041828965726209f2edd67350b1b87ea40fa233336188816dd356a96c16a400bb7264184ecfe0 -aa692abd6ea3c1233acfb967d303c0ff4dbf06040f9f4125569c926a5b2023fee38e6be5c3d903f8b89d1fc5da0c5123 -895f8d6894852f581e58a1d3a38d441b2e09229196be6a0485bb05d4df819652218ec7633bdf72b40b118265a9a86d65 -87d0a49828809f004164bf763dc57a3d53736da639054bb246ead524bbbc756b3b54b8aa123536bbfbd60cdd6daa368d -abbb9231831189aca4c97f2a7282c5152648002e500e5f489bee3fd20e70c9849aa9e580b924074b15566d698a316970 -82a8b321717ec28d78f37a85f2de33826b186fe8ea6952dd998e5c01d5ce43ce6f88de5d6beb04e8830dbd716fee95e3 -b2f28b28080627914071a05bd6e088f39766a1b6fb3d34e4eb8f8ad0ec4f72bee4341a391a378fe8be63746c17a7dc94 -a233eaba4f0a5165952838d280f68bea5a9bc41eeaa6abd074a17a1b21a946f98ab16f27d1e9f0610ba93533cd390170 -8a675908bb89daca05499a19197f222ca78025f0e6d248522e6a499c4858e6a5a8435aa0cabf6a88bb7043f9cef71e08 -b9c205fae160e28ace81bc9d3340f8af7f6350eab78d1f846bb563f8bc6dc8a2f60db4f3c83a64f55b5dda5a5bfe34ec -b1fbc0a92ca6eae5fe919b27b52127eea3402bde2c3aadc981779e56e7f69aa85fe629f8693220d2f1e5c21fc0eb89f7 -80c79ebe23abc587c7ecfe700cfd6350ca8732e1f8e10942cf82f8cb9579d4438cc08168dce7a0df4405b4fbde47e077 -a9db69149199e6677d26ba780ec0ebf19a95d696dd88774d26e56f1ca7e579894d06a04e831923cbaed3d96e0f513c7c -9235c8890e2d38fcc1e742993508e08397c2299503409aaeb96f83f805794c9e4baae8475c05b23d75c0434e15fa27ce -82a89dd908ad63a1c3c1f102f06d94c57da7e9cd00251488842ea78102717b074bbc2f3c8269fa84b88e0d6527277af7 -a29d27a66a29441070c7abdc8fe5ba7a4bb1f86fef7b13807ddd8c575906f7e9e37d68dd8fa0926409d4a69eab3ca49e -a76f20910708b939a5118833acbc9d406e4511e52340a3e542fc90486fa6f8a3cbad0672236aafa5095aed5728a0d4d9 -91bb8d3a58c7ecb8f79667fe79f888536730501a1986c012d358664620b44d4d88f76b3b7fc13ae03c69991d8bb9586a -91f0ce478b207f5eb3afd2997861bc6ed3337f3baeaf06c065bb9ea18ba02b88afb417712d016cc1ebdcfd71d1559bfb -8ff40891880e6c244164557a5fbfe5cf2e1668ff1135dbab2700f73bfcbce674a91718a9a10a00943845eee2960a2449 -8229fade9a4c778ec3faf66483ad09b6a22163f9db2bfa524842ddacc1e9d86f30a280f85f3e2e5d114aced05df03fad -b760a8cc07984aab476f4821f1852df82b8c323ec69fe6ba58a3ff299412164d5ed4321c13bcf4d037660ca6a2eeec8e -abb3f972e3d66fc83102f3d3ce5d9149e26428e2efbdfcf4ab706fed6dc191a4236536ecf7fd0f2ba5b117c63635ab8b -871eab5cd68e6210483a92dae308efa65c34722863f7645725682755f06567132a85ea121cb360f4d3daa7ae5c79779f -a3d3105c7892c5e37ab9885696483c2a9e21ae2543a1254763cda7843c9d911b34b40524701fa3dfd58798cdb5443706 -b7f04dec6ac8d4fd574633d1234b0e11dc79e84931c9feb88955b946e66f002b05fd368b839816d29d20739db079de48 -985265df8f1ccf16df6eb3ceddaf1cdeb708ad8195f213f6cd90cd8d6b434ed934b2a11a0dc7d881c788a3c3f39661e4 -aef74659cd7fe399ada47f7e891f3671c03525648a1ac9881e862afb4d6b0d3e2b019ed407845b99b96be58192921d25 -8df7e13253bef2a14b0f2562c758383deadb25323e048586c0ea73227798f4da01fc1b344a04ca7fa9bf37bbb7e7dc7d -83548a03a65ec441c4752bcfec5676651dde5a93dfa5c79d7bf36bd5590afef2a423cc689a5058da20e25996b4c7bef0 -9069788c6ccaec6900644352337c54493212e9dd6c7d8439828fd9f6f7bd72e3bf418bc8d077fef398cd3136059a0293 -80874240efd3bf0b6e16a1755f8a8c194955f32e1f8d842af597293ff0189ff5f2993bbea01ce3dab17335374e4f82dc -82976e21360d62e5bab7cdb6880a5c0b232cf16d267eadd8f5abad9c1eb72afbed8708cb4070ed3e26653e4015888cba -a905fdfb61ecbadb5973e19f5e4de0fcc95b67e0fbbdbf93e44b63e97dd187b9d40dbf16696eeb05f9a2913c1f05b379 -862a6058a82e9739fae91d056f6cbd4424d3961986c328418896abebef7c34c17b5d7f8fd764075d26901169ee332d36 -af599034da083c34d8d9dbedc2bb935b9ae1ea3c12bb530fdf4eeef4eca9362856451f85c034a759fef4d509ece3af89 -80f645328b7127f2a87064b3c2e17b03bbb9f2b847c2b5e293e10c394bee8ecdaa1d410f3d91dcf2857589101529acf5 -a46cb8e80f38ecb0572eeba9ca3a729cc2e3c18aec7b0120f80352345329541690fafd5a7c829de841c1ae2f99545fd4 -8614aff88db1109e62341e34464b88e3d48ab0ade15d8f28e798c86d2ab8daf2d4102f92bf16d753dbfed160a6abb166 -a6b8fac54762a0fa32c3962731db1d4003dc37c2a3c281f86d073001a028acfdcc1038452fe18f7899e9aca6eee24218 -b5ff71d36c9d05f2ad9a3650b3cf8790f3fd37f8b822648d443234155033ef2a36b194daf12438a9c140ca39a24bdc9e -a90c7c1c494deac27b9a5c7f1a4f094d05c560611e4f52d8449c5bbb4740f5c0032f36777ef751298de8995c6d96fac9 -b916572ee1b3e60c5293b2dcd31c7d22e09e005635cd858504e00238ff76d33330742f25febe0e81c8fae06d58a8c044 -aebbf9858c51349c4e6f8bc58361d84db7e4b4f68d160646a5eaafd2b30d2bc37e33c5c8f6f4f30ceca07d4defc4b4db -a63858c60bdf3e84caa70787a4a1f263125e5677af9e00a51caa094cb653e62ba144a6f00dce4d6b4411c2a68ab8a389 -ae0500de653c64f3c95d070117fdf2038207af58fcf8f1e977edd4e55efcd81d8e6e6d42c537f25861d3aee2add1028d -af550db81d086ba51560421f73ada3dbc187c55d7b9cd9d9a82d808cfddc0c3dc4769cd33a4a1a0898ef3972a11d0c38 -8fdcabffa49420cc665d1125aa44bd3ff221a78d5336467f58ee2f867d5132ac32c9527cc0c1da1d2e46f15b929bd658 -99a7479d6b9d4bab39c3bfaa95ff57b5312109c35660a76c89552d8693c9958c08e3ea7183832c831394b4cec8b609a6 -8e41800a484162826d3ddbafacf62b6332df04a3699adb2426b6540c10da2cf0f4e48eac0aff628ff845d7b73af33050 -a2e3d21c8b6097b3e81faa0904654f64123b8c1394ad2f79b94eb0764866843171ebf0f7c75b3a5671f665f0bd162b52 -a4ae60b19ce4cfb73ed515b06a2067c30ce7cc9c741d46b64d6d78c34e95bfc6fe28ceb69e109fc6031cb9a786407e3c -8f4c4e7ee70d2cb70b9a1bebb1299fbed26a3bd42da3ac5a859924edc3d67eab05f5c8c945c65e4040a63c6b440c1832 -af8e5f12ac7687a55c003bb259fd03a20323662680960ef36778152fdc7a5c972a34ad6ddcfcb056c3cd737f6e917dd0 -ac0bef27e89aab1026316e95d01d251df5f51c3aab3878d85e242786c851ffb1c20b47615571d825aa13da52c6e04167 -a6cc7c4b7e8c61dcae72c503465d53f707fcf0ab464cd88643476685409815b81009720af4837b07efc49e125320782f -a387370ace1d3318324bd6e7f39c458cba2d9ec9237532d4e1b307f305e419ca976fc8136f02b496ffd373b91d27f826 -a2edf48503b77b9f7c2e3aaf53cb2fc55d78d9a5b967ee7195ce55fddc92defae7833a1f3e2f4eeec287a8ef5dae5b7b -b8b9a735b2f4feda7fe78cd81531213ff0117d71cfc75693cfe39f10827c7f59fcdcb27586c517fb49d25e5c4aab4a19 -ab3fff53a4e5de48e46125389c3a6b4b75a4998c62d11f5352a9b5c096547a1c309e6940222e95f4f63e46402b08b1c5 -9510675e0db61be931abb8361274dbfc8c45487385d21faa632b50866997f194e29ed6143eed5028b04dc301fc75b7a2 -b47d23450d55c242f5228d0cab08ba0d1df65640c2208f71ac960926cda573c83ab5e8732ac82b967474403028bb1c1c -83ea07fc8b4a5637f8b141237a6164c1b3b853bfe05a7dc01e76825375882a6a0c57646a0f101e58f7001e4259d7b65d -8fedc52a5e7716c2920cd3350018ed430caecd1776393edb1261f73c762943190c06d89023b935c643de23941ad710a3 -a7e3046e9ec4a16c9e82d02c5bb5e34a13b7e9e049f07c83ac06a47e1a7fdc74e3e4e542bd2936819579740dc442df37 -ab26e108eaf27f9f29bdbabdfdf2f42c9ea2ad2f2b8c9dadf460279b7c9f5211d4b8ff134e23dbb8eb946f51d02161c6 -b086e526eaf8d74c70466165283dab79005e488635da40d3d4d0b0be114744695dcb11a6b448e0d6cd78aeedddc6a942 -92fa4cec65a26d3ac7e57f51dc78825b33a3f3faf71cd7841932b4d6dc5b1383fd48f64654fd1b7a01b6df7d0223135e -abd7f854a9e17d9b7b9fa25d8eb4ac3b4c3ee2b0738526fcc94cceeba812fb367afa2f508b04bcff556c67e69c8f22e4 -8262472f0cdb3fa497a97b48bf46d912b8bc8f8bb8a0be932b5988bee3c994a015f010fe79b92658a462fc3e6c449887 -abff4f751105d2b8eed9855607e78ba1b93d657d961d6457d879c7c8dc16c39b31f01ea24824162a13c17430cb648dfb -a4f3878f951e5da4a7dd126c01350fc0cb9d1bc1fe6360580313e5490c06655c4920d6d8e8b8a2358dbf86c0c5179f24 -8d0bbb0bc507b1a56d6a97398b0ce0e8f43bc91e65e4bb90714303cc9964e9c31a79132e3b8b7abc45ee602f2db8dafd -a453d578beed4ce9452c813375e3ec9370398415d7b95ca2a025bd054585cd036d01f7fdf4a2d109863942b35b187cb2 -8e799b132d3c3403944258bcc0475d0a27eff268ae3f64354a480b3d94be1d031cd691aa7c2dec7242ab8d60b84160f7 -a1c90f4c778921ee5570b9007db87e4b03a537e2979eb39fd37a7141601eae34fd81349e710193b4b1067cddae2de757 -a437108e7a200460701332e2e35dab0e65bd93ccf7567d02250ab04f27bb0d9e37c38063506b000a0b0755590ff8de9e -b77bd387d773e5fe4094011613e2fcecab11d615c784dbf3f2471523673191979e8952ddeb59f86085c4962d48eeadd0 -97298b40a2e9264a624ad5bea377c4334a58a899e08aa29566e10edab5409bd2a5da3872904f679df2811be3522e8079 -b67ae831f6713a5b360b39e18361e01771189e7198cece81619d0c7bdbb669414739da33ae37f223441069dd0310fadd -80555441f0bdca8c11a2d8762b1ce2c1e5b173bc2219c988840aacc91812f00a90d00a9cf0ec41a52a24401172abf39e -8f1524fa24ae27749e3ada13e853c5b48ae9f625d971efb0852c9047428ff861001f4d9d13b3509e7e0d36c7195bbc8f -a02d83ca38b3d2d79f3a5c378071eef81a71631a923efeb398f6ee8aef613a4afd13c17198687dcf9e3c19c5558cd5d1 -b2d1af2926d92d70501fbbe93d69107703de495fc6380551e26e15c82ae1e952c7eeecb2da4931e60f7e0201425c0b5c -83ebfefe37d59a34b2af8a550e4315c07bd9e8e8b69d5a56d7ea445260873e741e35ade4a9c8bdf91ff6c7dc62f1fe7a -8f0922c0f73333136b31d3ce8b941cc8315e646bb1910957ef98009b6bb4caacc6ffec3f27243f168230f76c5ceb9af8 -997d95de73ea163a236d81c195e685ae45f1de8ed1b32d5289dfcf0b48d4d9de5a09948bb34774c22aa89e310452b4e3 -a3132eb85ff3493fae216ff932bbf64c25456d922da5cf77212b4e2a6c06f57caf7e7f653817f3730279d5e927ab6022 -98064efd60b22bd6dc280091a70f70d7c52deb0b95d91ad7812abdc05d87dc46ec0b56b9fc9d9f6828e055cd07cc7d23 -8a523dba4df43d796e35a61c8ca09d41c8f86423bdfe4b38cd35702157de56b20d5fe521eb6b449d190f16d55e86974d -925c3b847ce02942cf18cf168734d4b5eefa50da063912599b4a6daf08b0cc0ae0356bdc9038eabbcf49c49f9e66ab8e -b028a4b2d938feeb45de0a788da0bf536e93605d0234d1888d5c95cae51def9ae5f3d5385a8e1bb2bd6cfe4e2bead56c -ae6da7af98b0bfb1b1f3c1e0e6bd9d6b2580e0e9d0ee38fc3ac8dc24380ec00cd5c2ba60e7630b2c257f534f3e03ce3a -9722ea65b6bae88ba8dff19752508d43897760e4dee834a3e5d0fab42da440988bf4a76eec95d9ff32b4818ef04edeb2 -a23d0f0b35d9b1987d164566fa2c32bb9eb3658add806f488c58798750b7c5d029f58bfebd79ff5280bd40f23c1be9dc -a914a088e4bacb1c9fa9132c674eb0fa76e2a3d9c0f34db86026672a5e2ac616a4e49c694585ae3137e381bcb0556756 -b7805c412077ddc3438a150f62afbaf7c970460c88f50ca72fcda3b186b52c33f0b20e2e84a88d988714c672c65ecc50 -93862bf0ccc1a066df78aa668f1a106a38cb63ca2fbbcb8dc36fb2734ef354554ff44048def81f663d040e343b14bd68 -abcf367336107f5a171ad9de26b012a82021f74e44846a7ed1c9cf6966c6fc4d36f3e3469b505c71427f66dfd7c529cd -93d08a06cef5c34cce8b3c8c67091d328e7abd9dd37d8fbdc37cdbd1ae268d7eafb8cdf727fac0ede2d786b56db2c945 -b20ad96af621943255a7b4da7066a3b276278a2a61225abf3be42f7b59fdb514d5383a7461c67596dd6df53540413a82 -afa34e15d5b485b1174e10ca95d69e4953cc5ec56934775be40fd8a75701a3b5d1c2ed53f8e428dd6a488a4907abaf77 -b83985e5ba6f76f4fd3bbda0b7e83f1a30364540163e7ddc021b633eb6d58422621f4d5ba5d86ad1d635780fc9570c48 -a0ab5bfcdbca4a3c8e15a2519fcdeb0f1871bedc80eb745a268d3a6095e9ef5e58ee5a5a304d44a121e7081bde3ca8a0 -8b71bd0dea1a2f12e7b3b51f68e7912079ca3708d0c2a8e882807bfdfe1b75830ec80c581a94593389d2c42c2a3f472e -8e15b91410750039668928732fb3a89505e86da53c95a5ec8813df06a581ba8e18e59ea4054179872f2cdf50f5d2b0f2 -883d78243c7786e88562fcfc9ee46dc471892996314f5effe85d9a584796ded166ef1110f2b60494ec90582da73fe3a4 -99904cebec134301892de562fdfe20e4b05776d78d2595ec229b47d5e07ade53a9051d389368e17b1c2592934cfdfd0e -964280d7097c3e8556abf5e6d2998a3bd73103a38b281e9203d23b12fb9b64508da5cb190827d935bd380082e722aa5d -8467dcfcbbed38bbb10a53b359a051deea6b4a06c9235085e6eac7a874237438183d181ed7f505af6225f76807e9996b -ae6abe0a4d86c17e7a7098674e768c4d38a7aaef6020721ea924ecf6eb0309aa1acbb669a4ec6d2793ccdcf46dd67fbe -976c523f68a94aecde41616ac316b333eb08d1dfbb3eaf3ae581b89cdefe0dddc7298cf881ad5dcd2aec1ac610b9de68 -8c5d91d6aead146e1c9610403b539125b9727c2a815c6357852e7f001887ece31a4b1bdc37f528cd2730520b6d52d3be -b47aab085b3be23b0a788cb639526c7b981d5edfc7afe6cd6df35065db0fca85923062bff2246ac4370d7f6581c0bc65 -a1a19f3d776b19d344ed69ed87fe40ee6745a5ead2a95acf865abcc0a887a0237d6319aa0edfd3d73edc08c15b86158e -b3ea4e3670b9e828cb55749defceaf8e77bf6d4c8a770a83d1a44811dbc681069a08713f456077b69e0ce52f31063386 -a94fe891d3321e7c0b348485948d02f14bc56073c81c9e4c4fa6dd536bcdf52f365c9510d7c6e41a32ecf3abb7caa92a -b197433b0649bd72f84eaa707cf1522243ead748f6c6d4909a3802c559fcba1414fe06382b61fa6dbf46ce1715a5f0d3 -a078ed708533b5be95862b654119876c190d203bc1a2e5b81ec039e62b572054547249e846000b8b2140943c4600b1cc -83bd134d6550229c626b5a900012d6311c7ecb7fccd60fe4f96d8ec4e14babfee80bb8cc329c199a8a87e015dfe02eed -8b457b0ad5b88d8524d3229d4be896f1cd8d8278de3686861ef0af91f27c8ea55f106dade616b364d1270cc24cec3ab8 -b9fb1653e0b80386024001a37504bdb7c474281ef8c1f047c293e15eb64b5f1d2f74a80a8e442c1156426d56b5f0bbca -8439065b415b06f792e126cef2221a29b6fe4d55af4aac745316de796adee1ccd4964c2570121086fc465c2dff2b3d21 -adce3b68c0649efc7b895aac0c22f5770aad2883628e71ec53b36dd0be4f3ed0edc8a60e1251785966cbd3987e65b03e -a46d19c2304f523586443a90070a3bba6a44fdf22d9a3f63320ac225caeac2ae389565d141c9a61610f6a28c68f24c55 -b245491cb5330184de7d0596d0800ae94bb2c27d4781c7e7f041d2609ac61ebd985f9453bf8c752893ac71efe5265ecb -a91106977c6aaa8774b9fb85315312e1e5fa47487052377cb4fc1c73e9fbde1745cd494a07ac587d7a26f55eca93393d -8b3454d96a6abbb9b650e010f42a3f276eeacf3108fd1d1f351968d667eeff0ead39d601ff501bcc4f9e02442cd7f885 -880d82ee5a00ce6f8e619ec1d2b7ddeb514debb85178d0326868f6b4858e312566ad106366f40fc7b0c9c89d93999295 -81df4a0c54e21e0ccb260daf05714bb155352986db76303d177f7f79a9064775ce8a6375ebe06032bcd978234b95cbf2 -afd0f51332ff145055a71f29ccb77aaee615b02258d2c73e3082a24f39caf6472d17f188650040e756b821be105158d8 -92bc592d88a9eded2f147eb9c05cf8a2156dcab1939a978fa7cd078f352816005ffcf0543bfd7827e4be66009337a2ea -b43b46e9c46ca90d9dd988cbf2a4a419c2b9fdd513da4b0a1b3edc95f83e4b1fbfaae29c54639a45b5586e99317fcd50 -b67ad98710f7f970214995afe267264767fd84c6b57459f64cbd6a01403f694b985d2ac5c8715a820b780275dc03d0a5 -92b1d870d1f0b5620784b40f1b04afbac4a492b8c39995b62d7469571cdcf12cdbdc018257864f62e226b76ce224ada3 -a35068ed28633e92d0cb277bbc6738c344d157362ce6861b37092ca170a89780009207addbdf97a6ee51424a47644fa5 -b1b2ca8769c4095d097634f7736ba7fbd0156f00840fad457ee1ed84271d13842bf75c9443eb86aa4b120751e22d5ac7 -8cf4342744ad0b7fbb380b3d6218495ee3c66f3a255660bad7975405ace5ad4663e321931c21f0c8a777d3f08295de1a -818dfcc79d7bbbe347e4fbfd567b4cbb7a9d7578faadd953e350c4851a05c8b3c6bb580edf13a37b9e56d32fe93a77a3 -8fc3d4f19c622dcb2d45a89a61e5b3b704bf13ee9c3cb9c5294971da13d4a9d897aa4ece68c2f9a71fecb2313cf6bfa8 -919cd2af2398bc4c52ecad6a0f50e92a17ea942a89ea78a711c2adadf200f7f3d5931d915cfa04f21cd9de8824a6ce15 -b0c902be67868929790e36293c4878ec213e01c8468a5a399c2980969418fff2f8a4b40cb56264d2f0d7b8ff58a82f7d -91f6eda8ae29bd47416a4d9041d2a96c9d3355ac88e6815ad2431c0b08dd379ddd2446b1259cfd0af500f3e50fe47675 -83bb510922f25def48734a22c7a6f1cee7582b328aa786447e10dec2967e119cf724d7ff936cbc5de7f4b2565783bd05 -8a6652aaf8c0a67a61b863bb84aeb00f0a89d905eb708e7797b68c07f7d7e431bbfe43286b1317e2d1d8cb14099462f1 -883ba22b1585e2baf7fc68289e57bb1e42021d5902b516d8a07622cb017a22b5df7238d9e0efa13f8b88e77018f268f5 -b74dd2861a513356c7aa2eaa12a39921767317f59f81daff17b3f35bb6a78c886857b31427f53ddbe27d5f3b13003795 -82b186fe0f341fbc551af3190cfce4be511153e120567be4d82e445b2311cf421616291675feb324f39dba4aa8b025f0 -92a63c8ea0156c88ccbc3a80f5c301109e20d4be941d98e45267022c47ea6257e114b660a2b9e6c698f46314f260e238 -b56a9284852547150dceccda1e5e4370c78b6f79fb47a348e3947e07043287e81860b274e4e99d25371a4afd965a0da1 -ad4c180eb60adacfd75629d645bbc1ba9cbf1617da36c64cfbf5066a964e9fa2dfc4e4a9a0e206296f560ef01a0819b0 -8aa05524780e6031a35e794bce4d66ce1f388364a064e999fb037a5cae86ffed82e0b743aa9fceca533e3aa191eeee21 -8343c52a931b1c1914d80fb5d9f995e68e00bd9ce3bf64e8d557541ceab02c482fb0ccdaa8e44f290dd15350a96ad6a3 -8e526e58cfeed1a7057de8221439c3436ebf089a22b84948bac3cf2be8717af6a7d164be42666957d820be9ff023c15a -8cd0a127dc55c4159bf5f57098756e01929393430745750767a024e084152cd9f366f1998f85ee290f0836c562ad28d4 -ad466a6ddf8778ea4853bd666bd321f40e727f49c85635e5f613747e3d8633f892a09558d830622f0a59cc68a6db62d2 -aa2200e6cc2eef1776da3920b98b5114380d1a59a5c822048ac4c85dccdcfca45643874ae3b5c0b582552dde2d938c83 -a38dbff9cff9611c6a8d10af8ce417048decbfa95b8bf95bc48c6e2adc4c3b73411f37a6bc87ffd4c75713431355de87 -ac35e566cc3a399f5f6659882bc6008dc023377df2743bdc3d7eed5b135ee590fd6ead0f53f67534a028a7e34a968eea -b266d00ed68f28ec4c1942dc93b355b78068af916d56ce7a10dc36112bb104c72f15564d139b53019952e4825b0adcf7 -b2f309b11b0e6fac3a7d13256f5e519087ec255d5a7dc3b3abc77dbac072adb293d0001f9b7de41291aeee627c12b146 -8cb234aea711919cc74523e1a7b2eb477190bf4f7ac4e2bb83c85c9c7410773f4c164cdc1c1c6dcf34df546ec4f67b3f -8165f4a17492ca163208f9fb93ce219fdc0935363bbe335f940de0159608a4115a2f7b264bebecbe5b227075a04d833c -96ccefa2c07d5006cba587f308a4d517d4303e9f68f9eb30a1edcf2cb3327023fcb3f7c23d11850fa7f404b70ba025b0 -aa10435bc7a8d6c13efc2931f8348351680ff4bf7552c98698739c28c1577fc13ef9d22e9a2b5dabb69dbee4113d98ed -b5000a583f4370e9f5de8d9307fdf1ad76f2b9d64706c65abab88afa2d5bc9f2ec5d4c5a5335c1d152ecfc347d82f5ca -a96af6ebf7500f826999777a3b82780283121b7fc2a50acf37924d6b1ca8d481233b475410a67f5c0493bf44d9267afe -8d9965f6ab952d978d3a798179d3590ae4ab213155964461d7469e0cce69d407967287ad2b990ad1127fcc401d7b7a63 -a727e2a86fdc7146442815fa81f860f3575e146417f2a1bf038d76cf1007f44efef97cb9ec39ec7da6bfe68d47a36fae -82d39e220a49ea0354aa2fdf269cd05a7de7b061e8c125996d14adb6bf51e307579890279d09f17f6101779ea0391429 -a1eab09c819ff5e07d5d2587244aa6eb2c7f8dde0cf40568bda3e100820405f626a1f165f655a81e8f39be49672c10a2 -9569f9a156d52c16cc8b83ba461deccab4280172a47625da4f8f300f1825ed8c59aa5d8e0b3b4e89708bc49af7a0d035 -a5236d9cb1fd8baac728e50b773857b25b8755a32f787da3d613d714f43d6ef76ab81f319d96d56e511a67827babe688 -a5762059420bdb2000a616e3ba44af116d759902555ff310fecba6490242e0f163bb35f47dae98677e9958077db73842 -b0c30003617d7e924503dd32ca876e90ebcdf726dbebc83944b798dc9f5c90d14953daffb3abc9422546971818fa699e -92db657e439c2efa905c9da0402d5af82a6d0aa65aed9e6b14f562cca24e93eddabde1e7f8dbad848c20dffb7005446e -92a600652083717eb58b208e82337e4d61e4e60c5ed2d21162930813a8dcb5b8bd919941eca0f8fd2c47c00c5b978b1d -b3826c1fde0583f919fb843d5cdf762d533687ce9b7fa5e7921b90b77a68fc9e04f3dbf3e4d2715bff1a2b17578900c7 -87386819db62e1b6d01410d8017bea98a1bd86a2f39b121bfe283ca2707b70cc4534fb114bf5902e3389e6d29fc831b2 -83e619d305c16d7d323ad2ab81dcb9e380e7e7a666f9e71a8310a9e8cf4d1b8ba003217f63aec6d83993f5d20d79aa47 -981b9d7bc517b3f72b7062bf75fdaf21f8ccf43fcc99d4dd5e33f984083ad06cf24425dfc70fdc449965abb3ce3de077 -8dffded967eaec03637e8328d8a67b1b2eb56f73bd370abffbadfcaf2747fcba0b24d61524d637ad4fb43c2b9b92036e -af0fa75f2b7d5a4ff9c4f32b8b9b8135899050d65fd5c69c13e6e78766164f01b6b0561954e3a9cf43b518005757e52c -84ca5c316157bb87ef1c5afa2a02cf3926da6a556fbb9a1ef7eb833770e8d94f7fc4ebc444b0b8eba9f5853da2c9b601 -805b0e7f6d64e384ff4d98e5495edc0fec4563cf9d117637dcad83a922b5eaabeb4f7b6ad441f9faaf96da8b2c0459c9 -a70c17690aacd71a82903f4b43a0866c37904e07313ef53c1d852e2362e223640f58d6d1fd6a752055c96530017a0313 -b387c51615101c21374cb6b85f109b88a7680ca0eec078d2ce2d8d3bf7b132df3e69e6f8164ea46905d4da6eeda24bf4 -b3ef1d01aba050ce9d365349aa250ce5713e0d928e64af737a70b0249bd81e38c8f34ef42c82ff4f79b535492c444251 -96579ef6391485b67ba39f57b4505fc3381f27fcafaa06d49b70bbea0a104e58c3b418c8390545ce176c463d796cde2c -8fa8961e5ab9f9ef0bf7b51de8815892f3068d8240e7b2c89b0f6e791c8820a80f450302001131a22c194dec326f07eb -b71ea51408c504f2731553a4f6e043712a97c2d754d3ffdac46f9a953bbe36c77d6d418c8304e8f6d961bdedbd1e2656 -918830ace4bef09da87807a1f4d0614379b49bb39ba888ede12c2c2dad47d8d5c376b1767c7ab60108c2d9fac8b537f6 -88b7850fcebcff11fccdbb739a470745da8e1251efe83c19785ced5f1b7eab422f4c8b949f1351f5dc4d58f7052edaf7 -8a63966c63a8907e101d00ca7fe5ed93989e7c4c1cd56e87d130ed62cd978cb2502311c9f9eae6f75e45779f63394206 -87ea261d93066a309a98a0335757057f7e7ff6eb45307982a3fa77f6a49a0125ca31fffbafb58e1767a5a7ed29afb028 -b3988758fc9a3ce524c408e74c2913e1250abeed4080b1dee3d43fca52043958f95ea96b95a285e3afc85a416b6d6c68 -8904ba0c408f2b2e2b8668056e2b9d6036fb472b5e2bfa23360a83164a5d8ae84bd9bea680f11c8c1b1a0f81366bf0d0 -9509780bebed875a6d6446de7200dffb6e31fa8a782585ffdd97f483d05ca055d4decc447b02d19d39e8e46719ac7f31 -8144639f8652aa4cd4c4f96debc1bff902767698d3529e8e606ab512db8b7a38d280f10e1d40e961f4bbc776cb04d706 -87200003b51cee3ce9b372e0596b8334bbd528f3eec8d0f7a7de3a113393c0893a7056b562194b794a57e650e04305bd -9368b04a6ac6a007307ac321346eaf445cfa65e9334695d299925d55287181a5f643675fcb4c329a4b0a52d2aa47edeb -8f9ad49465ecff41a9cadec62f150e70b65b75200223e3d12dbb27161104a09a58fc145defc4f57eac3f47ac9adf7dc3 -8295ed7e0a04a72f1382b2f7c7609bc763eca1c368c2270d072953ce3efb801af77eb3736fb5c526dc9aa46c3a6f302c -aa2443b1ae5b124e978eb865595a5fdfe7090119f418ae9c552f4fe84014966c2d4d3728acba0b950ef8bf69d9d4d3c8 -8a56d85d1041b9ac7023ec757ae6bdf7182db0a9013add26cbe9259db8f0ea831ee00d633d56ad5c0f5ddd7b44db4b6b -af1369cf9baf662fbcafaff6fd2dce2f0e25bf7032334972151f229386bb32741671b15e7288c57e46d597d6d4951962 -a599a85f665a0aca18b0c9ff7dbe974a41e0f59990a4da3f3f74a309e4d329c50ecabb108e2e7179ada76649d5d676e9 -8198bdc97492cd9ca1a730942fbce18ca26353f46eee756cb40b298bde0c645e469b90029b575c821b7ac01cd44ef7c9 -93f7ebe4bdf207abfb68a27f5218245eb03cdf932d04643c3ffd5cd5272ac37b8a1cab231f36eee006b1da8ae130f4e0 -99c5ed92cac6811b7cc15907802fa4c32cbdb42ef8becfdd29c4c3bfa44f230f561e6d014476d0eb8d21c475911003c8 -b94d580b5249ecedf59b9a03cca2f2c21ad0e17a51aab836bd9e9736ed132c5b23ba852c4e6d89071cf29c337f2d2582 -9052df4de5c289925823a8556c2cea87b44513f92bec8522017cc7526d009349192de50e7cd0c4ec18cfe9eeefee488c -88a1c90116f86184e4e989eb24af6af34631aaab1e28d2974401d560d925329a8fe49062b6701b28b448776247d86365 -8ab6bb41977b58ae41ff642fc341f72574e0a8907af395627fe41cb728e37aee77dbeaee7bbd0659c0c5370fa953a64f -b8b422e1e70ec4dd8fb1d79ec1381b4f9134710af3b2fc1fbb3c60913b0468d7caa98230ddd3e7bd61900ec4523e28b9 -952dcf9db231ea2abd5e4056bdeb906151f948a8f2cb977df1ffd3f62268279ac9212bd5c5b94ea7fbfe163572204090 -984cd3f20f84e0f9a58e406f983b46aefdc8b1bfa1854705c2fbd84593843c6e8c9945510660d204d93685293d0bb2ea -b249f5566f3ecc2982548e406acc0e773717d9e6032103c31df3d800a47bf64afddb5f8786d0137e76e5851ac665468f -8fe558cc8845e89f8d2f9d8e27151a78ea8ad452206db55dc94b29ff07dc9c4a60fc786c483c6d708712db9bff70e257 -af53896b4273a489323adc7e9c5b2f94f2aef6e2c8662c29071a5b1a5ae47e9a335820fb2664990d569fb59dbe98266a -a766f2fb21609313dfebb79f54874210210e27efa32d128ee5753ba22805c770cd27cca8e182d9bc64faff61ef4f0b3a -a5384375dda01f18bb57c73650127dd0c1a0c82f91cea436a9c670ea0ecbd6b47a6d10c0fe41dc12ddb0aed33ef95ff4 -95db3403ced35412a8e572d3b99ee09642cff5be67adc35ee881e8850ac4180b215e3404e7ad6fb18612c0e071dd7eec -aa84fe00ba4c2d0421a998c24f63c050c37aa0540445041254d93800f3ab50c337a1b4cd41286f1da2eca1b7816feea5 -982d1fffe81b87f73314cc273982a70abc4fab3baddf7bb0197bfd10172f6cc6d54bc9987314e1dd6b061c911311090a -ac7bfbc96d9588cab489c60c19a57db26d7bc7767f552842edca4ee40a7da544254ba309018617c73f57955f96eb2299 -917fc2d92973b0e73df5bdb9e1cacfc9bdb8daf608f63902f75ff880e256d75ff1edbf825eb3d1fca8704320ab9da75d -a98bed8cb3864dd54aa62f65918a17dab8e5ab0026891e7c2ec9cb6fd68bb17ef8745212e61d30b77a9786042a427c4e -8d574b4475ed6296fc82d05648c9f2bdb5ef925e423be513d5803f1d1ec6023274cd81a4221379bfe7d2eae79b7fe858 -a97a36e618bbe6bc1b2d320e78eac988d60c7315e780b449219a41c489029e8f76a9879dc2d3a28f80c521d70a159102 -921d1a332809f23c61d65041644b12589ba73a9ad5d4a8a73fb70d821608f1994cf6ce2c8f11075986711e6cad573ce1 -a3c20a0692e76787db3ef150b5fd98eb7c88cb161ecbb47323063d57f676821245a060a935f51f0fba15a59f1ef82c02 -8204b8a2d4abb6a6f60f2e1b86a91252b23b451202bd816b67b1a9b2546aa2149457ee101f2832d7c043d390763e6041 -920c56ebeddf8ea9dc437f580b1225547b5e3655d742f2868b08b82e70c095af9e070fd377e9cefbad4691e0a2a0b500 -ad36d7f526e2f59170cd4c4ee3ea2d4924ae5e1006d6891e52c09aa5941829ea4f59f93e47ddc4bd68c754d638b0ac88 -a8fb38042f73237564772eba8f89d91d924273c2e523660e7b5537bcafcb8075b403b06d656525460166bd69bc3eac5a -86a2b6d2b204917c424d7e4087657e6d7c66f198458ce992765575495e76097095aa73d3363a1a97d39f2c1856e96ab7 -84feb5070b803e14d96497b698059e564d458e6e1b8887ff5516e66f6fc92d50b52334b0a320c5126599cfa4d603043b -b2d57b0301ac57bf4917880f28faafadbc48f4aec7b82968f71286b355e386a05edcb0d5b02f99019d84e69d8bc910df -afaed8ef4324ccb2e348c84d8297f74ffdfd63990e02129d2a60accac883087febab71fc3697c4dd341723858ab8a8fe -af0126a72d2dc043a4b911452ef880adb86014f06384fa39b6a80340bc306dcd2671094bc4bb2372dce47e0a99ded473 -a669556ae9496e374feb1b6f496390d351514f858e47d1cfccd7ebf7c5c188953923c926d4bbd49dbaa646bc3d267ae1 -8fef55cbe88d8cbefcbb1bc71b9bbcd982c921c95876be0cf4e0cf8537ffaea562bf77daeac96c40a159ab69ac78a58d -8c052737bd9fd14625b32b5fe8661e2dc02b7db6d79a4d5cbe335977e3c32274af3445b46d1c65ca3783cfcc762fc375 -934d85dd78ca99b4ec77c0c5fba884aa12ff30fcbd0717692e705983a769f8d53637f497fcf413eccb438ddfd259bb79 -a29aaf139e57ef0323aefaf3ac836deb9a0aa8e464ad36d5c18ff282a42008843a90725995e95175e3042880a3df3b0a -8d1e5bba5c29a7e5d4103ddc3816ebe31f7a7f3735ec273dd437892bf452d818c4fdd89cd713600a25da6e63df154408 -ab42e2f489a595edbe62214929c78e4b61357e214d02ecaba9c5d650d2fee2cf6afe47d4fe6289ffb4d2e136fa4deb6f -958fd7aec907f3c11fe5b1e6df7dbff555e2d270f04c0bfc834da6042dab3880a336fcf7fd81cbc6c3476887c1298ffe -955c9009376d0b04eeaac2fc0b73d766ad36acf60ff06b738b7982d0c692f7775b33c1c36db6eb39fc72f0840df5d4ab -a20de145c323ed6143a40cb76ef1df39d460b5347f4e102620fa8f990c97bfd1b86474e390b1416d685e11cbd900bf6e -b5e8fe2034a7f70b884d99c57ded7eaaeb3241bb5a4b261ded0e320f5938fc568ec4d19f3d57f67a713265a8e0d375b6 -a780cbaa9a0e3ce85e9710fbcfcd3139586ac9c01e882234b6fad98954ec19f65a96b5849b742a8fb7bb061585ce378b -935831fc78c44018eb4982df4ca3eb902c5122f090db3ff1135422ebb0fa1d576ec6b74c867f2d9c40a6617cbadbb780 -b99271ea8cf8fdfca12034e909f1644ceae383f10b5c5af348cdb3f0839f5f5446f61bd31327e7a67d3d89544959e4f8 -a2bfae7db7fc3d8227104cec70c1c64a08bcbc3f8193f920393676c987a2e718471dea1013a11eb8c04ee866577f520f -805d10e056a8d7a6ac431741faffb18398c6f7eb59350dc80a6248afb435858d4f5365c82161fb93370acfef3d4f2692 -8e8efd8db5b869e30c35a2dd1e5cb9adcee10f595bd20039ee7ba9a6585908245a02302b49ad558892222b7d95fca9e9 -8c1719cf37ef916ad51035977c3614457dec6a449ed1b3dc99fa86a2a7beb6af54af806817fdd0c31a9a01ede4fc918f -a8c4f4fe4fe76160aab7c0c5bc158a5909018561529bea4cbbbd0d76b2d9b9a5686cf33808a06b49a112f4ab0946bc7a -8e6a529ee5cf317cc8dcc87d1207a3bc0ac3d65bcab385ada17d563cfa7ddb5fc4944534f2302367d420e2a957e5b238 -8a6649ea4ee194381c5186e714994c4f4c23533c135dd3074f9ddd7475122993b0f26e240f17a1db1980d5b2d01ad8e1 -af60c1343c84ddd86ebc201ba9b60145bfedd9ac6d714313e79e4927485ab7c0aaaa92de1e9e5bc3670c56ad14e2319d -ab64357387f4fa634b66912c87e7db0e855b8a5d4bf3b14a9c1561a9fee4b9fb9a7b8e78577ad6a9a987453510d598d3 -8eaff9c063ff7cb0da79f06d483c99d896bd0b8fe70b19ae4d300fc9f310a2565bfcbd6355aef87c47db4f11dcce2847 -ab20c9febd36b7ca0650d4f5ad026277b082e63275de2799525f9d50e168dbfcfd2ad42d29b032e09c068276dc8515d3 -b63769f7cf181ae3eb833b958b93bbd1b79fc9300939f347c666723876b7f0abd279a07e66b888af632e8d07f440107f -a3f129b5ed839a8a8e17612b0e2d2dc9a58d3847fdb0aa36e1589e830502744ec041dff4e4346a02e9cd0d6e55cc59d3 -95be94138fa99a68ff8fba01d38a4047cefedab262dd8b6fa28705511386ae58ca2b09394dae9db1034f9fd31f2a432b -83f55a55c09d102d88f232ae5571188ef083c02039f2ddaa21d94b88e2bab04ac8fe6385caaec6bcd733fffb6c1f3164 -aad5d87989ac51d910d5058dfe46493314f308e3b1b7a5bac181cfadb7c217b12ba2ae14c53425107aba089d0929b296 -923f69083b00daba5c59342600975672be13e562ea74c5eda87f06c12ad62a0272ef1c7f4ac19d0f1fe4f8623d94ec12 -b45fabadb7b5b93fcb8e9c8761134dd8bb720847caf8ffc5008d2ae0939678fb99cfaf28b8fce3b109d46c09e7214e37 -92d406b997492a2281f9c85f86f5a4c9ca37c9afbba91d27b8a0dff9e84420b0292533cdc5420b4f07332edcf312c4cf -8913462447189c164df3d1d48d7d350e947b2056a029702c29d7e7450d4255932b27ec429f54a4bf0a1770024725fc7d -b263c4e00a3f6cdc27df5f3ef8cafddd07b60341361a96ed9a3991693d9ed9f6b22217ad72f0dfc4eafd31c8cac230d0 -a17aa8cc8fecb4e45f015548ee17fa663ab2b498adf4850f5c4bff1781fcae354fa5407a76e418162c48794a591083a6 -8b8746ea3c88bf033ee6fdd618e23f671569156d8515d135c5493efdc3d2c9abad7aac3cbf181101bb11aef7b325901c -ae858cbcf1ac49503a3cccdddf57f00f90bb791b5e498ac619554b106ac53e44ceb9a4f8cdb74234b7617a40223bed55 -a89c76244bd9d3e46dcc2b91478cbf1d8f33ae104552fd8369ef073fd907728e79a505852091959f924941258ded15c8 -b67ef5be4e3576ccab40cfabe5ad28a6e258f3d9fab2f9affa31937c14df05d3d02a283d2fa151b9899fdeb64b326c17 -8a8e9ab29bcedabb3460f16e0ed295a92dabfd5dd5f7720ed5f0bda7bdcee9a9c4c5a06a66f81bc56962d41298158377 -b6ecb80bd1a5565bae594e51c223e18ca6ca8a519c2ebc7042c39d490fdc11ea251e07fb02da7d0506e9df84b34c78ba -b27473ecb416eda4fc9f93f0b7712a98a1264949cbb2ddb09b94fdaa7bfb56a5ef0cb0574e72e06696bc3d2978d8f535 -abbd03bc64328592ca7c6e8d6f805a3725502a433bed08f5b47fb91f1973d0b16090450222036961c9e365763ec1f939 -a4eb17a82c7195ac79c4826118d04ba7bb37c5fd0e0f3f9ebc23eade15dac61ce989ff25bd12aeefca58ca617681e68c -9134763d02167001dd1956ff2ef21a711b370491cf016cc6c25c3ca37ff507468bf355bd69aae847f17ffb3693466855 -8596c2c515cd9c138f2188a7838d9602e42878d464de2426d856affc474a22fbacc56633b9b8e82ec3ce93c9f1fe605b -83e65e4d4a42ce9fe739d248e74d0b89e73826a6234351a13142426e459526aea645ea4ac3e46c24c1eb5f5a6d8986c1 -897e1c24cbd3797ffc593b5488bde97e8dcb9e8dd6f665fd0cc8b22c2729755866ff9cd700d194e2a6a6e3aa428af299 -8bc9fb3392aab49bced7485fec5109fdcebd58feeb8d460cb63690fb5bff9f2641ca7ef373fb9f0a0f6f5a30d28defea -af9c73b869aecd8c7e1df934358cfd9f5c70601b6aa7bc4d828a15beb1c9d8cabd232999c196afd746500c566f53c4c4 -986ec1f953c3b13a03c63096fbf9e0c8ebd405bcb9176c69c9aa27c183e4147c798a2f00624fb00d7d1e267c8d595c04 -b09cd330ac3efd624598262507f9f19b790dbe615a6fa8e9a7383b899d2d87289019c0f7297fd20dcdac455d475d3dc7 -a934c732ba4e5597cc5f81792e209526c53d29083cbdfc1684d06a014a65711a6c7f37e2d64ff6891387f9e4c1e13214 -b06350f5d544b83b903fa614ecc1ee7db32c70c1702b89bf0c8c403f191e867ae0908e0402a48a28577d3a338582795c -b9243ca5194102b7c74aff9550574a37ce6ec95e154acbeb006173eb39197daa986a84a94aecaaedb453885891c3025f -b8732bb9cdf0849ff258b9ac610f294db2d75f3f383751d873f0eb3386a51e083994dc24efc1e176f6c0ed7637f994d1 -8e8302e19f7a44c3d136a13472f84c738baefe58f84f9d96bc389034988407b6a0a0688441672ef6bad09ac16cd2c33e -88d5cd05025d9e2d4e1f9f5e1b9e415daf69df033fb69f88737d1ff5097eb45c61a000fd7de4afeeeb6c4ae57277df77 -b5cb2c6a8f85976eac2f9b12d4b4634de56a38df5d772475b13d74bc18b0ab71ede5ac06483601ed6398c7e90dd9526f -a5dd5abd05fe92d65f9ea2780be6d3fcb14cf3d8ea8728b367a50741cf61c6952f6e1ad8cf5c2aa66fcf25a6f72cdfdc -8e540b6717e55c01eea1f70af2de7752b395c05b671986a63c1cebb52662a83720e63d8ec7e2879076ac759f225f7690 -b5699d669639600760f5adae013c1fd731b642fc95cf7b60ffbed9562b191547b445df29bd7095f8871334a14d39f116 -b812314b92e3d1902abc43a69b5f6aface3a3cd065637591c16e4721f3bdef2ce3f149251f06cb38b85dffd4044c0353 -99507fb69c705b92441ece2c5b661163522a10be231185e04247f24e134bfb189a3ed06ee655f064f3fc8c71dd99cd14 -b3fca1730c8ae1ae575d8ec75dbbcacbfd1460b6dfb15ad42b87044670d259be103b5386ff1bd828e4ab1b93480d1f90 -a9bb4e1c86098269a2110405f90eec8c1d084e13975f49aeb7e6751b0d118731207f7db74737396278b71c2947d20386 -9137aaf24aaf2804beb7b957e3a0135157831c99e2ed6a663052306122f7e412b6a2e1f2d20ecbaa35004b833885621a -a15586cb10f7db03f62d490ca33a417bba67e8b1f6031d4f6f7682db845b6200100aef072f247d399755f6d2f3eeb343 -82ccce2b29766b33f4ffbfe7c9705730f353091de994e36fbecdf1554bdf2fd2f656f30a1cf18305f63ea68f0c599fe5 -b0657dd5e228d6119a3d3ad9f5bf10c795957d064558ada78786f1789dada0cc1d3d1669e2269506ac7b290e13056ac0 -adc025943a687ad0dedcdb6bc696fe1f31e2b2e6ae1165c4a7b769b4042268cf2cd6c82c3a2546df4040e00872213f33 -b03b901d47294f7c35a0f3edfea4abad2419a01a3c024fa6f327c89bf7c10b67a3924b9eff74908d9d90883dd429be9c -895b433223f053da8275563ebe7cd6f299272d2f74e4af5fdb4b3fe76ee2939978fd5421ceb49c17acfe33af01e048db -b71e3b52d17e166023387c7efc6ba385e1d96950da6817f5c2f84288ffde1d3269d727db49fc80b4bc877621a444b1e9 -a89f01343f22ed143a4323127a0d10ae6e34ae1b6119c77268a018d4f1ab99da69aeb71b9978733686f0ec14115b3b80 -b76e79f595d0071b92d783298188dbe95210cc2f0e278d03773bb8a8618598bb9260080435d9cc6898f7d4484531cb78 -a7b1f26e04aba6eefc00d6f1b98bcc36d4b6aa712298aade84859d89fcf1fa90ce250cd573b500251a99bb039db041d9 -80d960d224d1b9cd377bcb5b0cb5f5b5e728c79323a2043cbcaca4c00c3ee4cdea4b910a39b75c976f6f71ddf48602cc -85e6bce985d85da33135c0174fa60024a2a33188c2a9d143c3838cd2c4d1aad5ea7a6e07443ff78c33e2a530d3e64f59 -b5ebd5c29b65239275af29ec51159a37f1e5b1efe6815905b822318b11c9bce2ee99429f2df8f5c36612cac58dc81c86 -86c1cae998c7c2c8a8aaad02702a2fede242c6dfad003e778031c432e54905c12d865f3ab4ccce31d46f2442ab97e8a9 -b95640d418d1230af5d3ca60b5cf2bd2de84a8586730deb329b9cddeeec8c9a9728fd238fcbfc156f473aedc8d139500 -83c794cd2b0cadd4b0058daffa0dd2b14286a8fd5b83f290ef4b22c2c830e848fe167414e169105cb4320c6ae6efd3d0 -ad03b494f56db17bdc79caf82160c94ee9eaf1686cb08325116ea267f6e4b1db3e6c3481226c6dc1d58f3b17a435cfdb -93538fb55d0ff17f4e3f06d9a44de86f0907537d8e2391790fe6403b25dabe475977a2fed14f8473fe1e7ecdac1da64b -a1c22cf0e4b365a298d8e5f4621bbec7e2a5ce7346681c7a8cd14f4e828f72be229334aa20c6a3f52d91065f34d14dbd -8711803102df64483b231b0deb3c92d69905f1fee288e9ca449bbf3f12b08c544c464b44d82d72a3a9daa04b7a8ca6dd -95843b78c5bea2de702922933ffbe117ddb96c4bfb3d9f90299a3c8a6b5aabd62985b0107f568abbd5b930bad36d34ce -b55774deef197b6ee82d822d7f3ffc8eaf4827d48a4d2ddc5de9acbf008dafdb31cf2d8e078b1248d5c8ef89308021b1 -af245d8555ae94e7e73371889234f52b0121b27fec354b0ad3745c84979c402d475efe8362629265109712a1e5c46c45 -b2911311fad929b4ee5edee39bdde8bc75c5d8a93ca7c364bd8b16c249c9692aad6ce0094982c5dd8e1a75b8cf065140 -921b0e0a07360e9818c5f7f2a5dbd8126f668642c76bb2bd4422ee598e5aee3783e793aa35e5394727fd8c7bc64c01c0 -8bdbcca62f1d8838df205ce1acb47562e0663d3dfa9cc8d6c627b548ac8c14aca2dae7a940dfcf86665c9c5618e0a214 -99199000ed7ed4bd5c3f1c5735549fdb15c235a72934aff81f07ad766b046e4fe839196e9aeb8dd2c3dc478e1551d918 -88359df71b006c18bb321911741a65dc057732d1ea2a5d0c916c341c923b5ee9a7634fcb0135b5f2ec09c231b8e674d7 -a16ec880727920cc910908f8956bb3506d2952e4baca9358ccc1591dc9b787596b95f5d4d9bd5bf6bd25eba8644ba127 -922e1ae936f4aa654ee3ce11440b953b0955dfa308973e6c0c77b580920bfa09b32c1fc6d06a633cb106d3c84bada228 -adbbff33f6d91c8584aa6710c24ac53dc3c1d860938332504ef211dd47c8eb38a4c55c785831932dc81e9d6422715930 -aa9bdab448347eec58c4403fc99abe30e07df67348fc676fe513ab380a80f61f1fcc93c2e6415966f574323d14d11ea8 -8817991c03a91112ea6712a050615d9a13796c930cbfbcbbdb56dc7cc35cb67a507f5a52eeb2262be3755be89bb6e56d -a5df4be4aa15a9cd263d07b9c02a5293063a20c4f8f694c201cfdd528c83548b788dc01c90128dbd37821da8e2563b01 -83eeb934f51fe508d4155e6722b7070c4a1f9b68420023d961029dc5d5b120e77ab77837276f19115dad87a118feada2 -8e3ca52f2f5123e55d486cec5376f06bb3f6cc2a35238fd3f4a069c01ad1bb4dd85f5597b6f0f22a29f7c3fb4d178104 -91e820db15a4a112642780f86210aa7269fbd856087c013a6ec5eeb3389caa9182bf7783e1f35e357d7cad12ab982035 -8e8c3cfb5cd8149c702b3c9370688b72783c4922392ea025ce4ca76b34cc269f67de6fb2936edd55ea1533ba6c6ed8ea -94b8709d7101af225ed26049e4fdfd5b6b01ee03defc3e175506cf1c95e2c76b05eacbd19f3bc21cc602b9f3d4f5275b -a750655fb03723564ac969c24804253510065e4082b0686310d86b023e5f97f4717bf5d673b7908d78093f0791f91fe4 -b76e7955ef3ed7a7c3b81d7701bf4061a648cabf20c3b3aa53b4d5a63810b5fec4dc63f7ffdeca697712bf96469a78a0 -913093a722bc94e4327d0058191c591f81c0339fb2f53d2244e3bbf2f43ce3b4e4f03dd12077492446a90c532ef67a01 -a20b34e0c26b6f4b1c9a659616a8f1ea432b3a7584de048173a936f14c90a3ba8e16e07570875b3be7a7019af56c0287 -aa1950cc2bb99423dc2fd189880818eb5967ae555bae303aa6dcc4a77e7bc3d1e1084a6a5b00f0479a6fff9b18ad974e -8807237a1257f953f72d37c540ee26aaa25c77e1f241cbe77b2efed37deeb220b12267f538f27ffac612f9873185147c -a34eacee19eba80a88ff1ee65ddff9580053b4f2ad3c57d803449fae50e6871bb358bbef99915cefbdbda7c7aec8857f -9772dce7cc392c1289fa9c44c7cc86e00fa502fcd4e53436dc8ad289db6183ec97071a65ee3b2012955f3a8e4ec8755c -b1c179fc317dc59aa5ce0d70e998bc5edeba80877ea571e7627ca71bf957441a94bcfa10a18d03d865d7dd30ea66b5a3 -b850d81819fdad3760240a9a1c7081ceb8993ed85a31ca3e592b126c20d567c0ab54a3aafb97ba876bcbe0f86aa8c986 -a2812e48e11a2764507f8cd41d93587f7bf1d0b3ec0f92c7b8df7d203b48e17cbce0f2fae2e04239d8c2b6efcaee9e14 -b06fb5c88cd531031c61aaba9dd9557db91ace895f148f53bd5202ffbd0abfa6ec3ca89ec0cbaa7925e0a1876d2dd1c2 -9064829a280736a170eab0e097654ebd52aba383b457f1a34851ec75d5f11d328cca59f1ce62d95d7cfc27dee607a40b -a90d9df142c02db2628099d0c2a53965526e9160e6dc6830fe4c4d853cb87119e23734f4262d058feb77651097ec8e9b -91ddb64930a2622e496b7eed0028442fa17dcdd69bb0c1633fada47c3d5838bc60fde3e655c3333dcd2b371e3478deae -b1069e98023843ef534232d09bb61cb2c839b29bfb6a4043bcc79ed36a75cd646e7f35f4599117b67169af63ec0b4c07 -9206340ade81d80f83a9ba8e57417b7ff7eb6834ed2736bb4d466e8b92a7ef487922165b3a44ff9f895c65ecc48c01e0 -990738833a0d95a8b506362422a967c5189d987b1c3494814aa41c852fd818e3ff1f1b8dfb0c48b4c67b52830fc2f104 -952c3f4770a13bea8d07d1988aac2c56e14612b55cd4e8b9b4a511f4fa94d2baa455afb71b8a84768128d39e70d9e59c -880ea03ee556cb4fdd70c04ce130b72f5dae8eedfa9215091c14014cd8c4c5b13f788748e786b8859458d949248976da -91116bc6c2ec6c9c53d432171ae1a8f9a8e39712a3c4e2c7b0ccdcaf515753be512e6e0916c82b9dcd286ebc10429ec4 -a98ffab9313c9139c9f372848e311e8983fabe5a2bdfa06ce891a381932ca94b260c917d3dbcd80a651214ef24cba353 -ab96357390995637ffa22a767183e3d2c386f5f7ec01d9fb8eef7d56176f4c1e025789b483224d5b982942c680b009f9 -a0d098d3dd8e93771f272359f00cc2c4a312728c99899788be35a2d194c607f2ec1b6d02883a9c83d338eca5dca8589e -8befe9775c49b8a7f11946ae0e649ea26cd97e74ba747a2a4954accab52c3547fb877e71b25f26a9ff3767aa19dbf151 -864c4d2f7758ea7e98f82795d56a89cf4e24effc0977fc4cad63d89a5f8941eb95003153c6d978adf820efa8515efe3d -910aff75111ee754b24cccfb37e9dea001346b099373fd30bb1370af7d2b4689e29ee0929b5d8beedc19d5e94b977952 -aa758f745dd998b9070a14e5d689353323f3d258f71b44f8a78b9d6e5e79be393b9d173d75a73c47d7e6ce6ddd786528 -975c8777759c48e60f53a9b8b2f151a5d36183aba236994c9278e5d09357774ea7b2dabf202def60d50b42e07931baa0 -86149eadfbba6619521f5cd30689db2feea32ca0a969dec7b3498f2559c9e158efea2677117de62595d2a219b676b217 -a19eb4c238272754ff1a0469a8f4df11d47246e430755d469e80127b4dac5974ba4c4f03cf494712ee0f55213704951e -94ec7c279c656e3598acf763d4a56a15c3685e3a37eb415593a450a9d8d77f8f4579188f113d8391b9f0b7b270523d75 -933201b432733ad60953b02495b0d240c06ce6c4a34a89e4e9d9c97e001f66d9e2b507d546f0041a5d81572ebc3d257e -ad8c6c40075f31904d5c633b058bbafe4387aebbff22d37d8045c546cd423305051fd0817c196e38e3da0c76920afa03 -82f6463d68dab6e86c5a82a24f91b5dcf534bb90cea762af9d97a45d490e51897c383e61108238d844599c481b37b8dd -a3399d11e1dd7c0e723331d2de7058b85a2c97164de806d3cb51ea113115800b3f74e755da2c90cb9a16b0a42c851ca3 -83c09f540e6d18425af7587c198e7e44b0cd56c27544afa50c829262d1de5be2785f9c115b42ccf8275b8eaf96070a71 -8a0611e2aa7623c51e76448084657af6b76498cfe237694b477dff5ebd3a1f055132853a26fcf91f3ef9a20616100e31 -a0ef39bb2fd548694c3eda6af19aa70b4ea8db68ac9c9291abb6339a5a9893824e266c3d5aab6198b37e4e3f4136fd87 -a16169f3e71379933ad737a89926e329afa1f15df309a09b539211c45a3b21fc5b93b504a1cd4b86829739a045320d73 -8e1afa218a8e29f9673342b8c2a717ded674d3d98c768918216377b723c9f1e95019304960912fc507811a8419fc9ed6 -aeb9f7ac89d3ba31be6bf5d6c469913324f7a670aceaeb8a7ccb726efb278bf14ccda9e0d5d486727ebcc533cc627df1 -953cfbdc6da3fc61c510d0d22100253ab876b8ae955ec7cbd920b79be621c4a889a83616dc3ac102f05daebde1ca7092 -98f179b3020bc6d12eb1671d539775a79cedd35455c51cbf0f1e1fdd23809f0dbfbb1c4d320378512e3158f0e0e7b17c -a2927c5ff70648d765d7c22d2c0cd146561f5bee36cd7136232dc0228e09a659aae45077dbecae09c57f3a791cefe96e -8e1529599a03078e154736fb9a6d895508e0e54e3827147066f1348374b0ea0d81ccda5339957ffae77f0757fa8f6ee4 -b2b1fea6d2bb4130290bf027986d7bde69e69ea3a33b25a9a90331d9352e4a03353065a57699d64de856f6445ff05003 -891bc04a15932fd7dfeb73b2e3a4101dc0e4566d13aa8923d5214204baa27628da89a05812fa9dea666af4b613599bb0 -b9af7ebcc7c0103cfa857fbad0f90e2176f6a59b00eb66ddcf5cce69918ee6c01d4bd41abca6c5c77e581ebb86185298 -8b8bd576b0df1413d1f2782393acbabbc377b351edd86bd0b0365d12e9838f775693d9a6908478fa7b2ba05be85f10f9 -a020e51161e3edf9b39f1adf8b17db01842cd32a719f777700733cbd6fce25a1b9de42d2dc749e5fe37821ac98654869 -b201acb0906ed7417c344bdbc704f7bc33df29572b1c908efb2b9a5e0acf5e684167f434bc785ee67d4e30cc0ba85151 -82f0e6c085d1a346945cf8b688e9ab16526d6edec42ba90378ae278d1b622b80cf273f54dd4978cf2dbd2923f92d7157 -b91595fd25166fcdb1341a55466e4c2e5537de1a57b8fd45f6a04b3574f46aaef44b991329ab15030776ee2b7bb1d488 -919b0439befe8a2cf8a5ad897e088a5886163dba78a6026ab257b4b968309cdeb30dd39b3054f0222faea566ea081a40 -8096fc93e7128017ae42b2dbba0cda82f457fbca6d88f94d297c9576ca5a53c6148b26b5689aca218649b9e7137a05ee -83d3892d32364e25ce75d458989da570796bb0dd4af9c95760f3f28c673a44e099b50321d7bba04e5a6e8ffd41e85eab -a042a6b84bb0df37ef0b281f89398f611b3042fd7bfe5cd264ea59c38cffc836bfa8e6658dd9a08bc0a77ab6438a7e91 -b0afc50462a35bdb463a520cf7f5e27ade9ab1fffaafcb6083fb3bda64f9909b15b274d3b6140a2f4d13fb9196713efc -86d8df9259018681a6a64ebf623c1926b6686d5f982c6a322d9e1213183680fb38ade15780b50aaa3010e9f44241d82f -a44ef545202b37bd4bc021d999be64bf3b0b06792658e41f2c115f0c5ce1607fb0b7c0dbf4f050aea2737982bf97a4bc -aecf43545ad7a0327fd07e2789879e90616a5fa23152e8fa865dde90a4ed5f5d65c3f1401782c624a9d1c0531923e4d3 -a186914d26698cfe54c105ed621d0b9d523e44dc3d9353964aed0a62e64aab735fc710ddf8581a398de08089fe71c7d6 -937e4bc999774fa6f6e56d68fc2fe878f1fd4149f4be478b67b2c8b659827dc23e962bd0c2089532243e4b4e5a65fe9b -a764420dd2f8435a5163f88778083f3956c7dbedaf428a9ddce70aa81f99c2988a5d7996fded783a91ed2eeb437df4c8 -b3006b89a8ec4ab96c1b066f1687a794a9a8a617886b64bee094787161ae50ade927f32582f7a438359f4f390c83fce4 -93146b1416425560e8fb830d3b1f603f56a3decc40af54420da40c4c9552c4c909f365f509fbdb228de1a39a9f52840d -a96391d9c8b46b210e61ff1852ed1c4ba5ef8a9445e159c8f0970c391da0aeadbe54d205609e9d55c5a36c1c50e08d34 -981b4f63467bfb617a3a38baa8a6b7a9dbd51ad13e0aad3c07ffbd8694d7e4f4bfae410d28252b7499e48e63e2a3e9a9 -910f003ae3aaf0e2385c17b194e44ca031e276a7614ff0e9401583ab43c627c7651153712f4f10c006d2ea4764d4c5bb -afdc08a43dbeae1ccd04e036e4cb0b4fedb13c977d49bbfccc9634e91d35dfce6d55ef8817cfc4e79467508c07a43ff6 -b210cb18e0d53153ec48882ce6b137947bbaee9f9c23ff56195cfe5b730937b6df139c72591748b2c9f17b7ff62f385a -a2ab3c9063bd56391b396876c39b074000bf32495f50cd67d710b86ec20e1eeeb04e92c9f39a29268e41e7a6cee1f479 -aac31b3f0e6c58242a7c5460b69a5b88b63b288c32bb8505674a40003e4af5ee2df8a6ec62fe77a4693fd4a6695cd80c -96e057d57dbc656a6cf38f4c25b3ff2404d890178d5cad0d0e9690276daa315a08f39302bc1a7e1be00f4343dc342f98 -85fc4c65024367063287e29fc7c8ee78c30a8690b1752978a2045dfb3bf6dd06e30ef2d3da31c9d7dc513c29b10bb115 -a1d649c5068d844e6c86a288cbdccb02bbeefb7cf42d3dda78fd04cb1cd01f437bc965f583523e6d20aaa555741f2502 -b0ce53379fb618355069938894a7e213d78cd408df37cec32a9d3fa1109cd06d57472f0a994beb1c063f3ac849e24246 -85634a2199109c28fcf02c84e209d9a08f80d8e6ac195f11a55162b0ffa05a59b834ce1a8ffcecc11d3ed023ec5df1a8 -98538ebaa0e1546f2e004144eeb1013e91737d965ce9ac5e14eaea2253998cd6276c19619f4380537a36faeb0162b8cb -971010911df12dba25f944d0d856adf7232d571896a025994114e3bb1d9dea08eabc8100d78abc07d115209e0897f3dc -aa4ae66c2d5c995551ed563116d54eee55be4e1ff2b4769a33a974128b2032211fb1d7709413ab60c38562ef35c71c2b -8ea33a37ed4ad34854f5d2d4c4c57e38b3723503ed68618b343302cef8ea571957988ec1357859491b8f6cf58dc080de -9957ab2dbbb892f642c0461da51d977f91a0f07a587db513fc7a1e039582fc7edbb2b322db8708b736e5c99ffa08075a -97f129c42e0c452db662f5ecf4aea09ae63bffa38db84fcadeb8f0889b1b5a6cd763735c0925dca71be44f6d1dcdbb5e -93c27d8a21ef4227f631a73a0f10053f73b7340081307d9ceaabbc85c5e97dfb1abf9c7ee1ebfa61865adee22a69da3e -ac8a8716b0fb65f75afa51e8184588c30da56455d7df00f0350cf173bf8f1eda8c96d0f3ce487bec5ccb8ba35f3f8ce0 -b6136d65875e9f9f2b2d21d1238a43905890ef03d438d98c15042ddfab5f8d4f0c7ed74791b3064a496cbbd09cae3d78 -8213d11129a6d1027cb5db26340c495cf97882383a1aba46b863ad7bc978fc64701b0fd9ed0a1bb69770bfc57c6b2156 -b146dbf3e10d3a1197e2cb49b7e5c9f3af6f72c1d470b9cce5300831db808506d859531aaea07e7b2199d872f9a3a402 -aee752221ca94e9dce1c30d58c405f9ac2e6a9588076e8b2ba0dfce58386d3f0aa7d762edc52857e805e3271d870cf53 -a5449b57845ab0260672ca878175aa838e6f10f6a72aeb9105d5ccec0300eb00c95efefb4512047d522ed6beca42ae15 -97ffafe9adfd84f16a3f8d7eca0e896a6285b5e1928a84e8ccba3fb307c1cfc2db0212cd9f7afc167437440be82678cb -b7cfdeda43677807dc8ab2b29e5a02792e58f303bb198a17da6b8868c341132649cf3560cb614e9a1a834cd4bd571ed7 -b598659737b0898c2c343082aca4a8b94ab9d9c5d780372f414d20d457a03cb91e582bb36313125c303e721856c2b239 -8adabbe7365b7a4841ea815647e7b02d42d2ee2b608f14745e80dbecd3bb1a57bd25ea5a98711a8b8ebfaa9e1033ea2d -9968778f94b8142c609d5dbf1a46302fb562402232d3527f6534ce7563e0d8f1350ade4a79441f48aa41c0724d8f787d -8410e5e80ef25a0d562f6704f9767611edf081aaa0f110e71bdb3bd4ea89de03ad36de7452d6e398a336bc1446b5464a -80cadd17472f05ef5d0f05a54645488b1382b218f561e1c0aa3c66b024db3f3677456fb2213fbfda47aefd413e6baec9 -ad00410ae25ee613a213950f7183286f0b92731d32bb990d64cd8c46f6327ab5b1a53966cff8ace636509bf50e05028c -a58df09fc821b03114c7cf3c319bc1fd9576425849eab490301f1225155e0dfb7a27a4b220e99f48ebc9e7bb33e0b0e2 -a63c419428f753f9a62775392bae96bee4ff6c88a526dcebd949efb4c9df208af2353c1d9eb10df767e904b323380152 -b159b7b7885964005dfb3d0d3820433fadee814276db20ed0828438beca34090b7b7c19d7f78e9e3a840229abc189022 -8c1864ab1427ed50341897f6ef4c716ded5f53926611c44d26117f4bd4628b86166d0ae4a5006e4e7fdf907595e267a2 -b324a257d3c6605d8aefa84466a892ec72753a33193b7f927d705948e0ded31cba394f970a7413ffac2d6ff72ae8adb0 -b852d056d9e01198b8f970f6daad14124618f2a542d2197a915bc8b5c16668c610fb61d6b9a7bad81e29ef30afba600d -959a513814ef445564f1dcf82078c17f4c90a90a7d25fb6d3b0b06ec345e29b3cf7913c2bbd8106c25d3b44d9bb6eff3 -a135ea86382b0fffc1feb0b627ab41a56d0a59183ee8c2e15bbf41101c1e40ca9e42e954a5a3326e5e2fee204735ee11 -a4fbb86f370efc93b1ebdea3ef625fbec6c25b8675c85531c70b1e1f9549ed633e6b108c43b901ecdcc94c289d153eb3 -9289c067662b7729be68282dd21ff6ee715dab73dffc630ec3c31d35d83d1a2104c92d47445d0d11b4181442cf213d44 -96cb7544412f438802eaf4e70d77d5b627b91a02f136cdc2c3674152ce5af5852806f3280048dce364fb88eae3a8483b -b7c2dc77fde2c94dd07f16d731369eef12a35a4546b3c7f98bb8b32ae88d0c2779927754121787a72c6a4da40f253de5 -a942801627fc3b26a0d4d9cb6a48f4a5d35b26ed9314ffc6cb5be5fdd680857f0ebad809571e0631f4f512c786611193 -8359a72eb61fe327172dd53433f5e19018a12e8c7cec6c1938ed44abb194c2339ff94399df94c2cd1758ff9c92d9cfb3 -9707da6f81de22cf5db457eece8f1d35daf4acd769f507cd0e4ea8d057cad3c4969c469ca928bfe2651ca49ce24ed016 -8caa1d0f49f9535d351ae4db7f64d2dd1d6484c43faad3c00857e05d74919ab0f2ccc9bdb526556718cf9160329f78c3 -8a32813e72e587412a7050825a0acb0551f89bc61caa6c2ce6056bc9744e0d7ee124df18f6029a2f9f41aa902472a8d3 -aadeec65d10ddcdc7647e378ad5f2b9bf46bcd4196ff12834a4b23627b0a13765da0dc0f84c8dc84fe2612cd18a88ca2 -a4c97e2fc7ec2777ff74af1b255287b108cd9047b75ae7a10560f14fc3a5e8b001156a6d6797b2314a436244069b43eb -aa474d3cf633e1d521998b2b34d3d3f8c5d5db7faa78fc37c970680a27c3463d85c2f01826717d5def3558fd37cfb7cd -b9493ffb799ec6af7b31492bc5e392e7eb89adf7f98910aeee0ebc32c00b8e31b1a77391901857e62fe5d0c10a73899f -944b68b2e1256af1d99998dada385863152a6558cd7a63cd9230997dedb434419545dc3833d99508cefe0c04b0296c1d -a6cc5c80ad89a05881ec09a5ab6ccbb49a7523afb9c85a08dd090377149cc056ec0c63d3373ffb3f13a15f4abc020542 -8c6f0dcff087ac53693e48008255bd4329ec2da6130cd55c622d63d8b3ef19f207aafed8c9d7b11c7d60b3b87664e6fd -aac51c05cc67466b386698fede62d436b79849a5710522cb7c2f41f54d36e39e2c9101fab7e454482f3ae263ea8be4a1 -90f19c9d81a9b099821210b58e59bc0e892bc92fac306e54962689fd7accb91de705743b0aa5ef3ab1b6942f0dc12bf3 -94d5fa9465cf93ef86e3cbc87342bb5d8c157c723b7748fc61d003bb415705b7599bacdcdae05dd391db188134ef14c2 -95804e19059342f8e9b2cc8857b027e35b7e289400541a85c5a2e796f6076b6378e2cea6fae7e8f29377ac0c69a77caf -a0ba78959ad3a5cca7b214bd9bc817075d71c7f699d982648378776a3ce71fcfbf1062b04a8b4e16077d6940992154d5 -8c24699416cd41b2e906fd9fb8517185c7977b86e6a49395e2af4a6d25fa82f86ab1039ae4fec37f4a52b63804203b80 -a28b00ec3ab90abcbbb692c29ecf6ceeab09551847a1b4725a0ea3102e19dda5a99b64fbe5853664a6064109e212254b -b5c3fab27875ddccbb4f93a500c9a6b3c634417e365cae99bff165a2d544c9cd6a6ff55e042fe2bd54ccdf4ce8306228 -ae0ef8516d8c4dc1514de3da39cfb5b3f3d2afe77e9381389bd9adb07c9eca587b48dd370893cf1a6bcb8c094ab8989a -acd9a0b0b7aef79bff1532764162d13e08a0c34dc55a246e16ac47986877789c9061a68d30ef1a4946cc7608b79cf8c8 -8146a47ba4998bd4a4562ffeb9dcc85686916c67be2c4b4f8d561db51679005b9a47bc4ac7a472e6ab89d7e8ec2d479d -8aa98ac804b0e71d7d3de780047fad561ac3ac5350282462625f3bd24ecd1ba0317b218d5086cff206c38ea39b30543e -86129cc240a9c8f3597129b6dd817e5db183a8a38d63264e9ecedf4e0900f31eee17b3a6cd593480efcec9b6d3c4d553 -b038c48f9dd315fb05bacd3023ef24471311c595ebe6a5fb57c4d6206445ed18dfe45649cdbe263d73080efd41110695 -b3976527178c76c4c222297da0835669207c15646e1d0d24cfe6bda6a001f5c248011e0509ef2b616e16249a5c9c3f47 -95b205cb1ede704760707aea034cf9d19b26b273c8aa690241b8a461254b05fdb1fff688796b157a929ec0dfdbf9d610 -9762fa37cc6b1cc7f7fc23d97a17458aacde74b1f3792bf9e425a380dfaab970393fcddad7241bab10fa4292a70bfb0b -a05276c63cfbfe5defbdb4ba5006a87a97959d80a3dbbe8fcf40c71e6e5f03ed85678e6894ee01f0f0bcc52dbe3eeee1 -9530ea93f98ab49ac8c284480a562d62682277e2fcfe7016ae643067cc0196380194780a0c2c03731186a9d229aaa45f -93c03104f921fe6d41b370c5ffafd25bcf952bb7de2722aee7b7a1d28de02f6a326e508d4b2bdac330705e638a906d19 -a2f3061f5531b684e2b539eacd2faf2395fa28e270e55db7036c02e41f8bd244c579b7746cb36daf96f30758d46946d0 -b97fa4565f5f67febb9b60dbcc3e8047f7f0ed963f4f4b1b8095a6932bdb31d1eb47bca6ccec4bdfec115f3df1258857 -95c1f51a5f5cbc6637f628100897e384a814fc1606377879c7df06d54edec53bee10b80bfb18f679465b9f2613c3b117 -846b81e8089df8d288e0795a719dfaf307c659d53cc09102e30876368ed7d818264cad21460b38641e09441dabe42914 -aae382dc2ebb20bf89d44ef010d76a7212f5374a4fbc5caf394ca972fee54322d726c696b86d4e6b9f16a158c9065384 -899255fc47db3f1e2694d2f300b14e765b4595224deb9527033fd16f25ffafd3f21a023113fb848a0f96931b6ef31b77 -aa3ac7fd484eedf34ee9c48d4dcc1f5b658c54afa3697d573b2162d4b0a2529cf1139a1ec5c00bba27f2b344fb0d191f -b66c43f81a1be23e806be5bbb4332d9448b8dbf507755bc0be2c86737a4bc62ee9a55cecef677b22300e7e00257068ad -8d1bb37d004040f6843523dafc1b8bb7f8856dcb160c65631799708e5668003215954bc44eabb1aefc06f951ecdcbb40 -93a29e38574573be2f68b3cc2f683c3b7ea7bc58ecc58f4ced0d2bf908a47edc48cdbc84293fc468f1dec76a6ffa9919 -92a468d7f6ac9f14ec6a0bfff01888a40ca197ac817958a14bb38c403dc05d31252137d46950b0b9f242aea0ceb7a184 -b6b708061c43b0b28ab94cd0c9ebc33adb9205f5c0aa84d1367c4e5a4ccfdcbbcbe731aca830cef25feeb744e52775ef -931c274184f3d5b61f23c5f7644694b956eb79edd238e6991c13c986838ae1049fc7b695c4d4ec2aac42799f7d59ad6b -abaae09b111f9d85213fdfa953a8f7c15988a3b21f7a71264f323e39a91db4d9ec836d4b27ee84d1d8a267c570e06af4 -98a145c11bf6e0c98810b8983dead947ec765b3bd7f9e245637933372dc1ab0cb24441bce3f18c25f70bbc91d3f1555e -a94ac8a11eb64bcb8185c1aaded79996e59395b5d130e57c12a946b3f0a9c06e2f583ea0ab98b38d944349e30bb393c0 -83facbac681dd218160be5721b7f70b6e0abc6963a721278f5f8f11816ea8848de2a12726031404f1bd3b0d93c7610bf -ad7fc2b78179621f502029d229cc936039360fd541c760339d4f6690644b39c36f39c435c45ecd7b4c683b45b5de8d5b -a93e6b114299c348a530c0adf04e3180de8c18bb04589b3fdd358dfdc118884c9554091815a01114a81011d9e8b9165a -880a5b941e6e7d213f0912c4e2800227ffe3c1c5db141b6357ef422ab8e55ef2c4de9a7acd6c88cdd9057e9b700b62ce -a79a25b8e8a2b6075c536822981d9bf95e71b60749a53fc7a40f309b92034a5a8a5aeb0e6e2f03e8e24f47d765fc27c6 -97e5e6a5b56d728e8cfa6eb048b74be6de7d1505a6e4354964c5f27aaecd8329b5d5150e26025d5e1542c613bf77a472 -a58bfcbb8bbf0bf556c0993936beab3a874b10ec56d25ab52a02b80ca4586d30d7f62990157244f326ad6de05c95dbbb -b5e13af56257d4e4b77480dfd738a498a2a78e1dc12cee786d60100a0d4c0adbdebf2cecd2ddae56b0a3c143c3b48c9e -88ce83c216b7f0a74dcc614f56ed9670eaa4052e8081124360cda319158e496b47edaaa8de28ad1d3e3887206f8c9fa9 -8c821c9d0f339837f9ad2136dee0e1385a078fda212375f2f79a56988f64e523bbce59cffc48834418cc37ddeef16e9e -9249c78a361432d967e51746d2e892a71925ad205ed71b93911a27a3a1135431bb424ef0d6d1ec961547489b0e45bbe5 -994c0205a2c192053b676486091fa49f6385fd404d106ea0949a6d7b074b79bf974647b3fa9bbb29eef106b12d004310 -a15c25bdbe3d8da65874337dcecc8178c35cdbfbc9d9c6b80851bd97690fd2dc2df8012f671abf2f3d0a7c80dbbf853e -8bf4a209ac8e7d639eb8aae0d22511a39d9427e8418198a34f59782dd9f6afbe8540c8a9485f121e8dbea8f654f3bfb0 -b455d43fd5dde19a3cd73b6f9b3f832f0f7995bee3cba01b0357209f4cfb0eedade3d3306815da4109d05850bb40acde -912e13fd316f16b882fcef2f00cf043eb86045ab456118f7c3621a5414c281fae951b44c417fb733c43e146416fa54fe -b9e6af5922ddba6584b56c5e3cbcf695aede93271a8a26c200026d9941c564dd27b38843597ec3924a81e6d209be5a82 -893e4d8ff12064c627128e0d33c499fdd6d884b41175e8dc5eea7a52ddff50c902b899eea64b549926a8478666aa8b23 -a07b337448f014805412c1f55516792eee49614f22b5b7fe7018742a6a389d496611f327a3cad1503c3eb3f416edf869 -a26760e5302364559671560026b6d4f26e3703238d4369dfa73536776bacabca0cb264a5806c0394c0c10b783ffc3f56 -88a0af353d6566b8ef5f32e2a5066feb9b9b942380aa557833371a24852e96a4983e03ad51e13ea4940e0eb4c75c7664 -8600082fa012be340643577af0417ee29ba540e23a1aff0f3568a0adc1a854e742ce1051b3d5da779066ddcffdc65d06 -88bd1dddb613991b9ccc3be5f96f79ded6c1e09ea96512b6ed17b18dac73facae88cdf0d17da01e7cfd5c38da3d06355 -aecae22f713b2792bc9351ca2ab301b28fc578c2c1ce6ad39800385e95ab275d0c1486cf5af08a54e15f17641ce60f0e -afd04d76335c81e86ab9a08b1a6719fa5cea4d0f090f4c678fe96e09e7d38ae26766521dd20eff3c7290e9fbbec1f081 -8404e03d13266d3d331c7aeef8f905d04041abe496027b9f9dfa1e3c55c43dac78634fc5c860bee8a9ac856e10224694 -98195b3fc94e03ab66eef7325c36acaaaf3f0a28a2440cc891939e04281b2951e4b1316d7f82842e2001fed444cd880d -ad672c6f852f812486cd8601472e36aaf66d5a873b0843c2f93e40865fe017ef710c48d286e188e127aba780dff24b75 -a3b9fffc17035d7d3a66cbea5c5014992078df6a437eb8d4235cacf6ba24041b918f4b61e6d285e278483c45206d1485 -aedfd94a7ab12c5c7fa25ef458fb227bf6cac8848a4873961e8fba90b1bf7b9b6e688c1217517e5ea08eaf39da43418d -830837da3ff93282d6dfbb02ace35fb57771919b49b6bc51b32b3e7e41f2761cee29dd6861d106a6e7de24879f58674e -aaed884ca90cae6dfd11408858f75b6b37db8085e221a278e7cea53a22928d6d01d43b7f98e9e5d0701df4639d28ec4c -9981805cd99ac373b92f5bb4a0cfbce7f07298f8a5632014863f7a071c68494b5e637b7e150732c375aca06be3d79895 -b6b6bbca3f8833c02274f182cc9e53cf72755f7913b5354413cf16be5c09dfb308f1f045371284f467b7a40e0f36560d -a7f0338a290d682cb2cf5b891df35642ea8f9befe1d229cad22a16c2735fdfd3f3c26ddafed41c7ed876b0cf54612ceb -b038d6d7b5336bd9cf957951366f73d484bf1da3a6da1148484474f3a7f7e74ac7235ac63b7d9d1011a90ecea402ce00 -b43cdd53092f4195fa6a70a713c9096c8ac5102302f2a7ccae6afb933a579485e5fd6c947f979143e896a8d0a264b1cb -8d3310f5e2e8546b57c69bd9bd012ce0a33cf6e80ee5c4b258a41e32db360b0487c88cf62e256dc5f6e9f41c0631d750 -92d4960d2f5cf834e24988f3ddc9380bda961de7d8c40a4f0684242a64e0ddc3ceec4feaaf097b7f99012fca57e74615 -b60ae72c7ef431db21c81b0ac9ca57a664fb257ba449191c92dbb88eb53b0100f0bffaa99bd44a4d84b7fe1730a7a5f4 -86b1ed40457e02b80c93120c8f17525cb4315c68c176fc3eb56e9e26d26c1c25eb3a24df2b6e93f1675e0f47f44f6a86 -a65d03f81d71530c768dae364f64a79b4f7ef33a9e03bbbd3f2c486c3813824a3d3c3953aca21e66fe0cb4552f2665e8 -8553f75b09a1d294367a16456287ee7c8d8bae29af9f9594a14658236db8acbb363bbb9275cac3d934619d95a83f38bb -96f916427a025dded34a24fd49f49730725cc4fe6f27bec379b3e4f0b18556881badd4e588dab9a29ec4011f7ef7edb0 -856608c27413af9ea3297aeac5921781216904c76896906c746d07598fa258e7c561ceed240a0fe6eec5f0d6cfa9ecd5 -b03f150ea87f48e8ba533d448fefa5119515e6d47afc25d2928077680d562d6294e1cb501d0a428112ceebc42f0ffbce -96e9be02b6fe585294b0f0e126b21ba2327b8e74095d1eb0dd8ebfb280758b07c43e1b1127f7dbf88af380f85846a983 -b866d4860775053c82c4c6fca8c0d5689bd673df26b30e528bb8406b0b871d97a7e950e90f2d95a95cf546bcb80fb6f0 -921e4409abbae325425d2e67b9fe9617ad4b00710e49f704485a3ec947bb7282b6ffad4a303e0110ecf46076852e929a -a52e51329c2995cf47c87ffe47560ad3b5222d19bde8747a9fb056e77f74f869cb4c23f3fa4b21e9de5a61ecb6c52432 -85599c31338482e3f8216b1ea1664ddae5b15977efa0d8227cb58342e88b26581975d9b1cea91c98d4a86d22558fc78e -b880e82d301ca15a01bebceaa7f54bcca3cd0fc92558d1b942dcc174a85ae8a1577c5e0feee963e41636fe372174e938 -b50ef1235b1283b490b6bfad836dd8cee72b86054f14ce46cd76b89c97f191f040fc4091af9c1bdad53a132bf751f7e6 -a8475ed4ba2f51f9041f71049b7fefa216c984494398656b58f317905736cce2091e4df7dbb3515d0ca72aa8ea749338 -95c4c4005cfdcf2778b8b27dedc17aada395eb80bece2d4fc8db43654f827d621e539d048e50373e9ce14a60180b7269 -99df65189d38997ebc4e6e2dd5075511f735058397a33d252539a0afe517623b7910295a8742682a2cdf4e21f603986a -8fb5fa37b512b9b02182065abe7f2c74ffc1a487c78f225c6bb82da4e3f245a8b62b652a7e64a0f52edb30927046b6ab -b242b2bf09d8c46a1955a121453893d455bb80e4dd648b5e87415a5df79a19b4094c55b813a5b1a488802e31d26982bb -addbd7c3a9621e2c506b7a172cf2625bf52b3af988fc24f2ecf47753dbe1173d95b86bbf4824c247675f57bab328e9e9 -ae95b055a1a249d19a3f080ce5cbc7065f3d009ebdeed03362db903d1e5138371a1564a9afbfcb51b620807d0e8f192f -8bfb763dcec00c041492d5a5e57f9c7442115201984f353aff71a08fce2ae242189cb098e43fb642e808b8761fa517d2 -b07b768339a8876887e920e5dc5e30a20fb24afa35b51269e154f5e75e93bfb334c6720f3ab143cfaa064221cacc1384 -9938f3d9d5a1da8c84dbad8e464e32dae0cecc232687d78b0984cd2b332ca7e41c6d5eade73ad9b95f0d9d076c8fecbd -959553e80a715ad90f4c83dee5bb1cd12b408b7baeb190df58e341e51b74018265dd2344602c74b57a747a75269f3e88 -a443ccc6b4112469ac4fec7af54ed637a719c1b0e0639742589f7a6309555d4674154f6d26839b76e90e9f82bee7c79a -8eed45cc7a9f3a0b2744488558c9abcc7a7e67a01784d4023cfc893ab88f443d355e4aee29c784d7195639ea7286a738 -996a81c4702567f42a957fe79e1db9f057b8d6a68ab4bd6b797c8f7319901919772dbfed7c0eaa9e717bbca61ce3aad9 -97829a09c35c566e6ba2b56d41ed069e6bdb48fed06dda7b8904306baf347d74467a65bc9505c9ff0ce2a1b1eb93ecc3 -94611efe2d155dbdf898312b53c51eeb30564e2608c3dd128e7ababfff92d5ebcdd8d8f3b6f57048cccc8da7d203c505 -ab83c9c8ec3db031b825af7c62fccf8a48a8a8746267ac7ff0c3cef0076e405b6ceeb459219d970239e76149bdb22278 -a5d8293e8bc13f832f1c277fb8534bb351f2e647f0558e0832850b74c35e101e5068752a9685770948d9203a68ddbfcd -93e1535575cba89e954312e9cd70339c61800b6d5627552749fffd4a77bdbffbcf4841944b4e9b38cf17400647434657 -8cf070ae2e71bfd843f9a13f5eb668e2dea943122e5c5d8c52db9d42e257f84e3b02cc22eef3f29d847f89c8051c8811 -a7351f0c76b8b678aff461c1fc78e8a55d20634da44b73d68a00feeabce0cb145149ccb8261f0269e3b5a43c93532dbf -9962048d16182ce28334b5c1c7b7a906dc54a739aa8a6e46878044f4293bac672904bec2292a288601cfb8b77db8390a -80dd3875dda5a0e8b747d431f5be4f181858c88a347b14cda91fecb508c6fabd6844adbe5d24fb0884c23a6af3f2e968 -8a6a9b3f7f99c4178e8eddd369a760beebf04fae990ddc8f0c2addcfe958b3318328f2d44e92515d8fd9c5b7cdc3a8b2 -ae316364802ed4a156e4107795896db8cbf1321d5d0af5ffe0d0a4805910e36429d9d01610211e7d9c716b4efb1b68b3 -9393c2bb0ea1855edc3b844e55291f3212b09b868bdc37cd7689f0d7e92c7473937af7ac16d6516141ca1dc17ccc7150 -ac909d1394e7d3b373feed325873310f29dd8f46c911595c2e8325e90ab8ec52672d921c447e69ec2d9bd000bc41cecb -80e58b3c07b9d8388a7bab67b77a68c7d1dd95f48b53f85a1366e2ff1b1d09ace885a80f49d686aa2d9dc6fc3579a700 -899bb130c5bc3703b0484a2aade21f4ad9099c482935b664d3db70eca3650b445e454578415622b01f8adb53403a06ff -b449d6a5c20e1c36a35bd909854e336cb097e2382d048f332e21aad5954c50d105dfe7d4a28fec14f1edb263f2e2c25e -b45b4ff01047afc7c64bcdb9ecf6a27201803c4ccc16ef36fcf3df02af5b447f7e36d7e150f847a5c767902028cd121d -855f8c1046329430595bd7a6e2612f1b5000ed5a8904a4ae924b132a3916626394dd150c383dedbb22e4475787c13e8a -8259182fcb8075805661c68773b5772781c45a1b406dbe3291c364e99336c89cbdf1a35b4e5cd742e0c09330967c79fb -8513b09f6cca871ccb53e0087352a015fe23dc66b1cb7985336510754d30e25c555e0a0883c04d3d8f977d1b14f8380c -98f6ef6f5267147ad71aeabda4ceb2a010b998ffde238cf461a4081cfe2f94b174c65a5b99f5bb12685a21f6d40e5d1d -97def96137d35335fa3f8b3f0925c6f785644123385bff82c67320810e6bc3116d23788b7e7682d28cadcd7ebe9391b7 -908424f845cf4bb30f048dfb8d77429eece0dbb1f8114b812f835c0fc297c7743385f2d9c389b132abd8b799abb906b3 -9342c5de2b22e2ff330073e79491dbbb8e0721f7f78e2c4d26b15e7a038a3c83356d170f0545996ebc28fb4090415369 -94583de96cc41a83c572d66fc2c91c62fb2ecb727de8d3af460fdc6ee3d8bdf6db92eeee454d0f0911256455b3527e2b -8923c81cfcb0b3826db821aa3ab3ca367b5ab75a14a73d98083d88d3c6c6f080b62c2376a18da975bdaf00ca3e3bf6ba -8d2fcde9fe511d5c030ad76bdbe60147053382003d76ad0e823f88bcc3a9c0c2dae49d8456c285c4782dc6cd6945493a -aedbd6629aa8732a94e860328ebf043ab713f36ac8055609e49ba250bc1a41f55f429788a3992c88a6769c1c37e45fb4 -8a692621506a50e26210b593712ab8cf40cfd79daf197d6130d603da70e2c89983221bd43113cb54471f500ea3b298e7 -8716022f429247192d04b007b4bfc6a35caf49a613641037143ce2dafe7b5a4930c0cf698c216b761b15ce63f4f4e4f1 -afd66da5617b07f6e14dd039019b28fb5aff8f14b4c0af5babf485d9e9ea77f3fdbabcfead1068c0415de93c99f7f69b -973cd042b5b7d6d8d5f1654555efc16d77d6e3a9a4e3a80e782db6bb297e4269df882d59c73d8ece5001d93baaa28745 -b0fd22c75caac1eebb54d621e12a437d3f50370ffccba5e90fd65a934f7c14eeaefb9d2c2af8c105d9757cbabc52d65d -adf8fe8f0daf405a5cdb26e4d99b10a9b4bbd1e7b8344dfed8ec89a0b452e1168eb12cd587606f3a0179f899305ff35e -b66c5014864c1e2fac3b1a03d37584c270989d770a31c43f30c5c64e887069390006ddbe4f3d6096917fadfff0a82bca -ad799ec175eae28694da6be84bf96b58ff464576b0b4dfa041ed43e18cb920dacaa8c2d6641d3ace5d80c01b0a885270 -b9c196d7d8095a4220d7ffa859ff843a19f0590a69ec1c7226f4132217770c122a3015454df562229d1cfb06bfbe75f8 -a88ec2554ad628af62c2301aebd842b1b613aef59deebb699ebce014ce49dc2136ad78d61fe3a5bddb52c1a37758564e -a7d13ed42552238853ad75a56b0b4ac1eeaad35227e8f54e345948edf497cafe3aa67bf5734f508e3a34ea1f84a2d619 -8b315c5e62fe691c1104fc38f0792499c2131f6ec94000902edf0888537f26b8be3d9d20cea29300459594505b457b73 -952d39d655d22005c2c0d06bcb30bc7d9fb4b074c0bd67b361b83d34987923a86575c7d3bd7e727e1d5bb3b030989769 -8469a8fafe8c5634999f674fa5b35e1de52dce5075f6c4b2a88417618fa3e82f1216220a836c343540c3f82c3d8a27ce -a0016f13768043458aec744bf7b052358f8a9efc0f26ddeec4bd8ddad09b40b7848c38b401e2bd67a353189b635fca74 -a7c9cd785192e32ef4fba350130af2dd577d6552c4365b9b7b30eb69dae48d68bc2ebd75ce6b80641d8f64420a1353eb -89d22056f344b22441579fa70614fe3f90c53e444a68ba31a330238b7080410bb587f4461fe78661eebcd972b8c91c4f -84c38a5e852387235b9805cf547ede71d7ca65827189a1ef25a83d9d6e2520e416e0afc28d91436a0a234f1e7efb99f1 -b1c170741d0fcd59b9d534a95e1a5d61106c1a2b671b16cb231de933c03f9b398fa9a5eae3b78b10043e3cf5183164ee -96388535c09dc84a1cfc90f22f8491419ab3dbb69889999bf939852acb34af2c30c3dc067cadd372440da2469a7fc749 -ab1211da4e11830484b271a9accf219cb49ee4c35a67ad61b33bcbe1d91b37c72e8632667e32c6769b1ef1d642313d39 -b86b69f64c4e5b603279e7804413e0f9787144a8e3f0cbf3c62e8622131450b4258f72e43bb220fc5d5b857455b0c450 -89693d9a04166a2b9aabec99d6962a5867f9e71ba732463d01ddd36ac3faf1351d8da0d0d836f285999f75dff5e79429 -8f2e0e97ba00f8482ab677190649b41a32109f0391d0433b89b3e73910d66e0d34c33cc4244c0a3b8282c1e1ff4e46c2 -a0c695498081bd255bc21d2c99c4dd9f466dd2fbf93c07abec13ad3dfaac697c8e87fcadad51f8d7e1649b16133b7206 -8254985bf2d0e9f662aaa58fe902cd594fca1c4a0b6c1614bfe621741ba17fa87d55cc5eb0118b2b3e36ec41534d1e4b -a3f674b4b6eb28a397b0768f3e442eced9ebc77f6b940d4fcf0c61410c77838c024d4c911521f11a0267e3c281f83876 -8d0fbc99adcf95044966448efa4c2e0a17f6799943662476d1877894562f3457a235b6ba0d34bd690125611fd1db881d -b8815547debbde07b3106143a37f3eeb9bf823065e107dbac9c94083376da22e8db6e29d3c3bd51d64d1e2ebd8f2833c -909001246abd7fb0dbde3d1e9410eccca09dd2c8d401bd9891f403c9b52c175008e052b2574493ed7a22299a737a7bc7 -8177f4a7276eb901c52afcee285ea905f1d6d01c1d4da2e9162e268897c020d81fe462d978e27ab42009467e918fbae9 -887128a316b4d253884786e62286a75a6aafb87ffe5e14cd44151bf5fd2aa93cc103ea46ff248225546eb124b0fdc618 -95aabc433f0233b5e45afa8d9adef84778393b3b366ade8e703f63e540105626926aff14c48ca896ba3cdb99b92e4113 -8c6d6b33017d87e15206ba8ddabffbf8610b5f05484137fd79ef98e77937465f85072eb5e079118a0f92c7ca996a38fe -b2a573683d47be62501a33fd228cb38cae0e26e66fdcf4716a97bab823fe39342172c163b21fa6566bf140ee6c60d898 -affd9c21e842b5abd6db2e82e0ce355d8301282cef36e2a0776fa354ef4a64a80fe939ac03201e49ce36c77b95efa31f -8e7e47f99294b735895118fdedff27918351ef22e16ddc814ad64935bd54ee68014349c75aa75081c7b35a19de981209 -937c44b8ffe0fccee348d5831dba4e4c5e83b6b39d056d4a4146987ab73b736eff92c138872e6da06e1eae3450050ea0 -8bc22e1faa0fea57db16e0a29cdccbb658b125f0da6c3121c156614dcc835b1eda596374883a043e3cf3d5812a32f6da -acf0a8e002b5e47b0f591ac6d67ba7d2d03c0bb7f475dba09dbe877b50585339cf4367d35118d7fc062299f74076f06b -988065fad7da459903d1c8b1c5c5b2a86898ba2ef40f259af52c100554574c0605eeadc5beab8631bd9751fdf3a099af -865c29b5f6db4c557f26ae68cf3f09d2723e6a4214fa4de8252343e5b13ea98dc6a18c43a2a957f03d82ffac04d96742 -a4658ecbaab8010495d2253ba880cb9c5d5e4973544b982de1dd001210cb3dcde58627a196ed36d33387224a057d59eb -8d7f1dc9229a4712f244f1e2bbde55f1ea9fe7bf30d90424d70391ebc839623c7f58924054dbdd813de971d171a1c895 -b918b80341da1be2635af51d33493e24a3a51468da0c53021f375319b6d7f142bbb9632c8ba512b0de42b51d8e2116f7 -82b633d66b9136f5da10fe6e7db0862eef339342653a1f5ec1b288495359bf67130fba5404b4a601b5cc1d9e931d2465 -a8b51cdc519fe1bb07517d64161b02c85ef763c265c2de76a8287b7edc63798b50afb168c324a83eeba514a126e9b291 -835f2cb916f75eabe0b7c7527bb688b1d38c7f033242169553b84d6885735f85330ac1085eb2a65f521331b853c76bf7 -b0f7e967bed7e73a64dab9fcc191426c50967c43c0b68b685241cbf87653f7061896adbe5839f685626307014ef3da47 -952726763e8ed7f06953bde904d0d85e9860c28038dd347efc18f7ef9a0926490c4ce8d9a244b33f07d9ff3d5c8000e0 -84f1d8c0f0de624e7b11c01c8fd5ca0f9f14fe223e4659866b3d25def1aec70ef2b84e98ba57e801fae2fb0c924e37f7 -8eba73a7f1222791916680e3d5051ac465b705167a3248846e41a9d38ae464365d2112e0504e001554d95a674fe02961 -ab8c38ea34fe35bcc1189015583a8ffaf4d1d3d25dededc316ab3ef323dd2b4e7b5848d3a1346a0830573304fe5789c8 -977b44b1953df7083b3aa462de8d4f1a939b7d53208a6e059a4667d57353b0dbb5aba81e7ef527c6ad34bbfe31b1df6e -acae51ed5bdb79421e48141fdaaa2a0170bad2b5e97f29b1583cec868173f035b741cd0275bffdbd6b1c5075a858778c -8ece5d5654085fb89fddf30ebd1ab7f7c09f22f36a3cca243065a93a1f17e3ddb8c5715ad7966bc358927753181e9c7b -997bc4885b71261557d2c769a3495678268abedb4edb27e8e76639c337a6e3a78bbeeb7086f54542be43267901269257 -96ac5346877b79649d51e6a04468741028d7166bec53590e52b78bbcafa96cc4eaa6e92abe6c2af27b7103217cba65f7 -9475731d5e5b83c7055e58270baabb301b4823e155986d9ccedfd4bf4cebded42040db0f071a210e0ab22ead92e737ba -ac5c47f50345ee85dc0fa567f976d8b7c038b3d9470062186042e2fa4b04381af438abc593ba4092f3cefa37e82c7017 -a85004428219e9488a27af2115efbceae9ed359ab20426cb6a213fec93a28175a1381a4e4465b6104aaff7494091ebe1 -a31a71e29ab0f714bec2a9411425bdf2ac3a4552840d5ba652d4c1f19a9b9b6eb5f06532e14b135cf02fa815f318cbdd -a9c34fed2cf448acad354248c32a7573fd84309dd980bed3b16df6bfa017fa6c4612b34b951e08001bdde9225ecf9925 -87f7b7fc0546de30cc7dca29e736cd46b4a8dbc8cc1bd90a9997216a6cf05a624439077b4c3a64bd9f6a393fdda89931 -ad7643a4a8a78a47c9021339113dcdfe7b3d6ce49faa7bea89f6c93cf6e3c89163d36fd20af31bb05ec85224fa80114f -8c42f70e3b415c8b8ee8bafdeec72df7d6e2d98f816de47accaef3bcc3eec79c16a9cf6e544b584a15df6d1a6a33adab -8e798628a0de39fb8fa41a801830950129dae10ca3c921048754dd922a7cc57d4f7644253706630aa8e461ac812ae4cb -abd8b79cdb7f10a1780c25bfddba5e5ef15f59479883447946f9d986ad7a56402d5fefe890127cf48ef4e400538fc674 -b0367e76fbd2868c4d26d2cef24df0f006a192ab19c52476d1ae0d3695f1070e6404a482af965035723c7e806cbbb08b -afa927c8bd26e0d56779a25517ddc2d813762f3d051a39588d359387c798b782aade8ebba7b4f80c6f091b7eda2e9a0f -b3a846e5aa6223123c7796eec02d139183ad6eb3e3c4936ddf8b56def9f33499611849a6377ada918f0da59e9cb23f5f -892a88deb8ec826a2fe56f4f8b33243f366cf37aa60bb3e3f2d8537af87374316e222c77e8ea87aa2aa1cb4757fdad9d -af22022daf80e3ec5495e2c413b5399c74e515562724b5beb916b5ed4ff9b8960848feac73f54dc460623c90efbd7aa4 -b9a11e155d91be316d08ce66ac1c9643afd007dd5868bc9e3b11db9f2d425bd4ee008449ec462482cec527767297ad63 -b0f8016f1440b8e3af6fdfe042af4023e04889093a38eb96f3a0a3855ed92ce18c752204b8325c4f0d308c69817215cf -946231cf5357a6f936ac15c2e237b3bbd57449be54ef04fc9bc0f41558912f0ee9bd159098ecf63e4739365d147e334d -911c1c4e3a95238efcc91a1e784966d6ec871517dd8621e50e39e29e3eaaf6f442867a4ad3920a467ab178bc6bcc497f -b6a43a06726fb70958a97f60f5dddf36d638167db12673234134c4b50eb031e83b98e1fa59a8441246a14bb3c42b6975 -ab401f0d47d80f1694cfeafbbca230f212e3266a0bd7377053b2ff67c582d588ddd494894bc1eedbf737cd12bd521084 -93a72a6bdfda70792900c0fefd8d965a26b9459c78c1eba72725416887b7dafbf3537cf84a7c60b38dcf7b2f3a417226 -aea1f6932280a9a32bf7aa5cfe5fd8d12fe35e3c6197d1b24e8d006fba87645358b788168955754da7fe2e256b77a760 -86961d43deccb4d4a6e35129a1e58250cf744b5c8f7bfe4af40bea9ee9f859f2668872a46ef54d5590b793e70ceb44fc -a00584fe7feec01d863b57894df34884fc4f05bfa3d6677bc6346e615eae261869651bc16e09f36b15e071d14b6d6ec2 -a9a33a813d7eaa1d242fb4e6f9f1d5bc6094e2fd344778c9ef83967243e38c77e0d95da9736dcc9f4d7eb48814564ef2 -98bb194ca38025d9d1bd0d39806f1e6aaba0f1601b34d62da293a71e07c01ef973f367886d920dca054212665396633c -862c96a93a5c8b057f3f0b1bbd3ccfb9aa3fbf8fa54896c5bd5a4d472c873542dbe3f85fb3202f800de3a62afe7f24bd -b791bd82dbe37e6367bb77504f6aebc9033a9c3726f4c5dc7e78cfdc240d811a447c5ec6a98328666ff4ccfcf34429ea -93f71b1f8ee703ec9e1e846ceedea5588337d9ee55e536467fe3a183b57574ff7129ad4c4a90f8a85a473782d949f793 -857545a9c3876c8f91ac171d1245606d1331bd86e35dc899984b5482c6132d5038598d41620532882b04c0d120b0831e -b3ed0887ca7680131c052b2493b119660d82fb776d78fdd9412db470bfb94d5bb99feb92c4378b72ebe0ef37db664ace -85ff9f917acffeecefda709aecd72699092269284039a237329e80ee2a71e759f4490e25b274d31c8f4c60016753c40e -99dbbaa49fde2a1c6e9a9491b09dbf8c6120a662a85ad37f310980002e9fa8a82ffb76e73376358364f0a9b021d1e3fa -8cdd3168e8aa14a63d27bcfe4e2cdca9abafd8b77267e05f5ea2bee3e2dd75c0948f84ac196bd38dd4d552925653baa6 -b7d3eeca5832412b9bc37c04f81d45ce2b43ea6d1e0e7d4cee176604aefc51b1df898aa80c58f795f288fb65ceaff267 -8fb16ba37d8d49aae9f7ce48a9d2c511c4bada41d500f6666117617d1d83248e85af35604843959b420f1f0bf65f0ab5 -b4dae92205a4f863a1d77cfad94d604a90bbfc9863fb62e96e0019bc943a9fa04fbfd958e19f905e1fb5c834557e0f0a -ab04b0590ac800d457b1a2f0493a4e7968391b623e0b54ea27362222eeb5dbd1629794566052add8fb09844388c85f7c -afd1872d0eae250a73dbb8ea962eac230aa5c70ae8b34519c60cafebed21c35daef3d7cff73f354b511035f45e378553 -8408af10276f388ddc874c1aa7d475a52fa4eabf465d4ac91bd49cf6f602cfbfd94e0cbcd47e1fe60c2256f7216b0185 -aab2fa76a6b2c2c611b35cc4760eeb3183958734fc85cb94ea5f82364b034a65502b63c0853b1e34b404a52d5f27ab58 -aaa1c58fb59459f3cdc6dc763e67d61c275b3b713667b5574a5a8d7f728fb103b57fc82eb75afa70bee9ee0e4a1de5cd -a2386a20d271f465c9070109b5cc271ac461718accfd6efec607078d4dfb183f83fcbc13507aae6d4bd3b75840adc792 -99aa7c9d89eaeadc27ada6d7b8e7da7a1f7689d67a980505354c76d516d4069320a6f008cb01248ff52c3f4792d35c11 -93301ba65e5000559171243790d4d1614e742ed2d7edaf5968e3fc808d9c7ffe9848fb90ccfd8335797c5efec6fb1fde -8c09fb031063102eae48a49b6c8505971c3d0c5a51ed5d5772782f51f359165641659d4a8dc8b21c0170a2c301b418d6 -8503b5f9a5aa7b3fa1cb9a1331a1cdcac4d0f48b3d39eba44c91f1777826982ab435e2715277e4af568aba1e6d6e9c02 -994f42763593bd319c53881e775001e5dfc2f73431491e6bd7cee7f68d67c2fd07f9c3d42a67c701d81e78ee1d9dad32 -81cd9b37b5e0e4b981aa950b75af66c7920a9a14ef4bd533a1601f0cd657ccf30fef88f4f0e07bccf21e2b20dc209874 -91984357f1a830a696fbcc82877e1835dec6d7289a8fb7cc425cca09c29887a978cfc46e99a050203306c2628a58d144 -8b95c3e7825b165f4db6261f8b8cc64a2285021f3d51c1bca49b82d61f9549dbfb0aa0f292b29f2c53f20a1e37ddcd3f -ae139cf1b9773fcc5f9ba2d55f77b1db1bcf6d55da09ad6ddcffd8f2431810eb59c6b6450c5a586274da856c10a06889 -8eead75951a2db5ecb0bdd965bebf38a87bbcd3923179aa34569085c0741539599a4fa354ec240ef6eda3dbe086507f8 -87dec9c32c4c432e2154c56a09d8799b3411ab85755745e16db16b5bfb9bebbf24fcb5c5abb39e5592ed45ca2ea1876b -8612aa7aa27d5f2ba0c19fa4cec9a2430c34f8bcd45f12edd782c288a1232995046df0285c92e471570e563d05de08de -b76728f34b64c11cc253a80f2e8eeead6bc6767284aa8a9055e04dbec5a0cd5e4941d625ebf9d9413d91712c57ca154f -885760ad275549df56a2d4dd7df55cd63467f9ee81dad44542324571641040f5d2374959a1aa9e5a2908ae71c7d80c2d -afe0ae20deacf08a337f439c667dcfce893d6dd889725faa8008ca3290f2fe4865ee2f74aba8f84424d6e7ce18ba3de4 -98a206aa52eebda387c026bdbd13b688a6dfaca9268c1940f6ac59965a7bc0eaa1018985ee66b4b69aa199814397ab76 -8d189b3c0e21d8869d966d76bbc0b039bcbf7d0969a9adaa400d213c3a1d25795c4381cbc3a84232a46ecb92bb5f6c86 -b5c3569590b612b978be1ec0d57a4dd136c12bf8508be7e4afe797bf5463480cbfefc7cac09dfb7f141c97f3096956ac -9067cd2621a2eca18bf109f1f5bd9d0d1e6d298d95f20e6bfb6a532aa664dee6e7b035dc5a91a2d725e8b53ae047b2be -8b8bd2a4fe2fc8db26cc8acf7b4baef6b57cde5663164655ede0096dfc4a82f74e35a4ec7acd23c8de139a7d640ff595 -818fd67c924aec500a6a3ef77f03fdff6bcd4d954fec7c047dfc0edca628dba603e42ca417bd58ad3c5e00706861a0d5 -84d1ec1bf9656e67fc5e3741b59e2da3124fd23bb90e55404d2c4644d4bc8b1b07da5672945861bd1ebd64a81bf94553 -a1f9009b2256b170c41cc21fec6c9c36dfbef1aa865051c53f95e90faf65d0bcc03419596c0b7ed6137c7c6bce826212 -a2938e2e6f96775ce1477a4af966b5cee118344ed0cfe1ed52b0e7f8c5cee32d7182855bc5108102bbc20fc44bf15db2 -a16a523356c46ab30dfc5746250c6c31328987ac06e8414d3a85ea44d09c7b8a8b1a02978b92aca0d5e40666202e258c -a4b5999ee0b33dc847020fd737dd9ea3d8251d37e6f2c3c50bc6faf14781de90749652334e57cae4bbd2a666fae23ace -8d46ae15ca8e3e85e0eed90ef311f7b043a29a244187bdbe561ea211a958a3c62e9c43a9f39e2cc2997c5e9c1cc75d1c -809becd2ed50a407f1249dc15e8dec7975c8fd4320ab18003d882e7d842bd654a6c3a516e30734b27ea3119004cc4798 -82e1c72c911874bb06e089d233bb628840087e556b9f171e5bc106e1d419b9f33973e7946c0d324816777265e81e7727 -a1ded762dfe72cf06346ce1b244de5b3051d4286380ac0b25703f11c51e809021f3b5ddbb5e2bc50d70b6202274f62de -b0f756a56322bce6f4427781dd0161657a6c09d31206199401e2c9db4d901a6ea8882fcbb447c500690269a82fa238b1 -b31c7b7bc410d9941243b1853ac1cdaddbe512221fd8d8ce21bc827c845a0aa679a37ac002c6698908316e4646d7a726 -a39d85cb0273c1bf5038a93c576de04016de8041edff99a75a5956357a3076ce466478e5b4eaea519e541aa0ace644f1 -81c3c61075652e356478b92ed8d62cf90b35626593ab5b6bd16e0f27374c6efd69fd50831955712e60937761c7261f50 -93abf5fa683e9472ca60cd77619466c8b762215814855e98b1f08daa333c6a40c292eca139f2b37e7e422f15a9828f5c -b54fac1cd9a45070f7d5ad5a89047f83c059497bb110e5bb81212b3f7908036b80112f44102e49c2f39e367cf965a260 -83a1cd2049b70145761c2ac927007a88551e63ad43ac54b8f5cbc4ad85ac8cae01748bed5e5b532ffd941dbccdb10f21 -b2fbab6865b4ca51ef0ff696c7a3e7a77177c087254563a3955a5f8d015b66dc1f26a8fe09639fcbc3661bfab1ca1ac1 -97356cbe18a7240552a9b64be64f52551b4aa16e37028d899196fa1cf24add08a88321073221c72bfee2a41f5a03115b -b81a98aac5b149793da7feaf62c8629f5672094f050207c747727ddacd3c41d8a9df7511d65b027b156c033f329f1973 -846bb6b03e89a33e0381edfe6a3ec4ab690c9a64b3a757435336f6ea41022201417552589158e529b475ded86b647c15 -9834ac83008a9f74307d7481ba8f1f932f898331e7c678d65b12d360796daad495ec4e0c795f40730948592055899402 -8da290ccf3e6f47779795ee48205a1b60ffd8244dcdfcf188400af74e0e40e424c6a002dd8c8ee0aa51c6458a960259b -a673a522e817d997f5899ae2c771de59cded39da1468e3657014ed54b088683b08fe50fe06e3cf5730ed35766d73fd28 -8f54c627bf991b6099f498c3248e442e83332384b6ebaec682d8e6ce8020e5f4219f88e5238dea1f495805e131499ed8 -8b9b91fde73288973fa818d7e4093e8b9a4ab8f2091c8a2e970995bd6ff4f1262439e0baeb6554a93e9ea2771beeb358 -a880c5aab17bdbc05df6512d528ff5c92eb9878dccdf53bb703463a4e6e84f26802b0bb8ae5ced0bb72ebcaa2d446002 -97137ccba969d9169993bc47f3a45a9d1efb33fd6d58161ccc4a3579abc7e33c970ef3dddafce5e10a0d84494cc5f948 -870179510e908dffcff2ff7a88a926a13a9e174b0d1dd147f25190fc33f3ae90d056d6eac92c2aab90f9d3b9a1bdc824 -8afafbcb08ad1df0fa9b9ba9884d674e065bf9483ab243f6523b98d6750c4679640bebe281e9397487e003e63c8a628c -88473f7d90ecd86829b85cb3366c3a7059cd6aef0325f4cf9d6cd94caeffa468a8a696b7f93bf4e522920a98b2a10529 -a56b3fbec7d0c1599f6a78baba8131756961a359b158b08ec9c9af398fa872132759ccee200cf0720f41d42dddc5567c -8f27162a599e91daa46cdb86a1b8fb37f60511af76f0bc6bb90a92ae01874b010bf837fb2086cae501353727d8976876 -93e0a60bb8a8cc356c081bba6ec9f9094467fae81ee73661956329d59e6df76ffe8344c7ae09f62ace55de416c7cda9c -a6c5b1db89f8515f8f7f729989a15a4556b7e7b83f1cecaf89b9cffe6f9c1dd853fd1761d40a0754fa177aa299a12587 -acc19a840c6df971bac15142d99f366303f2d29635e38fc41f2e3fa92a77ce8bae92337f917af007182aba3ca70cf294 -98fa25a57220facd6824eeaca320c65e3b99fd5091a509a6387993d76af39f6a32b1347cd3b8d4701d4f1af8420e7eec -a0b5c70e057701fc16a465b47b5581066ebee6336abb1629dc4a57a7b202583081dbddb5e687fdd0048d5cba317eb7a7 -8be0fbc3853b94f7cafa728f919e557000e33a704481207f0ec92ced676cf2844b20e87fc073050c52680bd5ee6c5903 -ae702a6c5700fe0ba7b8e46002bfddef90f045e4e027058cef31663bf2cf9909a53ca0f747afe0d878529f1f25cdfda1 -95d505b2f1fbe253fcec152b94bcfa9b1d409ce2873ceb711d71f4293b4ab52cf836949e73bff2f72efd14021d9e5467 -a7a1f3a425ffbf8d32a9a3917b76c4173b2dd19acf9e1aefc50865a91fd50caf25f82ca15a9f3ce158eb6074b43be754 -91ccef5392d08d4ef660bc91dbf929192ce6625329f8756b498953daa9f3ba253410f30b51bb4c96bc5a9446fdf2b296 -8573696c19a40d47b0cc92db3e04c85d7f4b87a7843bc8ed5e626ca693bccd642f3b99c11de34afbc8609ffd305c7d06 -a2c18941d77b7bef39a55129464a642363ae28eaaf34959ed4272c9f2db38e8434cbf2f2d24ac5a401e2adab889641b1 -8cfc4256aee21b83c25405a86d6be842296be60281a2bc6bb9bb83beb963233b9b594d6f119c41dff79f292fe60bd4c1 -9923ce6b8831cab9f7cf2fefed7ec383f5fc1d8c46d49c6da6ad43f82fbe6a42e37f3d334b12f8bb1afb95b566b8952c -88ea98718d9f795a8656020e8729096af0ff002b19fdee414e8abbe918d7b60561e3cdb68914fc6369721934dcbb5036 -86940ad730aa07d6cb8924d65513dbce1543f10bcb70915dead0d9f13c0db172fe5b8095d0a5a434c4effb892a9b8722 -939ef48e278334fc53a0b7225332641bf71bc8498b2896614e27864246d1f317ace6e2f40e2c498adec5d7b1c180e269 -9409d1a4cb5c52df40eaa46e97c0790cf1486ea6a076e6918a7ed173532f937fff7114371cbaac2d020f509d35e51ab6 -818145c4cf06027a64729013f0648741e31a6006c3521830b6a31f8240aa60d5469354939af50023893786be249ced86 -95a0e5f0fead474f24f8e3e340caaa294cf6847927a0591e2ecb671078a62f7af6d7675dc1ad7623064eea6e3bfbc57a -a16b1cd85c9bfc75e6c871b09d752efcbee0ded772c9759da2b350eb80a17b35f6b91322f38fda65c8bc61c753543494 -a16ce416b46dfd0ebe92147c06eccc9bfc3b5ab741407fefd95ebd2168b9aea4a953e8d0a54436bb8f80c2b44ae5c6f6 -9494a4f8bbe0917a36e8ad79c701b13c7f0c9c47f012835e05277d92eb7030f8fe1dd7ea246c2db0a230e120aa338b44 -80db6fef17211a2be9909b6d419446059242130ed24805ccd3e70827a826dd6ad5eb09bca509ab16f62f6d4a84a900ff -927ce984e665204e5959c70aaee03138f3e381bec132710b511c3fe9604424e0a736eca296356589cdfe5ab08b092289 -a07547ba349510d74b4e69c8ca2b6919f11e4f61644bb6b0ace151263ebf9ad1a2240b7d8b304afb160bc7d3ca322ebe -aa2fac784487749fde49ebee555491482da0a085875f37f4ec04209a75480652d0049c6e1398e3767573c51899168cd4 -aaa9a4e638eb96ed7aa6fd634e425ed9aedad74dc5afce3d51d6d6f7d25dc76b60f1c5546708570b25c4333ac91fafec -8112c9648d68ccfb4bee6282d4db075d9a7ed39e3f345223be56679dfb062f2e8f6386bddf50db5c4cd1f9131e3515fa -8461924caba220050d35853a9879017ab501831536c4544c6c2830e39f6c54256d08c0ea2eebd10ab38719d224e2b704 -8574767231de600e150899094c55c629c050cb6681221e4b64d8d30dee1e40da5099168cadbaddedda39333e9e02a222 -860fb72054c886af7b55cfa90b229d6064a0953f3157b4a0c2d73123083fe5f47268ccd015f626e8326d5327454c8fee -ab7b5696eee1b6ad6d42dccbfef004d0897148e4a38a9e9bf46d4ad1d0003176f831d1de7403b374acdbded0265d84cb -9128301b1f5994843f4220bcae4df86c29e62bc30bda18f31d3fc776a8d8cce06bb74aa6afcb0cab16cecccbb8991974 -903569cb5bcd237ce4766e0b6509fe6e332609feec5526bc149d30018a851eb666a51b873d80a642644cd54875d245a6 -89748c9ab4480a747b5af86c7d5ae2980c303e5bcad925fd3526067d3dbfa1f02d917e9d9b3e6e254b49e74863a38bc9 -b87839691b4277ff4fa95eabd4d9caf4425be9c94c2a4e4795e263df8f6eddaddd476fcf52facf8548294a6ea4a4a179 -9247ac277d338b67c355e140bd41547fe35867d4fc088403319f88ee9bfbdbd80916d7f07e0cd0e9c26da535fef84b9b -80557badc9f4520d91e36ef90ddcd626b3c41d019e0a2c02ba7cd3ece2d7b3621d732fec753035118e34af60e871990c -8a3054d7f0a2ec33df3cf7c180f77480e775694cae4bff1ebd802a65efe68aa010299a8018c4782311a7f18347f2a77b -ae6f26bfda86ff48ef213a467fbb27443c4fd7eef5e30a0f1891cc7b1ae90f287eb1df80b76c2addb459515d7eedfbf2 -b85deb5270f542e32cd9c090f48fca448ef4c259a09ba4dcdfec7c200171ce6b3ddc675a3dd655261b8dde7d2537cbef -8df5c814840c03f3a71eff016787c76f42a63cf2cdc18ec21462b441c9741cd53a6f80a4b14a09f95de33b8faef55bdd -b3f175f611093e70ce597e1eaae6256b5e11b178ba8c66f870c5fa8af22f493a85497fef146070df5a9ccc971fe31a1c -862451a08072809673803f2848e252286b226f86a5ba3a1f9ef04c461e64873ecae57fce1d93ab4e4e0dfdc94e70d2ca -ab9a55d848811b02e106974a7a366c7d713d75b728d84bfcb4a2fb5b7e16534267f4fc662f9746ea1be8a74249f8ff9d -97e412fc1b368a4d5913051cd99bbfd631fb0dc29b83056264c54e1f34288f5c1fbcd6e7880b29ca9e579ad1b3473640 -b85d55af1635b1b1a3e0bc01e100ff7c8b79f6aa72738b6497071c6f16688b9e166c8c8714c4a49ad1983c6cb16d6d0b -ac3e606fbeb77b39840909abd387c92c546cc6fcc8cf2b5266e77bbf949ed19e697345eb7c7fa2cbb1e2d4dca1b1ff67 -b588ee4f12c49b828f0489baa7558d3ce81265fb750bd4177dbc88a368713ff56f1e0ccd0ffeedb31f91741653bcbebe -a334504ce0129de9be09beb53d7bf8bff47a4bd17a8ebeb710a273c3529d81072d24ee6bf04264e1740956a34115ad31 -86a8e199c565317be2450e125ac63e33824e1b17dd5faeddfd65e1718bd77d3ef91c435cb0517cb001ed96222c06dc14 -88e05c3f80b16347fc3845216d9a62e0a89a43a71e2267d6e4634fb46c1eb33191413faf8602c444fc859c0ffdf2ff2d -b8f01fd968f6a60a217ecad284d909e80e247996056e410ddc7d5d059ce788a19c5e7d243b376a29c3c439430774dc63 -81547be3560d01d50fccd10379dbb149790c4b6325ec095086b60a90ff01f6b6c15419c8b2c32f5d021eeb44b20d9139 -872bfb96cb9a01e7036777a63ebd314381e45247a08986ef3bee15c8bbf3f5ea9c30725fada91a811a5358284def43cd -abe550e6c3bd1e041c601bf07fe2829da3def8cf15fe208886631238df28281ddf75d43b373e515b2b97affc0ce89943 -a607fca817db0c565308146c873b58eaab8a953cec61df87d49301ce35b7adb8f4131996446e4788981a9a90201a6bbf -877b31675e61949d2d369150fd8f7a0d8501ecf73207058053ad277a3381dbf441881bd05b626dc8bb716a16ba4d5a98 -b421488968877ed03c16561ffec5545225f8aaeed8c92eadeea6b07400360fd69a36ebac6a1eedef02e2b069079e4a51 -b9439a8a448a7501fff2f89efd933a521fec06928201828791fbb91b21740277106b61da5ddd52d9bffd88f52b9ba9d5 -83ebe6b769fdbb1c6ec4d70b914034030540bdc31385cbed84ffbd81e6a588808ea0f4a5e0dc5f9f2b5354f4ed16bf74 -b65794fa247fc03509883c23de6634e0c436d8383d6be4366e9b4e075939601097b7c6176e751e7d5b6213a85474d1d9 -994d90e9139433802f349cda5297917875f76b4cd0ca4c4566f0c391ab3c60dfa32f201252ba70b0a0e1102b8ffa080e -b011d6163bd0b456b814d401c42af85b1629ef6e959e6138432a955bb6fef3df5db44573439be7a142be15335909fd1d -a3904d86f0b5410cbc639235674f9393b430779badfb13dd477f3edee86f9255e91072f57042106f723d9b839311b348 -a33cc02f2047016a70cc3ef1bab2eb3737494ff854233e839857f4e579ee672eaec5da672b69161196d58a41e8421924 -9852b94b9afdad7861981d771a6c0ae2ab13a84129c2e60fc50d2587e3c14cef2847992f6e4256c940be588c43219d7c -a8628e57ba20ff2150ba6e53ef2f30e411bd066a561797fb3c19ebae1e37ebfbf47eb5e40c9e23870cd1cc0ce64af5b4 -aac016a5a591c9886be4ef0eebb75a987d37ed4b5b4e53142cfe38553d2c26fa73020504ab9e1f005f39d030fec79f24 -864466929e8cf3c02dafd742a0a8ffc676816eb8e78a69ef038f3f0aa9bbbe783efeec676ec688ce26739fc8d21ea15d -b9a475f1bdc6961b0a2cdfdcb8a2b079c6e94c7dde02a2cb3243920d3d7f3fa6a7547e1c67f4cf16807297f3f50c5c0a -8347fe25e2bb7c215fb067a5770c660bf45068fae224c6d30951d7a2187e1f9af04056a9b95f68c18859831801c01b13 -97cb8013e9908d38661cc9456862c38f392689dc8d2457b006682bd2353bcace38f52f71a93c8baf26b0ceb259f35622 -abdf92b8a44bf5cc75c92d7a30f025c2fa9c7e89e098227c38e19774d9dfa7563df065897514fcf7cf8a541c446f7c00 -afbfc533af295ef01acf44504c37453ee5ead2ab0913edf0b76f031a275de985611a20a31477e18ded9f77a6d2a3bf34 -a17d982ad311e07c2a916ae6aa6567251ca9f3c366edaa43f0d278a02830d5a6963d243944a3f40239c61eecfee29568 -b2328077836623baac0ce3a9eb178fb60f6f489c7fcdc76f34cfc18399f8ff0a85289c78c498f3fafe554f09b22166da -8c69eb1e6e9c31f934b999bd7bcb1c763a205c442631242b054d8a07917dbc11d7f29e619e42bd8d41359bf4655f5ccb -acedfb69850555308fb29ddac6029504f46deb0cd38f878f525c082630c027e08119639e4c71aad65848a1704cd18261 -8ef1506c0974884bbf52bcf1749f679c3d1e8e2dfbf7460ec9602ec5bba493bc56a276e9cad4f19ccb678a6482cb7d70 -a181d4a660193a4c52848d39d56d7aafcbd6e0cdde6b83ec1758fd5923d0185b0e1fedeb400e44c95a4adbb1cec0182a -8884286b6a0000e057c69b3f4782c8ddcf88e67229ae693a385bb70e8aa7ed54e3aea205dfef985b9d075f3ba434efa6 -90dbc43aba2d0d39a8e46f5112c405aac25a092ede5bb3e4d91fbbdb5d7011b8bc501fd4a2b3a3af668547064cf185d1 -a5e50ba4467cdec8889e52b9dfa2b2d3e8134aec120064a39440579e8738f3a6f88797a746f6371cb862f082f5f7f128 -9495c29711fb3cc4e2e3304ebdd27c2c04cf41b5d71aab98e1ba64d1ee937e6bf4291998997464f4befcfa31d3249655 -96d74b4750e5197c712e6191896a39b92e865ad1a15cde1847ce5ded06802dc150be388aa149194642763a4e44466db3 -98e13522b2ec70da640f3f3050102b18e8a8cee6711db74c8d20ba4e70a74193f6b605fd3d079ef8aa415347c0b5d26d -8361e51bde71a47e66748b3a62fa7f18a114558372f57aa5362c9f8564c80f31d416a4efebfdf98dfa50acaa6c10a8f5 -a569e8619e8cdfe4d42475b379d7adb3ead5cc9f80c5cd0fa173f07210c7bd15768c2922c5a0a7b750d8342764393284 -898bea20c715ab6c2fef89c15c27e55fc8973d1ac370b49ae856ba4a1d5dbf2d71439729b89545e708773c2423f8d9e8 -981bbbea66e1d0d4bd6e5be0f443ed2358819e4d4c82ddfd57f1ff618966ffe5dd27d86223bb90a010e49d5b6ddf546c -8beb2179a0ea1549d132f8b45d69e3d47d361a14b79880f504f53d5241884a205c7cebc7942b4e3e9d3dbc255cd5746a -a1f5e71808a7bc2d25704853a1fc18963a63d12adc3648f56d1d3c6b872bbd1d4a35ca83bd00862eedd80031cace3920 -a23e7c9ab4be5aa98ae409b09adb8e60084049e3487eb5c50e4194fc22bbbab06587593c032a9ae6535531ed4496ee4e -8c0a4ca74eed6582ba7a438c2be72e7037799110504158205d69ea24c1a85a9ccf1d11e1224789c29f3b122b19c2b25b -aba8d9fd2c0a47ada83cf635e86922fe91b79f5f86898589b436a141e4239c29efd8cbe8f85eaa9dd7ffccb00ac777cd -b6bc6b7eaf7606f95c16cbd1d82eeffc7e314412e8f77cfa353d7a713a6b4067be698f2be55f4c9dfb4f485431dcf04e -827e48dd9bf2a549890f83340b4b95ee62be157b402eecb95a9fdf7c02235257907762f1ffd4e86ef871bfb334671cbf -8c1e1566d315571bf4323f61f22b71f1332022a7688eddfad3780b51a91fe764d1039961c0a7ffd8e88a960dc4f491b8 -aee5d2e6bdc2d01778bcbe86dbcc19cdee45aa30887c3079e1f4c697ffa9b7cc7ca58716d953a5aaa186865fd0249d15 -820b28b56b9f2bc60ab47db8221952da5a08f52cd475ea1a47f4030bf48964a7edc0a71beea80ee13b480cc136d10d03 -819935fb10bd153010807e5fed0ff4333bab231ffc0e47af00279c882a0f8de25ce49076fc8057994cf803d623024006 -b65d45c0a04ea48c78233422bc755c49204fe42d6695be74e68e64626032cbe5743bff31548d9e6577b5e7a25b3c19e7 -98d9abec65b4d8c0ea421fcfe913c262dfd26b89a9de330d6836064596a9397c671a2b18c00faf1b1719bf2f51e65ced -835934a445aae9683b0c23aa8f782038f7505002118b63908fb0e55f7123cf9ef224b85d4c2388e80f67d783d04ef70a -a2ff9e7d1b04d0f5a0c526b34b357b2051295d4ad28e6e06a8fb24539d7d83b4ba775b4ff5bd7d2b887d240b9952475b -9780eaaa0da81f53180982dfe751ae7b455e978aee65390d5574952f2d53f7bb82707481abfb3439c6489156c60de114 -942a658ec982e1eb1efd9927d5b60dfdf3ff41ebf976e4ac1b5bfc4a51cc9c0a90e70efc3054f9e4d8013244b963066c -96ffdcd0bb052d69fe949927c6f14332d6649c6773e2b8254ba8500849c30c65428949d31a57efb3765f31d392425342 -b6dc51899a253c9e76de0704a32ae36c202da9168a896c12ddc9ed726ff3657f3e6aa1662ae1abd214f728f48a923215 -a35ed1514ab933932a584c4e1d9aac44ed03ea500c49dab3e82bf48edb905fbbbf895f2a6b295cc2607aa564f37b39e8 -a4f92c3a5d57c5a7994c9bf61c4831fb51cfcf5575405d22fbf1881033f19df1d03f6db0d5317cb1a3a2bad04e61750a -a790f6c3537dd32aaf6b64d96edd48ebb3c90cfecaf367f6f37d0ced7bada67f71672141d14114278ccc61b58654cc33 -a5f2861e199685c462e110c7623bae3c732aba61b1d61f580ba84af75b06df4cee6e2eff23902d8e20e1bc204cdb0e73 -979a500bb6842c9b10864946ab0b004006164141c27d6d7b03cf497fe22e957bd371f8988f8f89c0fe0a3c163a30092e -ac95f892ae422aa8993a3c7ebd23051253885ce0a775e7f5c90620782cf592518032696524900525c0d299818717e4e6 -8a60cc603343115aa6f700f6e12808a4cb4aa2af0bb9db502c032de7d1a01dc5c578b3fdf6cd4106153ed9b5eed1fa3e -977b6fef14c43041ecc9d77a2165fee9e56cf77cfd232b2662026127e734bb1340a1b9206077d5f81c974489a185e98e -9072d0de45572bcb528d1eb5a0c3ab695a713931033d8ca9e3ebde0e80ffbf1859e8b2022631b502b5a9b93b8ec189b0 -a0a022f5bf5f7d4312b10257159f3ab27484105432f4a152f85592bffdec1a3c474a99fa2ebc1a6952f4ba9967492e21 -b377d9dc0a36b2e23903cc308b09d50efb60f14f1122baebcbe1129d6fd20e4ca27bde74ae0553bede19cbd9866d6d02 -a838fc080b91b298b74bedbdfe123078ca2ff7fd7f27b2e4ddd61eff515a301b406e115713936ace6f75bdbdc5f47c9f -b05bea29aed5ef8ff72f6305bf13b7511b6025ef8b0a39fd052e24a8d7fc08d4571070d5160d100f9f62663131bb8079 -a9c7326c04f882fe353399c85146434712ad3e22f26cb3e583a9161a7b1dc799f77be4e8c7519dd267f5bf32831b7314 -88acbe4dbced1a02168343a0f7e5897b7af4abcda4281ad68a62b07eedfc36d32b99edd159013db3bd7aab80793ef5e7 -a12a8e9ca2e8dfef9a53e76489723eed7fd2a444803491eb8217f093d61f5fc146834070a77b9a014dbbdbe393c5913f -b409967600d99d3b510f703c2cd95ecfe981b310bc118142e3d54d2b274f11be5fe99998e92d1d848e53076dfe015fa6 -a3159d40c864eb0690c58a0a525293c99dedd8f8a283f46de1c235338b8a8d2fb8c88e1246ec18446b27e4aacfc1b915 -87f0c0b383593840c8ddc4716144005b8c0ea91ac6e43dbad5b14af92f19724615dde1a26c513e8e9d85d054546e4511 -98c1c3e3f3669c8eafc88a3d9a425b6ceafc8c5e7202014c1b58d07bca9aa1a37926909bc6c06baa63b00bfbc466bce7 -a8676ae8b28bde3d7dcdd68baf18de0a1b6924524d369e9831472453a96fdeb6d181f964cb7d0f630ecb572718694f57 -808a96dcad4b27774f505f4ef18e2ade99e87bf4ed566aa6eba8dfde7a19ed1a528d4e58fe26e5f0e223ac1376804e42 -9289ac76c1c425818a5de33f87fd8ce57f9c6e86f978ba4ee389ad13f8f0b3334f2941a5442e952fd7e5efae6a562d1a -a189e8a8399ec5dfa6cd6d90e4bc1b8dd0e53f0e30e6892141de08b5930906101c6dbe5f4869978e2eb54418187a926a -a7f454c20ba8b25362352f72c32ce0efa7115430f927ccf3e2c4f884b2dd4184b8c01d9dba9055446439117e2cc4dca9 -96d0558e58cf42f086562a9fadd5ebf799b2efc8bbbbf1c8f1eba0c4f9526d5a81a55fb6ee93b4538649fa5a0f4a80e2 -845e05c5b60390cfafb38dc086d0d105f8235e2e23bf3915e41aef6656398c018ec65ad355f9a973add083a7cf801dc6 -a4ee2f30376eaff528151584d565caa8b98ea03b3caa95a34379583d857d863e66130061e87f6b07a6be68bef4f50997 -b372e9985fc296ad8fcd42926a7f41cf46a94a0ea5a12475687c059fddf6b9d902b1d04320fdb596bef8e7f3b1fa34b4 -a603220b182a6ab95bbc244cc897c2c16b3de965ad7aef75e6b78eda578131642afb767c88bdf70b67d6328a06f16e1b -a7acae7d6a024859bdc7b439e4a898936a9e5dcbe379c620241a53ae6871e77f9bd89ae381aea56bcca6c1ada6339a5b -b67df929d8061c18a89b6f186b1861f97e6bbc46a121ecb71cbac71f54d4e246c473be1ef9417cdfe83f6dada4d5e38e -8066a3e22b3e23a3387b1a02a14d0e8c44a492734f2e314a352ae74ca9369d641dc5536462055557238a0e807bbdb382 -990bedc385cb5f3e9197927bd3d0c35a9dd650384885f8fb1bea22ccd96f7b891b18979e86069245c16fbfb62ce40d38 -a49bb8bed9876778dde4c93ce81239fbf706bbc123952f4ab72b5847c78b442f1a55e68924348124f3d79e798976993d -8a5ff2ce4dad2dbffba4fa8e664dddebd3c11519d8751347f1e9daa17bb667a6770f9f37b3f4169821ae36c1f5f5ff14 -b7004f7d467a0c74e3bbbab5725bca7b661e8bafe417655bf6a5965c7d60bdb93a1c52f0f0291ddab2e9ed6b013f3ef9 -8e78b2d17f787904438d10f8fd5f687d39dc6df6592aeca699c3dcb1ea644e6daf36f5f30964f004a4d5da3eda9d3c73 -883d3b89e87658ef6df8bcc8778b0aed1214ea14a7e8f85a0a40cf1fda4fa5b27a07e64d1b1f25012f4134d582e2225e -8ad583ea75f2fe95a75eeb091322fd11fd89316bd02b8461050c8799d5126e6445bef3c87cf1ee13325db8bb15aeea5f -a0ff1573983a10ddfe1706c43cc4723486c4f1d24200552ceb1849251d5fb65f542b9b967bbe9bc419f9ed5ee1715e53 -8befca726ad347d311ed180a3092f690b2e0cfd79be5f70cecb0aa30ff9f93a07d757f913deb79e5b966dec34a296729 -a6189acea271dabcc7072d4d6395e41b5f543065d676541658d97aaa113f19ba309f332c850e373616b712bd8067278a -b3e026881ad00f3f8fd3da96174554e2c673851e33aaef0f7adb886ff9c1cbadc44ab31a46c4c1e5f749a5e5cbfdafef -b98a7d424e6b25d19b20f2c79e3ccec111e94e2bd8db8e57c23607c46f12aa7d5812cb4c049a7e033f6de2b20aa2b650 -a4fce7c441b1d083933174aff776216efb0ac8dac9696b4a31a27d49c466c4fc866210375068f8e36b0f69ca00e97d85 -93a3d59479b99ac7eba650a55171af2e3b353a36bef91cf1813d3015484f22913c86cd32b7839443ad60c893016632ec -980da3babbdb03c06340dc8f2e0dcd48ab3a8a4979764981f5ed49839e22aa4b20525c7147b64f79b70cd12f832b5e12 -b6a7fc9d85ffa892436a7538f9b6c5ad5735c3d5b0f4599687646247d25dce8c80dae4c16126df8f7e17712ada1227da -b12d76b6a3048692e8c898e1cbd7cc67b772f46fb225a4553ab9d2fd6ca13ad5f43e7ba460597ee7d0a7ecf6a547fa91 -91395a8bee9932a7c254d903a815eb30cac0b13d391d2c7e3898c0c6fa1817d6f7a3c28293d248386ab4f7b48ac25e70 -a70d287fad703fb90864b688c6c5ad34bb8c6c1bec6b5565299a291495fa07028974a89013e132d6a4fd06a2d353498a -9142d6d97f792be9684f51933498410e1dcfb14814ef7c92650cc92a5d3906050904edc097d0d6985403ea6811c91c5f -8f4c7408c0eb12df8c06430706bb6b67a990049e2956adb9b4db7302657f6ed98ec21478cff5ec423bdf4c05286333d1 -a5dfa92ae114819505d86183e72d9f3f59335e407c589c0e9e782ce7cb7d80b267dee3a4eb03c60b1dbaff0979511f85 -8c2efc9f16ef0b88ea2d7c22a54e28f2ea2e7bbc96ec60f02b46ee2c3e27afda5379dd75487e3c8037fa724b16a3cfa5 -ab8d781d2a4763488987a230e7b829484d0fa8300d04449f215fca298fde403ad57fd21147ab6f579302a8fb75029bc5 -ac0d5a0ad0e19853051ffdd1f4f0dd0dedee2798d35ceebf167ae8c3bf3da500276bb2ca5f738a06b7d87defe43f2f01 -ab2db35e3af473ab171ad68c0fa7d5673a4b5ba3244c2f9aec739526753de72e62bc3a72629686644562d54ee6b1abe4 -885c0e19242394fd5b850aab741435be238f08ea1a19407c3931777f4f63962b8d45c38c09e9543dca54d424247a8470 -87b0e9f521a7bcf3025928763bf8baa1a677d292fde3f8ad9f42ca41eeee791652063d84e4ca75895ccb184b78d6f32d -ae4632856da447504f0528384594111cd61b96832984a7f37e328712c9b9ba3d1a6c3035d0c14af95b027c0531c659d8 -a8f7654b7700a7186904da484831c66125d59ccf4829ac0a7fdaf524790fca4a907263c4ea51de8993ad43be4b21d299 -973b17f1dd4636516a7d26c11cff0f12b20b6d6fa61dafcfed38af6aa5801b1af39f6da464bb060d102dd69ddd009b3b -b3883a95de9e815f7d2aab979276fdeb5c2b3eb3fdbba80e908e337d6204fc64a6ff578db6f75f862bc4c22ffe572ba0 -8e17059eb93dc9afbbeee6911abbecfcb10e1f7f873db189854e5387ca54ac8dba2f2d35c1254d6425bf00ce2ecf428b -a9bab7e9dfc44d4085ff15dc24093ada6e70ad8adc3ac3306d7138cc0b1ab4f2d5b1285070787e92288c4f080b949987 -b1874ef379f8552a2a75c7cf5350ea87f8f92c0e58cab4ce5e62fed9648e1a3975283de4bc45a38325448bb8c80d7f0a -922a4b13ec7900a96e85bd9ec1ae6740a53418b3980f58d5b9d89bf4a728cb9161dcfa9bdde85e4098e21076fe78e805 -80cac2d4c457fa381d277da285e99c8ae2d042b244c41ad1766960f56f2629ff291f36a8c875a3cc423ff6c7993c3e91 -b49ef553c1fc3b4f1edb83d7ef31b4a16a05d1430873a58e136992b4b57e46bbcffd45a7b65b60c2eb43e8c7d3904d74 -84a5de11e4aae5d874982531f7e5b55c0d3dec9c40bef1527c49a786949d9698e27c324dc65172c1a475bc3a40528185 -a4dcab5f41b25e5d3c2135074afab71df14d6a13f9367eb6b6d99f1f2b5394ffb5bff39dd019a1d7975e124f7f0309de -aab4de444f4a48f783c9d5f3ec5a12b7312e3ed381ef6e9abc50104a62d7b443df72267960719e87d9ba3bf854f69696 -863bf4f35a483b708c7550ae35e45e77a2d415341c07002855a9796f4bd52629bf44cf4d292b7286f7574ed504d05288 -93a7404436e9d610c442145c78902de1e2acd0f87224e5468ae8d7f21a6efd73f476c0c61483fa65eafc816ddce81d22 -b771d17923cbbbe5e158253399ba54348068cc75a2366d6a71cfdc1f90622f6b9a55cf689db547ff5261e2daeb2b9438 -835aa6b8eec584ce13659673954cac5ada0002e3f990dab3779bba9cbb8d1cde4f91b0fa3ae1f1e2e25f8198d2c1a304 -803d99fd0eb07e668a88fcc6b6bca2adcca28897728e69c038cd5f3f14e4f0a6f818fa6320ae0dc2ea0cd1077c410e2d -a727391adc4630eba3fc86a6a057306e1779e60f26abfff9d5f83d5e4d71596a13b13e7abcca8532bb42d328b8c7087c -a114b5acd9a6c6b24316356bbafca9b6f16c9eb9691accfd242ff744ac400d45ff7f1b5adc2d1a54c2161f0de4518576 -b4c7036bf1a505f114e9794ffce88d88852e0fc3ad5352107839ac9d4e0d017bb9935509b8ffd22bfcefce714c0482db -963134e8102f6dbc4f99a848a08fb661b95a163d8a1119749a6e8c4650bdd3f4bed6bf52951e8b7d6f84c75a2e030e2f -a54f4186b18e27b5f0d30d36ab59880994e9a67b2040e4222fe975a7e908ca7a7ec8b341718d5778daa86ce4b6fc540c -b0b1770bab4dcaa142acbbdd5e66f1d97f78ddbfde048584fdcb1bc7b755f53f2446f3154b52150f8fd07dbaca30ff74 -8e82bffce9911278f6903eac8e9a57208f53426749139fce2799a11513bd53ea3ef2f5c7a7d904a45b6420248b69101b -8f5caa32991798509c0251b3e75ff8dea3068ff5e77f03f66bda01f0b9846ca79a6e6161755492bdaab6dd81eb0f5a00 -aa1621a752391a810ffb0ece696ac7846e76106a9f54d9d1dd8cb8f9609a71c9eaf9c94efaa516dd3d3bd4414a272d68 -98e86d315537b3e89099a15c3bdd08116f23c1c330b9b2122311b23d35f6ed58e3c14e6704624955c44a5e118cdc0826 -a21ebb89eaad4ce05d422dfeb689021872871eb934b26860eb875c883f7193b65ee0ea444f8ceafbe7fd8092b11cd1bd -ab1034f602eb53ca863042855564b2971599d6790bca14a0893d940261e2f7b49327fd87f5adce0ec7a91d97093eca6e -a44bd180e143408d64c60d9f3af3516231da072bfffa6304e3675fbdcb5b286f14441dda980f1c64373348247f790df4 -91d69c45577d4d3032e8de4f362e3c6dd978fb6dc0df2993b6211f3d886bd33ab7fcd148bcb5d4d098d58f63a36835c0 -834bc318b0d95fa2f6d61ab11d97f47fa0cf74e1cc40a9dbf627371333d24db5615bd93b62928698600a38322bbfb937 -a8074f278d1720a908fe5d63a0d34f8d57ecabb8d510ee78e6b9aa20115ca25b26c59f7b780b69ba9a46ef14d7d191a8 -b5fffeee2f3afe4e25f041fd0847094c5142c8f1d8a525cbf763780486fa92f63aace52682c4dbfafe2f959ffdd4afec -a68d03d74107b6c429eb8d9aa00bee910121cfcf5a347e1ca4c127d19d419e7e46d34878338c9e458b24c612659c40ef -967aaef03f3b660c1688bc8142e1d5a22c7cb981a9152e6f7df4c21c3378490232667db6b092e147bc16b542ffcb0635 -a2f9ab09224cef0393832888a3d2ae8c1de7599b734b217f117306e4808782324a1b7b1e9dde290f7816efc5d2b8682c -8c713b63f99c08ce79e68734f38f0bc50b744899222d444de113ad5a3aab401b394355fbc3b0b0835b3db2d012212b9f -9153b792d8b441f86fd59cef546fd74015699a0f8c7822416684bdb2159f01dc0bfd1e1cd21a806284d36c3db9477b48 -ab06ae28eff3417b2670c98089842b835ff4fb19113060057fe27d80d8e2ea5e0090ba055ca44af38efbdede1e1b80b6 -a12fa3e8114fa8bc9b321a0dfd1089933b755b2586c878f4bdf2a00a0c0b29b0abb37e319a95205e2e3067fe0313eb9d -8b504ae8a69eb31a6529f10f105b121405c6a98660c642e0ead97fb5462f08058ad40a2a270422aaf8a92028498df5bb -872549f0b46900c3ed0e42e1ee9692251bfa91861b9b7d84393865ab3971e2260a85940844cb0bd9d3a5cdea2be336a7 -8177f100ffa41362ebff98ba9c9169d05fef682cb6b2d5c35af9167d9d3f15b6562dda7751260f26c387fb9b478bb8c9 -99e0a9302a64ade79ba5ce2cdc881a01f6fab428f8e669bc06d275fec9b3c14aa5af6416b7d2945dbbc497a21af7c2b7 -a191004f60f03469498c50cf3db556dc75952a1b5c8313faa6b88693c86e4d300ca029239f0cefb0419d74d3b80bea8d -86853e0c65bbb188d278f221173fc0f24c8f6a9e430dbb047ea11e421b5bb12f52625df972c76cfbd229b4651909834a -88a4b8026e9dba209f63281767b790d6a0a65afcce2fc22d7f6ed7154780ae07c64447517f421acfb5235e9a1b86250b -93b8ebd2632386a6ceda80e06134242838ab1341515aee6419d8d2d34eb927a59527eaa100f153fe1b2b115b39ae396f -b43ee68e5f82363ced0ccd98252f409f1975674e00956ae6dafaef87f5e02b83c36bdcb80093ae2a8a3bd725b3567dca -952063dff77655c477562181403cab520f66e8cc0fbda8c94c9d751870c1c87874e12dfacc36f1ac8a032d29d52000c6 -97581b37aa6df1205b01b431cdcd8c9ed53146851fdb4fbec0cdb55c171ba4be84158c84b6e400fb3dd1da6a3903ac44 -a90838133d778ed66ca110189e010e339bab6124e56d449c1432cf6045b7a46aed57c23ed77e4707680041b70621a966 -a5db677d15f8fd8c2d8a6fb8ceebac56f3d7e453e7ae748d5b54f257680d9b571929d08afd53cbc99f37b68144ee8ece -b163cbab3bca5e5f71ef63824a887778704312b0913c2760fb8a9e8991331cf4895385f1a0c4fe8d92a9eac561839f22 -9471f5635dbc8d1c1162ed51f84fe321db60976c014ced076cda83c90b9eee9413ea4c3924821e4c247cdc43212b61d9 -9897b29e1ad8ec9e0625b1ce5766638ee20631c8a3abb0bcfa8b87fd5763c15fcf6b46edaf794bf3bac29ada046e3a02 -9508f42caceec35dbe66855c05e8437e353bd49365d7271d6eb47fcfc4025b2ed5895b3ca107412a677243e6d37996ef -9009214c5716816c11fc558dc0d0975ca9e99ef706ec620bee7c5a0adf97c2d672bb6d81784d7f3470888b22e5f00102 -944f8f4df9cee411d86e344ab0d0fe95139300cbaed8bb06169b32f7fd8241936d0c22537cf5a05ebad50bd1eb826339 -b577e0281197b69275ea37bd669bdee7b9506fb081f41501a9c8296a21246ca6ec59c56b39a23d6c1d329e4bcc8009a6 -a6d2aa51c8f0bf345beffea2218a8a0c02d9cbd87804d5d254d802f02d717a87b376b3063cf5429fce6184ceb84e0f45 -aa381ecd4d49636a01610b1a437981dff765cd53d3525e8e54e80ff3c3f2430ae284debf7da67d5257143e6e95b0b9b4 -a5e6fd44c1df49aa9ead812d4a5398599e15dd01cb87fee04f812311bf5ae2fe19acec4fbd8b782d07f05bb6e3fe97c7 -8d3778a87602b01a112ee2922bd59f25ed5789b611decdc2206299ed732d9b8b5e064c51c8a6383be90077221c33fa2f -a6d7a37a72956273ecd47642e0dccff73d4658d713c33659db0e8022fe5c5cfae203dad043b576e654928b0e05aad7a1 -a9637e4acde677c390901331db4d518272d12fb7ba8ea008ff056b8207ca2e7535020c69ce1ff0facf36ab91c3f1ad82 -b390df8517c01af92ee7d3c00efad0b57a21e3f115d53463cfe2d696cc060705353661bfd0588ea1a28a6f682aaf102c -804786395fcae414a6d62bdd40cc701cfc8ef3b98cfa0276ad6ac6c5b6236496d9030d5763edf4c6abe229eb43c3d643 -937c3f83cf93c0f851e426af23227f8b88977217b167db7f50782cdd99a684209a7818dc34a7771aea3677e7569442f9 -93a1fdc055dcded7eaca555df493ec6520c84c49d1d2dcd8f66a10452e448b85df05244e5c3b083adbf20328c5d28b8c -b7248a7caf56010a880c66b1deda34febb1ed35e9e8b1b02dcefadd1be661b0f815739bea33e268204d1376c3f7705fe -8c2f1cf7282fdac6eddae749585a894b2a633b4813ceeb6f5d5010138cfe722bed578bc7821d2f91a1567fbff0872d62 -a0b3797287f446ee38aa1bcd13383ba083f1f4e0c1e534f278ead9c1365cc22a486a8fda556c151e9d2ef8838b69afcf -84ac38e8e7c74477d34000551dec47196ef90d93e8dd3362812352c026f10828b9673f06d3ac6719656409be049bcda7 -ac07e4ead9dbca9e94215a4a9907d0016fc12a791fe34b71b3f61bd253244b7b74f4799fa566a1ec3106937bd50dd3cb -a4a31552087fb463e972fdcba23f879875cc05d724ddab084c4946b44b41bc6fa83ebd469bc6acf5508437c180bb03de -94349881aab3575679be6134ec8a2f3f0fbb55c45c6edaf0ce482f6e19bb272c4023cb2a5578a4dc28d6f625c2b185b3 -a18ed8b7e0511519cfa1ed6150c34b35fb3754f08e727b8d9153ba170baf8711afe4a8358d461324b983706a447df248 -90cadbb6dacf3ade03ab585b46662be64f32aaead9fc7e3415722ce502e761cff2bb66209df2a06a8005ee90ec8245b8 -a8f734753b031df5f2540cec56d82da33e41e8311e9df661c865a1a6fa50b1b5965b605b578e59b7fb40e85ffe70ba15 -97a507a1d76e0293907f9b9d74f0f867461ea3911e70232bf903478504720b79e1c6cbe802e1ff3161931cad922e9faa -b00dae2339ad1af2635b0d6b90912a71908cec400ad87cb9515abd5b779c52584738e4e074bf5fcb4958c5a339d0442e -b6cb944484080216ebab8c41eaac3af9b994e9faa13f4f09b131d1b5bc110116cd15b0f51fc535f412a02d605ef922b2 -af1c3f7a1b5e8e427d1599d47f87c59912e8e0a336df1b4a26367fcb8f47bfb701af2b31ec4f1176d5dec7aaae013637 -b797e2c1b97ba59719113f5a72f00cf42d12b0b82f509f017fa0dd4fa3a540d584e69709a7b3d41f3d388a6d4791365f -a1fae3b1090518cc8712cfd06adcf54b8571e9cf1b31359f8e9216239b852c25b2a870009e259e10369fefd41cf08a09 -8810da66189d3b852bd3d34cb45f83332b8afb358df6db8fd9481867289bd5fad85d87270615cc96c95aab0626276008 -b270ac89215c5410e72dc0b28454a722a4e63dad803675a98f55f7c9fd964627040fb57e91c9e608f3f01e4e0d43b8ef -b662bc5b83aff81474289041878190d1ddf33d5c24de3c1d2dbf042b7218bab9b3d9abc9d33ffe128b550145ecf3eeeb -8bc2137ab0210d78442843d09d1b0c0e8282336b3540c84389b190647007fe92735879d9013f9642196415088f838a21 -a49a36aae11b2c55ae1771e9120f6154631de163edfd18ec3ac383402dab767a69d505c63a581218f426e0ac80aedf34 -ab9a926ee5037f0f560d921d419f45f8da37831f06dc807e4dbd5ef3f40ab1f87ade035caa0d7d56f42d0d11941139b0 -a251caef0c188d15431b29678117ea8069f63b876fa4c3809aad0ad01b42496d2834dddb14085fe66280bbcc974af68f -a7d733e30057bf9156419ab6eaa73cbd3797323fb3f97bbc7832f77de17a448a0b3fe19e60e2f7cf27a95bd85cc87746 -92a883acc48cd19e113aa6251848e68803f2fd5048b183f70c202659347d82114d0c2b04135699886110bf25c32b96fd -b3ab9dcb2b5102045ae492225b2d0f3adebadef82be8e7dd9c021e169d987e4e76332fa9c566696a189eb6f8a6382101 -955ab08b8aa4e510e940333c7a225dd03390bac40198f450aa47c6d760a62933af0463b54d89e8b98e1256dc80aabaa4 -9835e6d07d95dac2b06f17b77d5aa8bded9e98ea8bbf581c085de78f867311f42c36ed01e389adf7ef62e049131885d9 -ad92fc6fad987a760a5b2ec9e676af9b3606f9afa6de36a46b119b6b5898e2bee4ec08f453c8a712555ebef62b072815 -8998fd9861c2b82f6d550f0a033eacd6b336a5fc51dde60d6a5ad58aa2a6ca959bea5d3e9f0d8be3acd7ce594ede49bf -8881713d58d693876db346f8d727232f44f83c07c45eba878237b873e6a9c54df66fe1faef0d2678e847cf9d259fc732 -8510cf978240de717de4cf36b6d27a207c2dd516661f6ca35cef866f9aba31ae72937bb20466087090a2426d1ecea2ac -90f21365d17f291db128cd3e8e3c6e46ac5aef1c8b3e2d9f9ea0127ad28c5b21920a0e1be5215dc0a8643518a4aa3ba0 -978a3c998f1fade2dc5a000e85ad274b15aa849a1e406fa008bcf2eb283f3825dc142f9ef0efc61064807ec22c1cf6be -aec7a21bc3e067d6109a023b02d60dd73592af2f1e261a90da751de402418c993072075ca1bef421baef1dbc4e3c0aa5 -b63ddaa6f973b59498304de82b43b32167298e1d425fc016123951a7c87fc3aa7f6d8cb18023c955977e1aed191262fa -8cef35c8d0a93c7c56353a16f8aeb9fa93e1e6e74856d49c14220b918fd2d585724fdcb272d5e3611fcc97e46286707c -8fcd05938df6a1fc4402e0e216f6533449dab276d629e5e88a8854ded29e32c6638e4dfb3488419bd593437b8de0db85 -906b28f5a067015cfac412d97182b7a3e04787962a599a2dbf30254dcd794932be0549551aab9dbc335d95731634d025 -b583cf76e80f3c2142ef5a3a4d1800d36689aae4fd80a2e13c41370e55f1d1b4e1716db8b04eddcdd3b1fe5ab64b6c3a -8c08c57ef5ff82bd9b8791005b2009f0373861b62327523e5f70e8cb3dad639b3e2f5c21d35ae44157daac9d57d44059 -996a69ab504491e6219d9a495d9a6a07ebf86e86d9f9827e4811434a0df8a544d1027584d8f1142bc5edba2b324551be -b61e34a3365eb80747532ee32cc3c73ec85b4ab65340b53735d8563f616b7914bd152a3ef071272b20efaa83859fcca7 -a769a16a3975d9840a678be73a994dcb76bf0b9283f83e2679d4ce193199539e7afa2fdb6769fc44b5e8eacb04f570f1 -ae23ae27b659ffbe723e074d4777ea9c7c54ad4ab7d7fd34e121ec791932254b64265f178c6a1b2fc5b7bbf128f0c773 -828fd051327553ebae4de830fdd18d0ba64b023c35208b45cd920d68ed7e757f96e2fc6b6024393efb72c69d125365f1 -8688596a2b212b215647b6aa4c15b5e2d9c9cbd3ae6e2464fd264b48639b8c2cc8accb27b85e76faf9edad62bdaa76dc -8f576780e7e081e84b3cddf4e2290945993958d1267a53ca9ef0a7d6e356c3ff4db9e4cccfb799f7b6d53756c219b1ef -a40e0db022e392ae771c68d5119d8c4bd9c2eb3b738d6ff0c1db841fa44c318bf4644cedcfedd8573fae19963673b81d -9962e3a3cbf0b00d031f0e1bedb81ad58a6b16238ad3b99e5632cd38db9d913387ae03b07acdd9c4045d64b82fe2ea70 -8158cb612eeb14da499d2d42ec998650431a370a04cdc8e1df4872dce37375ac97629fa035f4ab38ce0b3f15c2d0d5d2 -92eb0ad4c8013b23bad28e12a74db1b98c2ede74395df0562826c37860459f1aa4ff6457079fab9e40cfaf0dced32e94 -af22899eddf1f274c840a6de80903fc5a550a3b958a68c3f7886f1a4154aab7d8e3c1bb794485f3740a4a269cd2df887 -9905e361f9fe64994ff36271b7d28672432e988bde670b3da0a483bda331958eb9edd5f57dc556f403500257b1784dab -a8c4d74de26aa8ddd6d91296c3848bb75e0f68327e5d203f2affb2427ccc3f9cd1b8e430259bdae71cfb5119c37337b7 -8014a82c827ba6462dd158978a0cba89a1d0c882f109fd8e852db69f4ec1c8f515eddf2030d126315cf5368a6e0317ff -a0721703b945acc72533663d5a3516588c87dbeabb2b00523d2e627f59d4bb6ce4f135f7422328145cac01403a9baf8c -907d0ed2cf6985934d436b6515108af2ffb25d3da9ed7cfd19d096cb1c7ad5b2234f12796f10ef24b4c27cff59f5c72a -935673b0336c8a5cd27e58452bf2e525b5869a82dfb0f0ec2c570a2a151a643975bfe8e15ec4337fdc6ca70017ba5d11 -b70b2547422c0191fa4d71a6a73075591cec5dcb6f672110a1fb19c5667e96a757a4a0b43021139d662a64f20791bb71 -a73b1a6768c05b4a56801f54f9b6226e13175111de0828aec8f34bd5d4cf5113e8d9d81a0f1c057b5593d1d358b2f97c -87a06ff094bbe1926a7663cad0a00d28f8072149adba2de9935d9f42cfea5e9f316467f23d190b7fd07b37c0517f3797 -b7a238257f702f2fd652fa81b20d0090359c3c176d5c0a630f5455c8fc458051ba21a49a2ee2f05e5c8555343b596890 -b47d5d9ec737ebd4a5cee5079b5497ede2219386408cf786767f618729901f1fd4d9f82c0245370d379148c5ee7a1ad9 -8874de66f703d7dfa133bc521cd2d8aad9ef2b178a172c375a24ff75dc419013f9be46dc38a715217b660217be3cf114 -ab77e93cf0c12c64c1bc489643b5ca23d6e81a15d7bb962d9df0bfb050115d304dd33f98cebb6c1a4ef05d2cf9e09c34 -a6a4fe5e0b4f0bc8d6192c1c52faf178a248ba1228a9f8df7b20c8caa3fcbff81b7e32b2edbf98c224879c0b18a298a1 -aef2865260b507624dc8e12aff7bc8b46e0e7471df39c2b6892833838c18e7a64e57aeede556ba42225ea0b20c706acb -af0c96673b290197e9fd493de9da77d08ef153ca4c77f3e33f3ae6f6e0a9e1da4f58726962a907d7bc09e65c2c4798ba -8e7323326dd8079c6ff351a94b902778a9b02601fc09377789cf8aff7c91d957de3a6d8a4225173053cc0b75a1a4c270 -b08e8d36a3ad46dbfdfe56c7ba2eb777d75ebb886c08a00b364f0433dc1dbf34d252e54653abb626cd40e15d599f0608 -b19c07923e56238c358032fee76aeb0cc37c4e02ff65df26e609d131f8d7592c161b52f222a758b6b4baf4b0698edf9f -980d1c0f8bf4fc2da9953ae5fb5a3a00b4ecfe8676ca305ab6972883de197b6bddb810053d19ce99c0e2d5914f5ac0fd -aff45b58109672fa091458e819a659d8b2fa0a7844e707b78f945b7bb093410ae6e67f2f2f0f1a17f78957ff6317c5f5 -8a6dd21166bc224894ac5100ac8d7f77f66880b3532c0df9b35077fbfc938c730d7c36ce076d68bee60eb4fe8ae91cbd -85fd4511d61ea0f78006b5d4c6cd8268f55eb7fea6709d2e85b14e5a03b9cea875eeec0c1ce238ac15a6c9393842f281 -a70b5ae308a5ed6253306250aa39dd6077748e4a18ba9b554d7503bd4ae493bad48606100c71e856be2c5420701dffed -a515595eb24cbe324bc3f94ece730a23854700ad93bacc6120026d7dd5cd03212bc415e0a25e48a9206d99d90453e79e -942b36ce768c511d65d12a1bf376287de5fd66bed4d9c6e3cf600989a39519a587f3613bbb00685b0e45c281e4a0c452 -83a5c6f179d8e86a5b68bef155720589509b8bbdfb78b2c76a9c83914b89904fb42a75b45418a528ed66099a9d173ecb -83448accbc24fc52bfc27bf4601fecccdbd53eb5bcfe7a51cc006700499d37025fe4ed2c46161ae8d28d42dce5d9e2ea -8a010850814a0c4db30acfc5a2c07468a446b9dae3f429efcd7a312b3f598c0952ca3a6ca749b7d5117180432f7981e4 -b228090f42a87322e6779888ecb8b4fd825c0dc79e7c00132150a4c593e16e38d37e838b6168bc23dee58e957da1b99d -af16dbd5ad98a41d7ad725aff4cda4f7feee1063e3b2ef9a85812c88bcd1bc1e8c0f6aed171c1c5fbbaa14b9394fb1b2 -b176706487da733cc9116653c277b484fa84896d32b12e861783a0fec8eeebae9dbe0fa91d91ccee0b986adc4810d1a7 -b33dc169ce8d3d0c6a4e24682d1430fcc8c8c19de46dfe3614a3038c766c839f9f31ff9475633426c90fab0e1e3972c7 -a8e831183d1de7ee12916a3b449e2e9e41f069a2f51fb8035f9349006e82f5a22f63e8cbbaaef41efc4ca25c857ead76 -8dfff2fc0a9c853b1a3d99d3a39e8fc226251f188cfb684b44fb242b779243e83147a98800510f19537c12aab46e4327 -8d8e5feeec647f13a5186bc8c4d2c5141bbcebdf9d2f836435733d2efa75badffe57081211a6f2cf8e87929d1fc04fad -af594e0e48ec2f88bab23204e02207d1144fc5eba69e7fb16311d1aa46b442f45ae8e8726448499bbd82eb4d523ac6aa -a74c860f9d66e676a8a25c6f643644e484b0bd91574e1bf23486e979468249b8da1f4c52b5ccaf331f61ce3993b47ce4 -98767036d5f42c3d3d6e92bd1b176f165eaf1bfbdcc0f8b78a41bef23c68f6619d918e0b1236295662e02790fbe69b29 -a6c3bd7174522b4f70cd338968eaa526a072661de9cea2e0f689ccc707392f5239029441c25ed8082f4f920bdc90f6a4 -89c9270b00f3396bdf7e157bc72c1c6073fcda9a8fb74ca46cc61ce8c6080852e62c7c7cef0a12a36d62526eab47b2fb -92a40c911deaa49d682d285e523c6c8e9d72326620e096399dc1fc0fc758811d9d1e4619529918cfbffd6ad249e09dce -acef1169e9d7636125bbe7a4a2ae670407a14d8ade3281dc0701a0ffd3d474ae7f0c2ab7e5db1631319f52e3e278daca -92b43ec4e3c5bb047d018683fb62f3c50d7f3cad409cf3992b9bee03a308c299b7b2b73ddbb0cb445c886392082d1b6d -ac4b72ec840e593ef3f154a2896cba7530c7b245187275e6e68c65da0b58195580f112d51373e36cf7977ea8362b98b0 -a4cb8adaf311285056c2753795ddea6ec8775ff9c1eb635d39fefa59d0d630ccf68b2c92de2f063835923819aae4d1f3 -b28d62a46ded2e889f397f871508b64f82f9d19d7eb1d0c396aabfde3c21856a4c274bacb116c6d180a1b67e9dd4d6d2 -802309d1e92a9b56cb67eb81076c66255c48d6ab8fb683e8964a2a4e42156f5d1dda7489dce39be64cf69c6e11a62292 -88346b771b7575702da0479767009112ca9fcc119c55be73f573268a5f80c00988ca56da0e96c9aa035a9a70c29ac2d9 -9410ccdb67c9e9bd632529a6e32cd8763236118be74a7269182d491af2b4b050fafc29ccc5596c65425e97a7d62737a6 -8419da76f6ae86ad5473270edc831804902ddcb32e2bb5b91858a8d32fd90202ad1e7b83d02fb8ae870427200958ee9c -98b4c81723ac7981f5457f5972d0764c52df4e7884f8f677b702c757dd202298a55d1b0c9c66c45461e58cb60fbb71c4 -a0db34ec3ba07a39688115fab56fe535e645550bf7cb80593087c1f271d1859df8cb6318b08d9a90ffb06eef1795b6a9 -b404cc7e0bc049f1852a6c41db65173f64d32964bd3d8b225d1902d61df9c47f0c4748c972212a60d94ec0ff378199c6 -81cf8324fb341549e0be456421b973ec7f0f7678d02fd688dca82c0c67dab27974ad926da4541b9ddda4293bca1714d4 -869eb17879af8be1b74f1eafc4a7d5efceed18a59493f09e49f0a54b976db20b86efc1f7469470991117545db2d5e0c2 -abd400cb31b79373e83febb51feccb04be54594ef339bff6b27060b1fd9cc4166204297ce6cfe7e35e10956d77821b63 -8934ae372546374b81874114e05e9a8f657519c9b5610c92a9fa7998308eec6590e3bbde6603ec5d6068e365cd6ba4a0 -a641fdb324d269e8e398fa1c4a995676e12b388e4aea04f9be059e53d9a592699a3f90b667733ab37e4af414c2672797 -8733c0e88d7872a23e1a19bb03cbbcbc21dc24d33629e06e26593faf80135aaf2ab152499d54c2fad61fe2a5623c6de4 -b0edcbdd024492c7b97031179b3a73b766a51d9b8e8ce74e7a50112575930370aca39b0120e777046ff73a1d3d98322b -adcb9f33cac546f00631df518e956a5855523fe189dfb5f92c0122c2ae40996701215a5c0c182ccba036c2d205845285 -991f157e50291ba5a5ffaf57f9c1c4bd5a987548a9f7b19c3c8eedd414abb785c8ab6f51bc766d285c6f85b25db1a829 -81fe3ed83fbe3053ddf47561d12875cf4da0270155b50e8b6c5beab31e4a295f167df96427a6a9a638b209264e50d591 -933bf009a45e43fa3294e2252949fbd76337fd6201699a4648e464f84144e36d245e1215f51ea93fbba76ce4c36ab2c3 -8eb3759f364f49a65ccfba1adc0d12c564e31936a8c3b86b274a84fbc1d67919c87db5f58c92b2778094b9cd2e0ea0b0 -b46daa9261e739448268775ead25a2a907807a0653674ce416358302652485ce29026806a5c080f93584f9b63ef1b870 -8e265bd8eb701c8640db63ad8982d392c2f04acb572f8a7819e5d2811f276b658b2dfbcd9124bda8362198da4077cf57 -974a1ae8b109dd0e8bbc95decd68a2fd23c38d3ee3ea91b847d9f46dfd5175337e22c0fc81014281a929c22b8f6cd8bc -8037a033791944866830d4e92ad026f62a948505d9dbee2812a3afa5d6284583784f36796e59cbd6f03485a4c9b6f8f2 -8b29ac555fa0f9e82629a7e37bdf2b23f5ec30a34b0fba0efe00a787336baa69107e4e6ea504af60c446b3e32038b08b -92e46327da3cdc5ee89689cc5a8d51cbee604fb3545dea358fab77ade60c1cc52eef078590d40466539471300ba4cfad -918ab27dcfda124766942542a0e666b2e708f67e5c9d2b26f277002d00cea7f2d76535fc1d2b66d86420d891720e6daa -a3c4ce4898354f4c052c48ad269629186f1a8885d14adc2e17dec724dc0e6206cf5719cc2f926e1087fd755494d79b18 -a440d5731f64cc037e74f3938d1b2b28a0d203d058e7cd190528369fe23345817950afcd5ad21b3d982ae88ac72190f5 -8193c27e58c6cbcb16a97ef06e4ff69f7dc1c87e4743dd9254aed6a714e7b8e1e0ec768900e41dc3b39cfd407a1db3f1 -86f191157c8e85b5f0e7152f632346fca712dfdb1879d5deacde18dbf918194f3246a6c46e8e9d7d71b0ab429a059b37 -84ae83021192215245d26aa84295d02c15051570758e100c1d7ab82f78161cd772ffad2112620ef0d8680477832c4031 -a4c81b0002e40ecc379e0a2c2ad3ae80ca4ee0b1030a89ce58e28061ae7c8c455fb6e5b58dcdb02c749f7fea72fcfc1f -b8371a720c83686be25c8e63a37127e1b1b612f2652df965fe215d044df070cce156e3e5a062f0159c495c66d05efc04 -a621a637dbe143f099ce34dac177c9c4384d27b431230b6fc17ea4478913dc9efa1029eee0b8b04c07e31ebb07e0c397 -a7022d1eddb9deef129a62e4e9e04e37011cd200cda8248126689d8ab41eeb1516267afea53e0e681c59e5bf9d307199 -91d41d3f25575ebc036148cddbb6bb956f316eec09d881f75bee17f315ca0b2dce519b6da1a53365605c99e9ea21267a -ab63040dc84060885f4bfcccaa85fa45073141329c3b02b500d52e8e501f4ea651d1920ba635a2b79eb0244a6be5b68b -ab20bdf8969207c69d38bf297aca90a2a5069c652b158a9e6c3053e844d87f2b95148dae5bde68fd2e0e42503451a00b -827a020a26e824ab606f287d517e315dd992d6ed2c8c982e3bb7de3d54210791516cbbeeace31f42a09f076db98ec686 -843a815d2ec52f80dd8caf22f6d7998cf61c06ffebc37c63d1b990655f50223d1e0cfd795f8d6574ba8ebd82d9832b2d -a595fface5650664e51c603d76c8d7476f4657fe49ce883e8726c3e6146214e870e6d1ed8d63a3d765de23ce72e19e08 -ae48c329586ba4d025854abd156d5b2545805ee775c6ab095c254e3754fed65359327a0cbe32cbfbf1cdb0f97b352a75 -a69e783c8f3cca9a52ae30c954ff75131174aff108de903d3c16aeb77a481dd0ba632cb78ace088accd77e53c0b2b0a8 -b18c69d7c7b52072b125ce78a19b2dfe47c0c1a7d8e9c2152591e8853c004760db4ee6120bd6a1d5466b2141af490a25 -ada5ec5285afd44751dd1ba4a3cc9a9910711be18229d7b622933db4c10523cbebaeb6e4f4fc556c79a0bd1d045f9bba -94a051724e5ae356d4c5c0861da835a196f7c4289d088217b92e7067a12d2335d98bc0ad4fe591a494ba9e9f6469c963 -ac40df154abaab6427f8e2f335023afa05be0e12884ae8d5932eb1a81e0386b6e68c4632d1c0f6c11def67b0b4c79b25 -92c335770ebac3ac14f1c56beb617dd1dd134aa7a691b8883dcef104d80a5f04229e0bf9346cce0e6ef85e028c97e4bf -84c52736ec2731d82ad82eed79e1686d88146e6db561674549981a73801f93e91fe1b79eeafdd521cfae29f2fcf7e5aa -9965e135c7f44c2fa497edaf5b3a3540fb08ac902be0a075e6e130f93668dcdd6b2a8624996f81f76968f49309dc0314 -912c059c8131e73dcbca17517f35e0767792337e02c86de289c04202ed69ef9c7a57774649df8ba169eec8c0eb49f4e8 -8977256599f48d1c28b883988285daf42a53a15cbcb11d87c3a2d69bf20001c38c0d72719dc1af43a438fc2da77ee78e -974701aecb6c0ebe278be8297afa491e0d8232796d4ce4e5c3ce8a57043e22eed36517cc6a184b6af811447ae28bf846 -9769a3b8b931e07fec9c02cfd4c51f15b5cb37bacf5e47bafa32c0fd937963b0e0010fc1f963802dc24d89d37018358b -979ff8cf0f472fb2621f7bcff40f76739bc8eefd83d3a673d7bfea6f0c563365d9c8083ce71ed9107a330191cce6b07d -96c20d0db06f4948a19de606a42a84a0cac850dbfe05280f11f62a9832d7d2cec4f7a40c16face069c78736e6cdcfd61 -ae4782233342c02901ab2ee6f49b43a3f8dec4d50e83251ab3956ec29c6f67ed934dccec52f0a5a5b068a267c32d8f89 -86dfe7862de9fec66666dcf00fadfebd81a24cf82ccc900451cfef04c06b0d203f10a621695f53c25c22ab7540c8d532 -8778132b6fadb3b8186219ec03a457b21a365ca20f0ccdb6b2174c0fc396dcebe66e363cf8859315b2423a9ad188a040 -ad6ac25dc4c04777a54b13a15df68ecb97037b3b6148b8d593ed8712993b3de5154d09e4ea22e1ef6b63643189e1cc71 -ac7ac4a7b30d18ee1b79017b6a3169289fd72721cf274fe9b8373375c163f6a5226a38acbaeb2aab67d9128a0f247f88 -b56eb67b31ec85c73536cd664cddd2e9890557a917ac589cb1f05e5ecc27690608ee4ed2a7d234c45af11a5f0f97ad53 -b3aeef6101227197104ce802c87621c6d09808388f4feb364cb9c0630cd71ddbc4a1bfb5e891b1aad5888b26482431e5 -93f565fa505833d5cb76b23d5928a7ec955dd754fdf7300fa4f01fdee752e30adef8f91c3ba94411a58fbf5018ba62b3 -a699045ab8b898f4ee265d1f4548788cecb5861de8697cb35193744fa8917b34d2817b8ee67ced2c90aa9661a3dde43d -933ee92a18863b164efa9dd6e813fcada50edca408776f0e27f3f6633b1ad30a85763c9daa9a7204db8350f627d4b235 -83b8eaf9c5524fd8534f6f66a14102b0183e0d37463556ebc777301b4298c97eed7b454041a25c723493da925fcdc8b3 -9405f4fd069ba5fe18acf22af977ed09004135273665eb5441652afba9475ab2de549331503ee2b7322857a1f139d613 -b3f55b8afdae1bfde6bf840c7e30da0a161e8a0a9e27e09070688720e0518e71b2b3a87365371463a81221ddde23774b -af0c120fa403fc0dae19e51e6ce3152c56d71a73b4e237a64732739527ec1ecb8721cda69ba96ecfa78091195220af10 -952a66436ae24f5a73bab30301a347580a7b14c759a6f7ece69522cfb3f5a325635bb018dc1f277ccbf80151f85463a6 -90e604dfe68e58ff9a3405742bc04163d920811caef3a49491412663bea36bef33350adc5f656555a8473016f9bf2417 -af3acf7ceb9bb60bb3f0c827bfb1a872714f172a57bf13a00deff4c5821a6ea3dc131b1fc56c91e12da328d433a50086 -a0c941013249af9410b5e48c4ea19ab5792468530190237406519e5907dd490b790581a5ba07910a3c3de530c5f1289d -884b448dcd6331440bd4f50da31772c943184e00cf246600b5cd923a79928c5d87492602a9f62c8cc3c5a76ef534a67d -a275c9cf5498772748743d55e99d5fa54d3ef495202f46bb439c0e07728eb0b58ee5f59b3fd1b4233e2266aeda829c11 -aa9f78222ced7796588d848c7d2964b4a0e229a702d16bd6cd2020e34138ddfdd24faf01c77f9d1a6fb1bc9ba8c2f820 -b7b34e56b94aa15f83b71b757a3465ea47ac4e5a39095bbe683fc6c6713c87631a15b81b9994d56846d153f1cc51b103 -ae54faa7aeb046ec0e77db95f35ee5e1f1274ec2346dc1f1734d70e86bcce54feb9fc52e94879791f16e691c2da67374 -b6f0c9eaa7a32d8811b597680b5acd16faf2394ab6772b8621bec7cdaa3a249d1674a5b45f312f92ec81514aec551052 -a88ff68063f30795884333dd033bccb397c7866af6922d6b09b968729a49d13c33fd66cafccf00579d88f23668b2a9f6 -8a897fe4e6165a62f3605d33235e91b5a999762d0f822655d44bbeb7a006dc7c08300f48e19d299723ee22f23f884742 -b67a42d41ffc93f8004d6d72f29077f8e26620ca510ee35d9f0b5bbf34e26e5c2353552b9f57776e55d5b0cd095aa311 -a27689f0949df64cceda7ad2beaa4ca9bbc4ed85da9b2fbea96c604445a2284faf8078dfbfa5a1e1514bb1b7156e2fde -b6064f305165fa52ee7efd5846b9871338f42ef06400e642882270659917c71e8e6f8bdd84e0b07b5305883c26d6832e -b5d4e50a19ade548c1e71d4252bd078d8e729e3c88cc0888969620db31930ff42712784090ecb456c60a0368620dcbf7 -a26f4fa8d75f350b9c1f4d989fc6af06e0c61be7220589438d4d4ef6f2f4d1a0ded7901a46edcabad234260c7fdcbb89 -9737ddf44d1ae3fcd9a4d6e095fde2e761ff0169f2df2783562ade0880d531191266b460c3924b007a97eda482c0c15a -a1e50e270d2629a01c5f90afd59bd5cff365de8af44e2ea572200cc444c7b7cc10d4d843df6d34fa9b783fb0b6b12326 -b274fbbc10628736c5c2c1b3ffbfe7ef2fe8e33ff5d3424b4e685c44964d576e8cfb7b9fc491c4293031b2dd4a00ced0 -a0fe81040c264126d9163da6694580c5b7203f4c69f8dfdfd842326f0ae724239a232019379357e4f12a5ba22447a06e -87fe3ee98cb358f6e26e7647b6910bd2286d5864f8544d7f34cf5949464c5854c58e35fae79b43e0edec8ed0bb189c06 -82c28a86c0cd0380ef0c14337c38e09e07a5b671d304b8f60b315dff470211350d930138bba3602ec9ea8b4d5f9db52c -96a86ac8736f8155c1d661cdf537125750c66f3bbeaff54388944c46e3b482f7b25c8f7101c9dada2f63841534979184 -89c92e713a0795caaa711ef9bc7cc23cc0314a3b4290209f57df3d8c74cbe943f495711f0c28064ef1b6540cbd0ce036 -800e9eb3ad2a7e11deccf92708f3649e37009e1851f9bc5686524e4fd47e9d799275ca3e95fa0a51c9424a659a546aca -914abd539869ee464aafd6bf78cd63e0ea88fc21be5d1a8bf81bce4473ddb333728ce631618a2f23e2afbc4ec0dc660d -b652c3453d34a7b9b45ae3bc2542bbc32023571ba377bc5416e9989113e96eab94d57ffa31a0c73c5d1a71b51b9659a5 -ace4559844a367e30a9dcd0047ee21693d6232d9c6557e1b92805a0c2a2eca9b970b6104be0d3e360ad8f4a9ce2779c2 -843ddbee50b9715f067285772f9a04c48b41d9a957727e1e04899d9ec0372355a708e61d39c32956e119cc77e9abb0fb -ae3b4f57050968d1b3dcbd9b5bb5f3e2aacaddb39aa84229e4718b9cc03736467ea6e35606136f60e3b72b35eecca5dd -96ad4da2c505b7da33c724893a403197d4a5a393092d04a0b62151f99c8e04ad944ceeb031c9362481cc83d99ee50996 -b4973acd731be9ef200b505ce72e77fa781afa269290c8160b545aa14e4a0ce0d704f0ba8117b6c2dc8bc144ace6ed40 -9159f84f8fe9b85e749007e63d36317a3336a1b1a7e440fb084ae6fb4a3a6d2afac0b0cdd6b382bce3779159e0b814b0 -98654b7af82e7e1b643ffdd09e125fa916e0b39588908596fb802aab82c3bd8f379f4593fe8c1fc7c533d8518af42e39 -b47e4d79ccd82c4a1ba3df20dc809662320fb775cc2b5010f58572e1c2051a52c013dea507a3e3b681dfd9b98bd5ada6 -98ea992f0ed02bb12c305017126dc0e3709bb7a1c5257fecd94f54699303ca8cd3f568c7bddd8ed5bc30dab458dec9e0 -8d7bf1317239e3c21b8778848d479795a9098033731544654bffe13f8be88671561c4c65f45e71a7b7e21adc9a76bef9 -b56ec8f5484d1d6b0730960652eab5974e88fedb5642500933c9382e922fb473186319f4a534bf799a925335fa69cb2f -8e7a801d1e39b8dafa84a1bb9be4da78da41df793e2757b80b435f24d4f4fbadc436ee265c2de53de5e81ef02973669b -b74a9840cc4f59aec04947a389fad3d7811c4c60eecf7d4f1ba9de6d3d04b7f760d7d3332b97f40ced1fbaff52b7b89c -a8cbad1896bb20a5329ae4d4ebc4e04b0ee8e763e006050f7bb2e18994f11c65f7cd57355964f1d03b98fbca500a64e6 -83a9fe1753eefb84aea64339c416e5bf6bbb67b877ae4834c388fdbb1bb4791a22af59bd8172f0400253a1f7405071fa -b9cb49a7a2fa5904f850989fccf089900fd9488bf6024199dd7d5d797d35a5513e32bb85d78ed91349b93bff0f313cd9 -aa507796d3cc78b8732bba85e4fd8dfc790e8ce6711a5ca75a27c6b9f6c3ae5afbfce696daa7e2ccb31a0b722c996b28 -a4fb761dab54ead40dad4a34d19fb6912337eef0463a6ecc0ff816a8394f2e540f78faba7ac9358bf013e406c23418b6 -a3943c1926c5ef891f3e76b3116b2cfbc05bf048f4e5c99712194b5601e830635c90584b535ab1ad47c6c8a494c811d0 -b0f166d2c5fb07b1c96043b0a7e71ceeb243122330043978331fe8392796df3cc420cbd59f89a9c0f2e950dcf843b428 -8030e3ec511eac9d90e81eb1f219c14c23eaeb82d101a1cf88ce5674d41191ed18f773472f222b5c7071d2319b12d875 -91f0478cb91f3d0bcaea82df36cbca937c38a393b28b3b6d2af28c6d653fcf42912a7a5c7ae0f890685df6d7e3f1ab8b -8b888613c52c0b4e91845d7175aaf7f2de756a11aa7e82cd26e1dd489b04ad62aa585fcd0f92748d8b45257eacf8fdc5 -8a13d62dc07ed4ae220f8f339b3fdedcde68cd1720988c6f2409ab81ec4663b8ffcbe63e110b89b6311e1380a8dfc93f -a3ca0100c7da9a1976d948d9ffaa1e12e90adaddaa8a741978e367b2308b8d7272506030605dc7a759da4d1d56253b5b -878a79b06334b14cd23b801dfc4769a2a6c6adc97758b180ba6ba81be729de7a2e2d914ab86642563a83c6c18a3e684f -a9f5bdda8edd8c1fb9b5bb9e08940c0577688e8785ab6b9c87516027ca0409361e647b47a59fa97bb11307272de58a22 -b6ef00890eba760a3cb765a8cbc00643bfac23290c5eea5f9afd0235df42054c15a79f578642d721f7064f1071a200a3 -b0cef537eafea359e62ffc453d937935089fdee23cb4b691bf43f8e64698c59f2d81bb02e9994345ea26f78417470b16 -b5426a7a581d7dcc4e6136901e3551c27dc4dd442b2849786ca61453ee8082f15d41d0ae23c2a8cec4160b7c4da4ea22 -8432e93e19fc24961201dd750f7d14c9fca69a457fe9e97a9cc9b618927896d1a523d2cd9418243025d9978c3f781528 -a11cec4c9c707c51ac9583b4ecd1fc80d3b848b539f9429edd532d50d8a93f3219dc98100922af3d45d2ac8ec0315723 -a5a0fa3e3d8bf1316422aef9d449c63d63ecb4fb294b4987e1ce768135a3ad7aa9cb81a3dfb0e51d5d0ecc5b6b2e6c29 -b3a1cb977dbcf38487f94ceb72ac3d4111b55a3e5ee71b14860a975ec8f08001e3a129675527194b808dc2cc2fec69da -8df5a9e743cf36cdad2e2a425c332daf317d418ad0c4e6676cccce659e57af12a35b059ae11ccb08c80d41f7d3aee472 -b5b25b3d7063f13f8f634cdc7be4f2b619c9b948cf28a5c2d189ceec3752b55f99cda9a2d65d2ebf96ce895d0348a79e -a4a5d32d74d5b1077d1dcba527ec40a8669ddeea9796d51568cd44c3f481a9cf870cf66354fbdd262ddfa9e189d41b10 -95196a2873b5bed8c4cab84250bf874572828697d4beca9fbc16048053ddf913063b001678c9e8c99992e057b5644402 -a77930043de6d3231cbf6d66f82a8a746e4f77775c5c1e35fd19d43b70399c94d30ea9895c82c865a6c4ee60f206a9ed -99de8f9dab554fc07e061e9fd411ef916f46139a4461607f5d601d6930194d3433882f6427ac8a346cf867cbbd08097c -b76809b153f611ab9d16bc49cdf9774343f82d6fc1939f13a49b20f8e8dc0ef679f07f534bd5acd5404ffdf3fc18f04e -8c6d45c1cab2759209e0ffaca93d0f7602122e883b5ae71c79087abd781585f33b4b89c3f5505da82897fb2c6379ddb5 -984279d4c9ee8f51eaee7a146ed665094bfc1bc97a50bcf1a77e18b6304fc71fd2a6ef58daf3abf1160d744d9813c035 -83529d6085fa4142ed5c7e950cbe25d87f1a16955c2a7b963478daa4940f0cf8f31571589d537cdc02a7eb39df019872 -8f4c88ed9d4f0ae38f5b3c014414cd50bd2387393996f35a91491fad83fe0ea9a112c48369ef2e901eae345c72be7690 -b1ef0a88686b4d48455ea06d5e9bedc92c13789774df37e2f0868da3b55d06aaf58a41fcce391f5cc0861f35441877a8 -82b92a1ea191176167375b5c1374b27ba710c768d81cee06cde787790db098d9f12415711400747fd54612ef9af0ea6e +8d0c6eeadd3f8529d67246f77404a4ac2d9d7fd7d50cf103d3e6abb9003e5e36d8f322663ebced6707a7f46d97b7566d +a0d2392f030681c61c2a867862917e10f7678d882034bb89af3db87e6ab3883a304034643dc9688a04e41a5b831582bc +94298073048d70c74f36685e547d04b7311479daa05912e18ead64b2099a194bf48ec344273d58daf0b86b1d8f1d318d +85c4063d13499013dc2ccaa98c1606763e6b1e8cca20922d4cec12ecbaf006ea81ffabe6596d1ac7ba1daf7e63e30898 +84c64bce36c6b5145c6880113366025ab9a8f88e3948d374e27be8b8f9f87402c70fec9b3c621a2d1d26764a84370d0c +8b206c823acf5294552ee54579fac0f45ea15bd273dbacd63b88cd7cddbcce23b56e52f8ea352e1e1d7dcd9b3991b413 +b70aaa4038ba3f5ff306c647b4392d004950c53ad8f6713b5c9c21ac99f5c56cf57323dac500a1f4e9507c4746b07a2f +895f6d1fc70b52f838d81b24f4840729cd5988b649e9d6e6f6dbac4281d8818f39ebdae7e6ea139d7f98a832bd6f29f1 +a71a2832bbaade974c9ef7505dfa24e1ba466a9951b7c2db56886be31c9c7b871f3ee76cb1fcc1aab4b906d6502bc9b5 +9530ba64a21e27834609c00616bc63e8fc2dc7800e478ad728ec39c624f65bbc62cb48f59decb7fbf605ce1920d02622 +8d0609affaf8619bb2f6c80699e5bc7783becbd5973630cdd227ae52d6d701c45f4270becca97701b40279fab588cf64 +8f5d5b4c3bb8dc9a19e5a0f84df6322a79a00c7783c86254197d313a5b35d3965a1f7c0b9c4e39ec1e8f5d02d3aa0862 +96aa47a3ba20b1cfe81eb26bef503225037fdf4c9df53bea1b520841875cd1db6aa8e0f34685da08b55a3ce7289e6de0 +b4c27ee3f4b8c0031837160f0a75632f5b51b5850d52b530096443f54c2b264aeccc5c61b4fcc8de7074475f354fa0d8 +acfd735cda20be1d6f425a7886629c91732fbb5a4e0350ca740a8fb5b39f2001071cec0b2a0f6ca35e1f35a5ea18d00f +ae44d87b1d16d59504c602cbacde2c2791f1520391ca50154e6036d3953ca466cf93d6537da2adb729e6f9f4ffa87853 +97b492872ce44941ea4668ffca83b82fac0f4021bd47e0a5ffeaaacb1b3fc924ee4d53b99f7bcafe0985caf0fbe5d1d3 +b3fbe2f9103d293f49c6c6016d5913f041c9113295397388111a0fdf4245d8edd6e63b9a1a1c9c8f868d6e1988116880 +805efa08fd2046c44c427b225c17bed8a1eb3320cdf94026fdc24c6d345a6cfebfd7475f85d2d1bf22018ca72d2761d3 +9888bae0d83077d1dfde82fdffb1195565c31c519b80cba1e21aba58ee9ccb5677f74bfde13fa5723026514a7d839661 +922e19d2646ba90c9f56278bddf74621cc4518ae2f042fb8245843e87cd82724c6d7c9a99907ac6de5f2187fd2e77cbe +a38f0e1faf97dd1e0804b44e4d150dbfa48318442d1c5255eb0c14ea56b50502f3c7cb216a0336e7c140398088dc01cf +93598ea391c8735799a1d4cd0456f34994ccdf4883fad57419f634f30fee595938bc66b066dade9ae52578818c00d899 +a528dc920734cfaee9feacbc0baa5b73befb1ec6fbd422fcad09a9c1f8f8c40b5ea332b2cf04dc1d6d921e9da9ddfeb4 +b38d45316bf78d11e796a34ee535814e6cde0e642f14108329c5b21f4fec18cd61f84a3025824bb8dc4cbd26b2ecc9bf +8eec35a7404c9a35dc6ad0260b7f0f7fd1bfe92a2e08bc72548b99ed9acdc378728a8ea9c6879a6e47e37edb0d28c193 +a68a4446274ccd947c61bf736c5219dad680b99c6085a26719793e0d9dab26d5f8a0b28e71be6e1b9ea4ae39139f7f57 +a0acb543f41ad12e3b2e096629ccdd719a001d0ff53bb151e9a37aa57852f7275a7bbd06dc2a06af9144524548164af5 +b271e74cdbcf8b9143f8472174bdb068c23308ea807c60a554c185f7be6f231aac13347139837514171a876dfac5baa5 +8195a460719000cd1df379ebbf7918f71301a50a2fa587505cc5b8c4534c3d2343f63d28e7ee991d7a1cebb15d380696 +96202b60426773e8731dcbedbf613477f65940a19fb4be0f4f742b0c76ae9d88ecdb6d36cd4f12bb404dd5d360c819e2 +b0a80fe60b71ca9e80157138de8787b8a786326179604b8a15a744e52662645987e5f859ef5c76492d560daf4624b9a7 +a331ea8adf87daa5e2d458d0113c307edae1a84927bca7d484aca5f8c1b6378ab42981c44b0d916d7249f4b475f926f1 +aa1a8f59ae0912abf191ea7e209ff401628278dfb2269db6d87cf33bd52af3dbffbe96513a8b210e965c853a554b787a +ac4f4a0e1b1a155e1f22a9085b0b047fe54c8437dbbb8e9720fd6b0cdd76557d19ca2e885a48890f0247b1a72be0e287 +a428465505eac7b9660eb0d495a7a00c8cc238de3a02ebbd2eb07e502e9868086e9584b59953cf1480c0b781295db339 +b7b77e21e08f6357cbd3dcd3035c3e8ec84cdfa13c7baef6c67e0ef43095e61fd549694263d7def8b8adc3a0fdcc7987 +abb991d17c5bdd264c592c55101e265cb3210c4157aee4079173fd51da1e0199eed1d6c890aab95817ec078561d771af +846a8e4f801faf5fbec078b09c362ee30a00b2b58a4871744d03cd118b913464233ff926e52b0c75fbfcf098ad25a1e6 +947e91ffa32f38c1ccb72cca4bfabaee9e63ab74a16f034cabba25e462f7331ebe5a7ba393f69e91830415fa75b1b52e +8dc5e26adc693f4e300cab7385edca1a2fe14c8ee6dc0cd6d013cb5aa154dc380e9e81e259cbc59c1f38f7c4a57f1c7d +9818ef6605d6ea3b7bf4da5c6d6d8ed540bb94df4d14c974e1b79ed2fd1a0b897b8cf1ff671a181a697effd66b1644a5 +b5eab6baf03af994fc32cc9dce388394c18c01cdafe7909fde948f3e00a72dc8f30d15977d0f114bd7c140f5f94cf005 +83b2e9858d3b929f9a2ad66a91a2c0c44d15d288c17c12a1614301a6f2d61d31eaa540ca7781520fe4420afae0ec0208 +ab338fbd38bce4d1b7a759f71e5e5673746c52846eff3d0b6825e390aeeca8f9f123ee88c78fe4d520cc415cbae32bf1 +81adb6322b8db95d1711304e5b59f37640ca88c03e6c7e15de932be5267dff7351fa17664113ecc528e8920f5bfdc0d1 +89e2e0c0d769e4107232df741678a6bacb041d0154385450aaca8be9c3c18c42f817373962e7569d33935c35666a8a6a +8f0756fea8b34a2b471ec39e4448a6a6935e5432ec2859d222964a4c82777a340e1d702777aeb946fa405afc0438221a +a2bf90c505a6f03b3dd09d04e1e7cf301fe3415b273e263f15fdfe5d0e40f619b95e8bf00916d3eaa7d7f8c0bae41c8e +91d5c76b5542637588cd47279d0bd74a25dbda0d8ec0ff68b62d7e01e34a63fc3e06d116ee75c803864b1cf330f6c360 +a9958c388d25315a979566174b0622446335cb559aff1992bd71910c47497536019c6854d31c0e22df07505963fc44ff +91d82b09d5726077eed6c19bcb398abe79d87ce16c413df6bf5932b8fd64b4c0fd19c9bf0fa8db657a4a4d4c0d8f5a2d +ac6e0a86e0ee416855c3e9eef2526c43835f5245527ed0038bc83b4fcadb4ea5beb91143cc674486681a9f0e63f856b1 +aaf00d6efd0c6efb9f7d6a42555abec05c5af8f324e2e579fc2ac83bdc937cc682d9bc2ffd250619c8bb098b8c84db80 +963f5fcd8476d0dbeb03a62cde40e3deee25f55e7ded7572d8884975f38eddc5406fc4b0adff602a1cca90f7205a7fdc +a3805ee01512f644d2679511bd8607890ee9721e75ac9a85ab9fd6fceb1308d5b9b0e9907686b4e683b34aed0f34cd81 +a483d7708465cd4e33b4407fe82c84ef6bc7fa21475d961fe2e99802d0c999b6474ef7a46dd615b219c9c7e9faec45ee +b6b5f9456f12d6781c41f17cdc9d259f9515994d5dee49bb701a33fa2e8dcbb2c8c13f822b51ad232fc5e05bff2f68ef +8766b721b0cf9b1a42614c7d29aad2d89da4996dc9e2a3baeba4b33ca74100ab0b83f55c546c963e3b6af1dcf9ca067c +ac5e8da1154cf4be8df2bbd2e212b7f8077099b2010c99e739441198f65337c6f7ef0d9136453a7668fde6e1389c32c7 +a9d6d2c8845e5f1fec183c5153f1f6e23421e28ce0c86b0ce993b30b87869065acad9e6d9927d9f03c590852821b2f9c +a320ca07c44f7ea3ff858fe18395a86f59559617f13ec96d1e8b4a3f01d9c066a45c8d8cf8f1f14a360bb774d55f5f18 +b3adb00e1312dce73b74fbd2ea16f0fb0085bd0db10772e9c260e9ed9f8829ff690e3dfffacaddc8233d484bb69778b3 +87b0c8d8a167d5199d0b0743c20fb83ec8a1c442f0204bcc53bf292ba382bef58a58a6d1e2467920e32c290fdc6dae7c +a74fa436a5adc280a68e0c56b28ac33647bdfc8c5326f4c99db6dbd1b98d91afb1f41f5fffd6bcc31c1f8789c148e2db +8a37349e4ba7558965077f7f9d839c61b7dcb857fcc7965c76a64a75e377bfea8cd09b7a269ce602cc4472affc483b69 +8af813f62c5962ff96bf73e33f47fd5a8e3e55651d429e77d2ce64a63c535ecc5cfc749bb120c489b7ea1d9b2a5d233c +833021445b7d9817caa33d6853fa25efc38e9d62494d209627d26799432ea7b87a96de4694967151abc1252dd2d04dfc +8f78a715107e0ace3a41bff0385fd75c13bf1250f9e5ddecf39e81bacc1244b978e3464892f7fb2596957855b8bf9fc7 +aed144134dc1cc6c671f70ebe71a3aadf7511eea382969bc5d499a678d2d8ce249ebf1a06b51183f61413eba0517012b +b39a53e82c5553943a5e45bc5116d8672ec44bed96b3541dead40344b287a7b02dbf7107372effb067edd946f47de500 +b383844c3b20a8bc06098046ec6b406df9419ad86fac4a000905c01325426903a5e369af856d71ccd52fea362ed29db5 +83815a7098283723eec6aa6451b5d99578bf28a02971375a1fe90c15a20963e129372ac4af7b306ee2e7316472c5d66d +b426b4e185806a31febd745fa8d26b6397832a04e33c9a7eb460cbf302b4c134a8a01d4e5e40bc9b73296c539e60b3ca +a6cabf8205711457e6363ef4379ebc1226001e1aaea3002b25bfd9e173f4368002f4461e79eeb9f4aa46f1b56c739ab9 +a6e88ab01282313269cd2d8c0df1a79dada5b565d6623900af9e7e15351de2b0105cc55d3e9080e1e41efe48be32a622 +b2b106db3d56d189ea57afa133ae4941b4eb1dc168357af488e46811c687713fc66bbd6f8500bbd13cdb45cb82c14d1d +b3a74780ff949d19e6438db280e53632c60dc544f41320d40297fe5bb7fcee7e7931111053c30fb1ed9019ab28965b44 +8c67f32b9fdc04ec291cc0d928841ab09b08e87356e43fbbf7ac3ff0f955642628f661b6f0c8e2192a887489fddf07bb +b3be58bd628383352e6473fe9a1a27cf17242df0b1273f5867e9119e908969b9e9e7e294a83b9ea14825003cb652d80c +a867acf6ab03e50936c19a21d4040bfd97eb5a89852bd9967da0e326d67ce839937cab4e910d1149ecef9d5f1b2d8f08 +8006b19126bd49cbb40d73a99a37c2e02d6d37065bbe0cfcee888280176184964bd8f222f85960667c5b36dfaee0ee35 +ac50967b8b7840bf9d51216d68a274f1d3431c7d4031fbac75a754befbbb707c2bb184867db6b9d957f3ba0fd0a26231 +b5a794c928aff0c4271674eb0a02143ed9b4d3bc950584c7cd97b7d3c3f2e323798fd5ccc6fcc0eb2e417d87f4c542a2 +a2ca3d6509f04b37091ce6697672ee6495b42d986d75bd2d2058faa100d09fd0a145350f2d280d2cb36516171bd97dbf +92cfa293469967a9207b37cd70392312faf81b52963bfbad5f9f3da00817d26e10faf469e0e720c3bb195f23dda8c696 +a0dd5135da0a0e33fa922c623263b29518d7fa000e5beefc66faa4d6201516d058f155475c4806917a3259db4377c38a +8fc3ae8ea6231aa9afb245a0af437e88ebca2c9ab76850c731981afba90d5add0ea254053449355eccf39df55bd912ed +9727afe1f0804297717cec9dc96d2d27024a6ae6d352fee5d25377ee858ee801593df6124b79cb62ddc9235ec1ade4ac +8bcb2c53fcaa38e8e2e0fd0929bc4d9ddce73c0282c8675676950ff806cb9f56ebd398b269f9a8c2a6265b15faf25fca +a8bd9007fbbdd4b8c049d0eb7d3649bd6a3e5097372fa8ea4b8821ba955c9ef3f39ac8b19f39d3af98640c74b9595005 +92c7e851c8bd6b09dfcbfdb644725c4f65e1c3dbd111df9d85d14a0bb2d7b657eb0c7db796b42bf447b3912ef1d3b8c3 +98c499b494d5b2b8bea97d00ac3a6d826ab3045bb35424575c87117fc2a1958f3829813e266630749caf0fa6eeb76819 +8df190d71e432fe8691d843f6eb563445805c372eb5b6b064ec4e939be3e07526b5b7f5a289ede44ae6116a91357b8b1 +b5010243f7c760fb52a935f6d8ed8fc12c0c2f57db3de8bb01fdeedf7e1c87b08f3dd3c649b65751f9fd27afa6be34c7 +889c8057402cc18649f5f943aed38d6ef609b66c583f75584f3b876c1f50c5dc7d738dc7642135742e1f13fa87be46c1 +996087337f69a19a4ebe8e764acf7af8170a7ad733cd201b0e4efde6ea11039a1853e115ad11387e0fb30ab655a666d8 +902732c429e767ab895f47b2e72f7facad5ef05a72c36a5f9762c2194eb559f22845bbb87c1acc985306ecb4b4fbbf79 +8519b62a150ea805cdfc05788b8d4e797d8396a7306b41777c438c2e8b5c38839cfec5e7dc5d546b42b7b76e062982a7 +862a53ba169e6842a72763f9082ff48fbfbb63129d5a26513917c2bca9ad6362c624ce6fc973cf464f2eb4892131eb04 +b86cd67c809d75fdb9f1c9453a39870f448b138f2b4058d07a707b88bb37f29d42e33ce444f4fbe50d6be13339cae8a6 +8cf5d8365dbbafc0af192feb4fc00c181e2c3babc5d253268ef5564934555fb1e9b1d85ec46f0ca4709b7d5b27169b89 +b48f11a1809ec780bf6181fae3b8d14f8d4dc7d1721128854354be691c7fc7695d60624f84016c1cea29a02aaf28bfbc +8b46b695a08cb9a2f29ab9dd79ab8a39ec7f0086995b8685568e007cd73aa2cd650d4fae6c3fb109c35612f751ba225e +8d2f9f0a5a7de894d6c50baceb8d75c96082df1dcf893ac95f420a93acbbf910204903d2eb6012b1b0495f08aaf9992f +b334db00a770394a84ec55c1bd5440b7d9f2521029030ef3411b0c2e0a34c75c827fd629c561ea76bd21cd6cf47027f4 +96e9ff76c42bcb36f2fb7819e9123420ed5608132f7c791f95cb657a61b13041e9ba2b36f798a0fdb484878cbe015905 +99f8d701e889abd7815d43ba99e0a85776ec48311fa7cb719d049f73b5d530fa950746ffbbb7beb9e30c39d864891dc2 +98169c20df7c15d7543991f9c68e40ac66607cbd43fc6195416e40009917039357e932d6e807f3a40bc4503ad01ae80a +84bd97dd9e4e2ba75d0dee7d4418c720d4746203d847ce2bdd6ed17d492023df48d7b1de27e3f5cb8660c4bb9519ae1b +a54319e06db7f5f826277a54734a875c5b3fd2fa09d36d8b73594137aa62774b7356560157bc9e3fdf1046dc57b6006a +90cfff7cd4e7c73b84f63455d31b0d428cb5eee53e378028591478511985bcc95eb94f79ad28af5b3bed864e422d7b06 +a11c23cc8dce26ac35aea9abe911905a32616a259fa7da3a20f42dc853ad31b2634007aa110c360d3771ff19851f4fb4 +9856fbee9095074ad0568498ff45f13fe81e84ea5edaf04127d9ee7e35e730c6d23fa7f8f49d092cf06b222f94ab7f36 +818862dec89f0dc314629fffbca9b96f24dfde2d835fa8bde21b30dc99fe46d837d8f745e41b39b8cf26bfe7f338f582 +831819d41524c50d19f7720bf48f65346b42fb7955ee6ecc192f7e9fed2e7010abccdfdeac2b0c7c599bc83ac70be371 +b367e588eb96aa8a908d8cc354706fee97e092d1bc7a836dbcc97c6ed4de349643a783fb4ddf0dec85a32060318efa85 +b7aaef729befd4ab2be5ec957d7d1dbe6178de1d05c2b230d8c4b0574a3363e2d51bc54ea0279a49cc7adffa15a5a43a +ae2891d848822794ecb641e12e30701f571431821d281ceecbccaaa69b8cd8242495dc5dbf38f7d8ed98f6c6919038aa +872cf2f230d3fffce17bf6f70739084876dc13596415644d151e477ce04170d6ab5a40773557eeb3600c1ad953a0bfce +b853d0a14cef7893ba1efb8f4c0fdb61342d30fa66f8e3d2ca5208826ce1db5c8a99aa5b64c97e9d90857d53beb93d67 +910b434536cec39a2c47ca396e279afdbc997a1c0192a7d8be2ba24126b4d762b4525a94cea593a7c1f707ba39f17c0c +b6511e9dea1fbccedd7b8bb0a790a71db3999bd4e3db91be2f1e25062fae9bb4e94e50d8ec0dcc67b7a0abce985200b2 +936885c90ebe5a231d9c2eb0dfd8d08a55ecaa8e0db31c28b7416869b3cc0371448168cbec968d4d26d1cb5a16ebe541 +b71c2ac873b27fe3da67036ca546d31ca7f7a3dc13070f1530fce566e7a707daeb22b80423d505f1835fe557173754f8 +85acb64140915c940b078478b7d4dadd4d8504cde595e64f60bd6c21e426b4e422608df1ed2dd94709c190e8592c22d7 +b5831c7d7c413278070a4ef1653cec9c4c029ee27a209a6ea0ad09b299309dea70a7aef4ff9c6bdeda87dcda8fa0c318 +aa0e56e3205751b4b8f8fa2b6d68b25121f2b2468df9f1bd4ef55f236b031805a7d9fd6f3bba876c69cdba8c5ea5e05f +b021f5ae4ed50f9b53f66dd326e3f49a96f4314fc7986ace23c1f4be9955ec61d8f7c74961b5fdeabcd0b9bccbf92ce8 +88df439f485c297469e04a1d407e738e4e6ac09a7a0e14e2df66681e562fdb637a996df4b9df4e185faab8914a5cef76 +8e7ae06baa69cb23ca3575205920cb74ac3cda9eb316f4eef7b46e2bff549175a751226d5b5c65fe631a35c3f8e34d61 +99b26ff174418d1efc07dfbed70be8e0cb86ac0cec84e7524677161f519977d9ca3e2bbe76face8fe9016f994dafc0ff +a5f17fe28992be57abd2d2dcaa6f7c085522795bfdf87ba9d762a0070ad4630a42aa1e809801bc9f2a5daf46a03e0c22 +8d673c7934d0e072b9d844994f30c384e55cec8d37ce88d3ad21f8bb1c90ecc770a0eaf2945851e5dab697c3fc2814a9 +a003ed4eb401cfe08d56405442ca572f29728cfff8f682ef4d0e56dd06557750f6a9f28a20c033bc6bbb792cc76cc1a8 +8010408f845cf1185b381fed0e03c53b33b86ea4912426819d431477bd61c534df25b6d3cf40042583543093e5f4bb44 +9021a1ae2eb501134e0f51093c9f9ac7d276d10b14471b14f4a9e386256e8c155bef59973a3d81c38bdab683cd5c10e0 +a5abf269ceabbb1cf0b75d5b9c720a3d230d38f284ed787b6a05145d697a01909662a5b095269996e6fa021849d0f41f +b4b260af0a005220deb2266518d11dbc36d17e59fc7b4780ab20a813f2412ebd568b1f8adc45bf045fcbe0e60c65fd24 +b8c4cb93bedbb75d058269dfccda44ae92fe37b3ab2ef3d95c4a907e1fadf77c3db0fa5869c19843e14b122e01e5c1f4 +ac818f7cdecc7b495779d8d0ff487f23ab36a61d0cf073e11000349747537b5b77044203585a55214bb34f67ef76f2d2 +86215799c25356904611e71271327ca4882f19a889938839c80a30d319ddbe6c0f1dfa9d5523813a096048c4aef338cd +a9204889b9388bf713ca59ea35d288cd692285a34e4aa47f3751453589eb3b03a9cc49a40d82ec2c913c736752d8674d +893aecf973c862c71602ffb9f5ac7bf9c256db36e909c95fe093d871aab2499e7a248f924f72dea604de14abfc00e21c +b8882ee51cfe4acba958fa6f19102aa5471b1fbaf3c00292e474e3e2ec0d5b79af3748b7eea7489b17920ce29efc4139 +8350813d2ec66ef35f1efa6c129e2ebaedc082c5160507bcf04018e170fc0731858ad417a017dadbd9ade78015312e7f +83f6829532be8cd92f3bf1fef264ee5b7466b96e2821d097f56cbb292d605a6fb26cd3a01d4037a3b1681d8143ae54d7 +87d6258777347e4c1428ba3dcbf87fdd5113d5c30cf329e89fa3c9c1d954d031e8acacb4eed9dca8d44507c65e47e7cd +a05669a1e561b1c131b0f70e3d9fc846dc320dc0872334d07347e260d40b2e51fdbabeb0d1ae1fb89fba70af51f25a1a +819925c23fd4d851ea0eecc8c581f4a0047f5449c821d34eccc59a2911f1bd4c319dab6ece19411d028b7fdedece366b +b831b762254afd35364a04966d07b3c97e0b883c27444ff939c2ab1b649dc21ac8915b99dc6903623ed7adaae44870ac +93ec0190f47deffe74179879d3df8113a720423f5ca211d56db9654db20afe10371f3f8ec491d4e166609b9b9a82d0d4 +8f4aa6313719bcfad7ca1ed0af2d2ee10424ea303177466915839f17d2c5df84cc28fcef192cbb91bb696dd383efd3b2 +8d9c9fdf4b8b6a0a702959cf784ad43d550834e5ab2cd3bebede7773c0c755417ad2de7d25b7ff579f377f0800234b44 +99d9427c20752f89049195a91cf85e7082f9150c3b5cb66b267be44c89d41e7cc269a66dacabacadab62f2fa00cc03be +b37709d1aca976cbbf3dc4f08d9c35924d1b8b0f1c465bd92e4c8ff9708e7d045c423183b04a0e0ab4c29efd99ef6f0e +a163f42fb371b138d59c683c2a4db4ca8cbc971ae13f9a9cc39d7f253b7ee46a207b804360e05e8938c73bf3193bab55 +87a037aa558508773fc9a0b9ba18e3d368ffe47dfaf1afacee4748f72e9d3decc2f7c44b7bf0b0268873a9c2ef5fe916 +a1f20cb535cc3aebd6e738491fe3446478f7609d210af56a4004d72500b3ec2236e93446783fe628c9337bcd89c1e8e1 +9757aa358dfbba4f7116da00fe9af97f7ac6d390792ea07682b984aa853379ac525222ac8a83de802859c6dec9182ef7 +815daca1eded189ec7cb7cbc8ad443f38e6ddb3fb1301d1e5a1b02586f1329035209b7c9232dc4dff3fc546cb5ac7835 +aed86dfaf9c4f0a4b2a183f70f9041172002a773482a8ebf3d9d5f97d37ee7c6767badfda15476b3b243931235c7831c +8d032e681e89e41b29f26be02f80030fa888f6967061d2204c1ebb2279a3211d759d187bce6408c6830affa1337fb4e0 +877bff5c2db06116f918a722b26422c920aeade1efa02fa61773fca77f0ea4a7e4ee0ecaaa5cfe98044c0ff91b627588 +b9ee5310d0996a10a242738d846565bdb343a4049a24cd4868db318ea6168a32548efaf4ab84edfbf27ce8aec1be2d1c +b59f6928167323037c6296dd7697846e80a7a4b81320cfae9073ebd2002a03bdf6933e887f33ad83eda8468876c2c4fb +8167686245149dc116a175331c25301e18bb48a6627e2835ae3dd80dd373d029129c50ab2aebeaf2c2ccddc58dcc72ec +82b7dcc29803f916effb67c5ba96a1c067ed8ca43ad0e8d61a510ab067baefd4d6b49e3886b863da2de1d8f2979a4baa +b43824cd6f6872a576d64372dde466fef6decdbb5ad5db55791249fde0a483e4e40c6e1c221e923e096a038fe47dab5e +ab1e9884cf5a8444140cf4a22b9a4311a266db11b392e06c89843ac9d027729fee410560bcd35626fd8de3aad19afc4a +a0dbd92a8d955eb1d24887ca739c639bdee8493506d7344aadb28c929f9eb3b4ebaae6bd7fd9ffe8abb83d0d29091e43 +8352a47a70e343f21b55da541b8c0e35cd88731276a1550d45792c738c4d4d7dc664f447c3933daabd4dbb29bb83be4a +8ce4a1e3c4370346d6f58528a5ef1a85360d964f89e54867ba09c985c1e6c07e710a32cdda8da9fa0e3b26622d866874 +b5e356d67dd70b6f01dd6181611d89f30ea00b179ae1fa42c7eadb0b077fb52b19212b0b9a075ebd6dc62c74050b2d2f +b68f2cd1db8e4ad5efdba3c6eaa60bfcc7b51c2b0ce8bb943a4bc6968995abe8a45fe7f12434e5b0076f148d942786be +b5c7b07f80cd05c0b0840a9f634845928210433b549fb0f84a36c87bf5f7d7eb854736c4083445c952348482a300226a +8cfd9ea5185ff9779dee35efe0252957d6a74693104fb7c2ea989252a1aa99d19abaab76b2d7416eb99145c6fdb89506 +8cc8e2c5c6ddee7ef720052a39cab1ecc5e1d4c5f00fb6989731a23f6d87ac4b055abb47da7202a98c674684d103152a +8c95394c9ed45e1bf1b7cfe93b2694f6a01ff5fed8f6064e673ba3e67551829949f6885963d11860d005e6fabd5ac32c +adf00b86f4a295b607df157f14195d6b51e18e2757778fde0006289fabba8c0a4ab8fad5e3e68ddbb16ccb196cc5973f +b1714b95c4885aac0ee978e6bbabbc9596f92b8858cb953df077511d178527c462cbe1d97fdc898938bae2cd560f7b66 +adf103f4344feb6b9c8104105d64475abc697e5f805e9b08aa874e4953d56605677ef7ff4b0b97987dc47257168ae94d +b0ce6ede9edb272d8769aed7c9c7a7c9df2fb83d31cc16771f13173bcdc209daf2f35887dcca85522d5fdae39f7b8e36 +ad698d1154f7eda04e2e65f66f7fcdb7b0391f248ba37d210a18db75dafd10aedc8a4d6f9299d5b6a77964c58b380126 +904856cd3ecdbb1742239441f92d579beb5616a6e46a953cf2f1dd4a83a147679fc45270dcac3e9e3d346b46ab061757 +b600b5b521af51cdfcb75581e1eccc666a7078d6a7f49f4fdb0d73c9b2dab4ce0ecafcbd71f6dd22636e135c634ee055 +a170c5d31f6657f85078c48c7bbf11687ce032ab2ff4b9b3aee5af742baecf41ea1c2db83bcba00bccc977af7d0c5c8e +a9ef1cbb6a7acb54faf1bcbd4676cdeba36013ca5d1ac1914c3ff353954f42e152b16da2bdf4a7d423b986d62b831974 +aa706d88d3bd2ce9e992547e285788295fd3e2bbf88e329fae91e772248aa68fdfdb52f0b766746a3d7991308c725f47 +911a837dfff2062bae6bcd1fe41032e889eb397e8206cedadf888c9a427a0afe8c88dcb24579be7bfa502a40f6a8c1cc +ae80382929b7a9b6f51fe0439528a7b1a78f97a8565ba8cddb9ee4ba488f2ab710e7923443f8759a10f670087e1292c4 +b8962de382aaa844d45a882ffb7cd0cd1ab2ef073bce510a0d18a119f7a3f9088a7e06d8864a69b13dc2f66840af35ae +954538ffff65191538dca17ec1df5876cb2cd63023ff2665cc3954143e318ece7d14d64548929e939b86038f6c323fc1 +89efa770de15201a41f298020d1d6880c032e3fb8de3690d482843eb859e286acabb1a6dc001c94185494759f47a0c83 +a7a22d95b97c7c07b555764069adaa31b00b6738d853a5da0fe7dc47297d4912a0add87b14fa7db0a087a9de402ea281 +9190d60740c0813ba2ae1a7a1400fa75d6db4d5ce88b4db0626922647f0c50796a4e724e9cc67d635b8a03c5f41978f7 +ab07c30b95477c65f35dc4c56d164e9346d393ad1c2f989326763a4cc04b2cb0386e263007cc5d0125631a09ad3b874c +9398d8e243147de3f70ce60f162c56c6c75f29feb7bc913512420ee3f992e3c3fb964d84ef8de70ef2c118db7d6d7fd5 +b161b15b38cbd581f51ca991d1d897e0710cd6fdf672b9467af612cd26ec30e770c2553469de587af44b17e3d7fea9f7 +8c5d0260b6eb71375c7ad2e243257065e4ea15501190371e9c33721a121c8111e68387db278e8f1a206c0cce478aaa2b +b54ac06a0fb7711d701c0cd25c01ef640e60e3cb669f76e530a97615680905b5c5eac3c653ce6f97ceca2b04f6248e46 +b5c7f76e3ed6dc6c5d45494f851fa1b5eaf3b89adac7c34ad66c730e10488928f6ef0c399c4c26cbeb231e6e0d3d5022 +b6cd90bdd011ac1370a7bbc9c111489da2968d7b50bf1c40330375d1a405c62a31e338e89842fe67982f8165b03480c7 +b0afcaf8d01f5b57cdeb54393f27b27dc81922aa9eaccc411de3b03d920ae7b45295b090ef65685457b1f8045c435587 +b2786c0460e5057f94d346c8ebe194f994f6556ab2904a1d1afd66c0ff36391b56f72ed769dcc58558ee5efaa2ed6785 +965dbb0cb671be339afcb2d6f56e3c386fb5d28536d61d6073b420ee15dee79c205af2f089fbb07514a03c71bf54b4e2 +90f2003e2286bba9cebff3a6791637ca83b6509201c6aed1d47f27097d383d5c2d8532bff9e3541d2c34259841cf26ab +902142d1224e1888ebbfef66aaf8d5b98c27927a00b950753a41d1d28a687a8286b51655da9a60db285b20dc81d5ea89 +a5d364448bf0d0849e5104bdaef9cb2cc8c555f5d6d34239c68671fbe1252f7c8c75b83cea10159dee4da73298f39a12 +b013a54c5b99e296d9419ad5c2aaf4545acd34405e57d13cb764e92132cc20d1a14b33e10caf22d898b608670c04f273 +b92976dceda373331804d48a7847f508cafde8d15949df53dbda09d03908678db1e61ee637baad5f05b2b03ea6f5a870 +968bcb308c7ad0813dc9b3170f23f419aecd7b42176f27fac698811795bf42659fea6b04dab4ef43595dcc990622041b +a9d0a20e9367ea831dccd37f4d97ea75e9aeec952947a7946d95e0d249c94024183ef79a624bdea782469824df0ee4e4 +8521b9667453c3658703e5db365b13f0e0d2331ce611ff1e708f8124d8a81bb5e82871de4a66d45c1a6b0a3901bd901e +b9c88e76e69b0722c0a2f97e57dbc4a6f7456434cd694e2ff67f4e24740cffa4db03e2b18f07f22954ae7db2286e1fa2 +8400e55aa9ab01d4cc0affd611127b5d8d9a9dbd897f3cb8e2050379983aa54249be17d7b7891977b2515bb44a483f65 +8cbb967b4ed31dc40ea06822a94d54cbfc8845c66fbafa3474c8f5fe1ada97299ed4ca955d9d7a39af8821eabf711854 +b4d266ee3fea264a6c563fd6bed46f958c2d7bd328225f6e47faf41a0916aef3b697574322f8b814dfb2f5c242022bf6 +8f7c72d69a919450215ead660ffa9637642c5306354888d549fd4a42e11c649b389f67cc802a0184d10fdb261351140c +a5f9e494ea9b2393ec32c48aac76c04158ccef436d4e70ad930cba20c55fbf61e8f239f70b9d75462405c4b6317c71a1 +b3befb259b52a44a6f44345859e315c20efa48c0c992b0b1621d903164a77667a93f13859790a5e4acb9f3ec6c5a3c6e +b9e4ca259b4ee490d0824207d4d05baf0910d3fe5561ff8b514d8aa5c646417ca76f36ab7c6a9d0fb04c279742f6167a +98fa8c32a39092edb3c2c65c811d2a553931010ccb18d2124d5b96debd8b637d42b8a80111289f2079d9ebca2131a6dc +a65e5aa4631ab168b0954e404006ce05ac088fd3d8692d48af2de5fd47edbf306c80e1c7529697754dbbba1b54164ba0 +b94b7d37e4d970b4bb67bf324ebf80961a1b5a1fa7d9531286ab81a71d6c5f79886f8ef59d38ae35b518a10ed8176dcc +b5ed2f4b0a9ae9ace2e8f6a7fd6560d17c90ae11a74fa8bef2c6c0e38bfd2b9dd2984480633bca276cb73137467e2ce3 +a18556fe291d87a2358e804ee62ddff2c1d53569858b8ae9b4949d117e3bfb4aefce1950be8b6545277f112bebeeb93d +a0d60b9def5d3c05856dff874b4b66ec6e6f0a55c7b33060cc26206c266017cdcf79b1d6f6be93ed7005a932f9c6a0b9 +801fced58a3537c69c232ce846b7517efd958e57c4d7cd262dbec9038d71246dafad124aa48e47fe84ecc786433747c7 +a5e9a8ea302524323aa64a7c26274f08d497df3d570676ecc86bd753c96a487a650389a85f0bc8f5ea94fe6819dc14e5 +a8a2963dc9238a268045d103db101adc3b2f3ab4651b7703b2fe40ece06f66bf60af91369c712aa176df6ed3d64a82fa +a4a8ff0a9a98442357bcdd9a44665919c5d9da6a7d7d21ccdbbd8f3079b1e01125af054b43b37fc303941d0a2e7baee0 +90ef893350f50d6f61ee13dfab6e3121f4a06a1908a707b5f0036cdc2fe483614de3b1445df663934036784342b0106f +84e74d5bc40aaab2cc1d52946b7e06781fbef9d8de6f8b50cd74955d6bdb724864c0e31d5ac57bf271a521db6a352bd6 +832cdf653bbbd128e2e36e7360354a9e82813737c8ab194303d76667a27aa95252756c1514b9e4257db1875f70f73eb4 +a0af8660ed32e6dbcc4d5d21b0a79a25ff49394224f14e6e47604cf3b00136de8f9ab92e82814a595bf65340271c16c3 +9040b5caf5e4dc4118572a2df6176716b5b79d510877bbb4a1211b046596899ea193be4d889e11e464ffb445ab71907b +b9bf8354c70238ab084b028f59e379b8a65c21604034d1b8c9b975f35a476e3c0ba09dd25bf95c5d8ffb25832537319b +a7b492cc1df2a8f62c935d49770d5078586bd0fefda262eb5622033e867e0b9dc0ffc2ce61cd678136a3878d4cbb2b56 +95a5ef06f38743bba187a7a977023b1d9d5ec9ef95ba4343ad149a7b8b0db0e8e528bfb268dc7e5c708bc614dc3d02c8 +99dcf7f123df6c55aeff0a20885a73e84d861ec95cf9208ba90494f37a2dcaacebc8344f392547d3046616d9753c7217 +b3e14f309281a3685ceb14f8921c1e021b7e93c9e9595596b9fb627e60d09ed9e5534733fcbdf2fbc8c981698f5e62ac +816a5e0463074f8c7fb2998e0f0cf89b55790bdbbb573715f6268afb0492453bd640dd07a9953d0400169d555fdf4ac8 +8356d68f3fe7e02a751f579813bd888c9f4edcc568142307d1c9259caef692800e1581d14225e3a3585dac667928fa94 +8d70ea3314c91bfc3f7c1dcf08328ae96f857d98c6aac12ad9eebc2f77e514afdbaf728dfcb192ed29e7ce9a0623ecbb +b68280e7f62ced834b55bc2fcc38d9ea0b1fbcd67cc1682622231894d707c51478ed5edf657d68e0b1b734d9f814b731 +b712dd539e1d79a6222328615d548612eab564ace9737d0249aa2eefed556bbcf3101eba35a8d429d4a5f9828c2ac1fe +8da42ca096419f267f0680fd3067a5dbb790bc815606800ae87fe0263cae47c29a9a1d8233b19fe89f8cc8df6f64697e +8cb2ffd647e07a6754b606bde29582c0665ac4dde30ebdda0144d3479998948dae9eb0f65f82a6c5630210449fbd59f7 +8064c3ef96c8e04398d49e665d6de714de6ee0fced836695baa2aa31139373fad63a7fc3d40600d69799c9df1374a791 +aec99bea8ab4e6d4b246c364b5edc27631c0acc619687941d83fa5ba087dd41f8eaec024c7e5c97cf83b141b6fb135da +8db6051f48901308b08bb1feb8fd2bceaedde560548e79223bd87e485ea45d28c6dcec58030537406ed2b7a9e94e60cc +a5b812c92d0081833dcf9e54f2e1979a919b01302535d10b03b779330c6d25d2de1f374b77fe357db65d24f9cbcd5572 +967d442485c44cf94971d035040e090c98264e3348f55deabd9b48366ec8fe0d5a52e4b2c9a96780a94fc1340338484e +a4b4110bef27f55d70f2765fc3f83c5ddcdfe7f8c341ea9d7c5bcee2f6341bcfbf7b170b52e51480e9b5509f3b52048f +a0d39e4eb013da967a6ac808625122a1c69bf589e3855482dedb6847bb78adc0c8366612c1886d485b31cda7304ec987 +a92f756b44d44b4e22ad265b688b13c9358114557489b8fb0d9720a35e1773b3f0fa7805ac59b35d119a57fe0f596692 +aa27e4b979af6742b49db8bf73c064afd83a9cfe9016131a10381f35a46169e8cfd1a466f295fcc432c217c7c9fa44a5 +845961319cc10bcfbb1f3cb414a5c6a6d008fb3aac42c7d5d74e892cc998af97bc9a9120c3f794e4078135e16a416e38 +a18dbe3015c26ae3e95034c01d7898e3c884d49cc82e71ddb2cf89d11cec34cc2a3dff0fafb464e8e59b82ce1a0a7a11 +a954aed6d7124fa5bd5074bd65be4d28547a665fb4fe5a31c75a5313b77d1c6fc3c978e24c9591a2774f97f76632bdde +8f983b2da584bdff598fcb83c4caa367b4542f4417cc9fa05265ff11d6e12143c384b4398d3745a2d826235c72186a79 +b2caa17d434982d8dd59a9427307dfe4416b0efc8df627dd5fc20d2c11046c93461d669cab2862c094eec6a9845990c6 +8c2baa5a97ee3154cce9fa24f6b54b23e9d073e222220fdd0e83e210c0058fb45ce844382828b0cb21438cf4cad76ee6 +b93437406e4755ccf1de89f5cbe89e939490a2a5cf1585d4363c21ae35b986cb0b981dec02be2940b4ec429cc7a64d4c +a90ac36c97b7ea2eddb65e98e0d08a61e5253019eeb138b9f68f82bb61cdbadf06245b9dfffe851dfa3aa0667c6ac4b8 +8bcdd7b92f43b721ddbfd7596e104bc30b8b43bdaee098aac11222903c37f860df29d888a44aa19f6041da8400ddd062 +98f62d96bdf4e93ed25b2184598081f77732795b06b3041515aa95ffda18eb2af5da1db0e7cfed3899143e4a5d5e7d6c +ad541e3d7f24e4546b4ae1160c1c359f531099dab4be3c077e446c82cb41b9e20b35fa7569798a9f72c1fae312b140b4 +8844a1471ff3f868c6465459a5e0f2fb4d93c65021641760f1bb84f792b151bc04b5a0421bbc72cf978e038edc046b8f +af895aebe27f8357ae6d991c2841572c2063b8d0b05a2a35e51d9b58944c425c764f45a3f3b13f50b1b1f3d9025e52ad +adf85265bb8ee7fead68d676a8301129a6b4984149f0eb4701eae82ec50120ddad657d8798af533e2295877309366e9c +962e157fe343d7296b45f88d9495d2e5481e05ea44ca7661c1fdf8cc0ac87c403753ca81101c1294f248e09089c090eb +a7c8959548c7ae2338b083172fee07543dc14b25860538b48c76ef98ab8f2f126ecb53f8576b8a2b5813ecb152867f18 +ae71680366e11471e1c9a0bc7ea3095bc4d6ceb6cf15b51f1b6061b043f6d5941c9f869be7cb5513e8450dca16df2547 +831290201f42ebf21f611ca769477b767cf0ee58d549fcd9e993fae39d07745813c5ce66afa61b55bb5b4664f400ece7 +af5879e992f86de4787f1bc6decbc4de7d340367b420a99a6c34ac4650d2a40cbe1cef5c6470fc6c72de8ee1fe6bcce4 +8d3c27e1b2ef88d76ac0b1441d327567c761962779c8b1f746e3c976acb63b21d03e5e76589ce9bb0d9ba6e849ed3d53 +ab23b09c9f4151e22654d43c1523f009623b01fe1953d343107cef38b95bd10afd898964946d3cb8521bcbe893e1c84d +8a6acade9520e7a8c07f33d60a87fd53faa6fbf7f018735bffcbbb757c3bafb26f547ceb68e7b8b6bca74819bfcd521a +94db50080d557440a46b6b45ee8083bc90e9267d40489040cbed6234bebf350c788ec51557b969f95194102fde8e9713 +8be8031f32504e0c44958d893649f76cec17af79efcd22bbedb78378f0a150845467e59f79a3f2a3b6a66bdf0d71d13c +a69a4ac47fd92e1926b5e14adcbebbef049848e8a00d4bb387340892e5a9333cae512f447201728d3b53c6cf980a5fdc +8fc713825277c5a8d9ef0a1f6219d141def6d8b30aff0d901026280a17d1265d563ff5192a0817e0e1a04ff447fb6643 +8bf0a85569c4f0770ff09db30b8b2ea6c687630c7801302c17986c69a57c30f0781d14b3f98a10b50c4ecebc16a5b5ec +896baa4135d5621fd6b6a19c6d20b47415923c6e10f76c03a8879fd8354e853b0b98993aa44e334623d60166ba3e3ca9 +b82cde1c2e75a519ef727b17f1e76f4a858857261be9d866a4429d9facf9ea71d16b8af53c26bde34739fe6ea99edc73 +b1a9e1f2e34895a7c5711b983220580589713306837c14073d952fe2aef0297135de0be4b25cbfaed5e2566727fb32ef +b42ed0e9eaf02312d1dba19a044702038cf72d02944d3018960077effc6da86c5753036a85d93cd7233671f03d78d49a +a402e34849e911dbf0981328b9fe6fff834c1b8683591efd3b85aa7d249811d6b460a534d95e7a96fdd7f821a201c2c4 +a774417470c1532f39923d499566af762fa176c9d533767efd457cc5e4a27f60e9217f4b84a9343ecb133d9a9aab96b7 +83dc340541b9ef2eb8394d957cd07b996d2b52ac6eb5562cbba8f1a3312f941c424c12d1341a6dc19d18d289c681ef40 +b2906c32d5756b5712e45dec53782494a81e80f887c6e1ef76e79c737625eccecb8fd17b20e6f84890d322b6ffde6eab +b89705c30cec4d50691bc9f4d461c902d6a4d147cf75ee2f1c542ad73e5f0dabe3d04cd41c6c04ab1422be4134cf1ad7 +8c3293651f4c4fac688bf5837c208b15e5a19ce51b20dd80ffc7fca12d3e615b2773cfc3ed62a1b39c66808a116bde06 +8fceb8ef481163527d1fc3abc7e1a5b3b6de2f654c3fe116d1367b177dcba2e0d2124a7216803513a3d53fc1e30435b9 +b2a42c827da630aaa3eb20ed07d136aa11ba01b4c8efc0a57ebab7d5b851a15daa6ba118bcffbc20703916e430e30a87 +a86340153abb3fe97414e2fde857e15aac27c9bb9b61258eea6766024f426ed0753f08f07f6b02b5375e1587ea3afcab +b006465e258e646f91ba889765113d3dc9bd657246c533cab6516d55ba054baa9d7276a3b0fa31730c3bd824845bf107 +a08aadc09428719cde0050d064c0f42c5b7c4f6c158227d7636f870957d6cfe821b4c62d39279a7c98f5a75fcb7bbfba +885e7d47ce9b50d21b95116be195be25f15223a6a189387575cc76740174c3e9044f1196986d82856b3fb25cdd562049 +b18c3780362d822cc06910743c4cbcef044823a22d12987fe2e56f3801e417f2e9cd31574ea1c5c6ee7673a14aa56e3e +a625570ef7d31c042d968018865aeeba34ee65a059ab1ec079c7a8ba1be9e24bce6afb7036c07d9d6c96ab014f95d661 +8fc9bd4764adc4c300b5bd49a06dce885d1d8aff9bae68a47976d0cd42110aa6afa2d7b90b64e81c0f14de729f2fb851 +91d88714cb669f5f00241aa5ab80dffb04109492ea9c72b59645eb1f85f3539c61db2ab418af986f42241df8b35445e9 +b98f14e664df2590dd2d00b5b5c817e388e5d9fb074f718637c33b3d4969c89e82fdd12db8997f5ff3bf5bb5ca5dd839 +86cb3d9f148cb2170317a4c22af7092155aa66ecff7ab1299b102fbbaa33ed2a284b97b08f529d2da9faea63fb98972c +92449f6b8a7c737ecef291c947cbd602c47d7fe47dc3426c2b413f3019169aa56e14c2a7216adce713e1c7bd5c08a83f +b08c1b9080bba88b44a65070948142d73c00730715fbdd01e13fc3415c5b4f3248ef514fa3ade4a918c9a820cccae97c +b0a05297da76e37c22be7383e60bba1cbc4f98ba650e12d4afcfcea569842003644a10ad73c9148958f7bf1ffa0a27d0 +839092c1f4e9fb1ec0dde8176f013b0d706ab275079f00f8e774287dd658d1b5638d5fe206f5f2a141911a74bb120f75 +a36bd669bdc055ece4b17ff6eac4c60a2f23324a5eb6d0d6c16a2fce44c39cfd52d1fa2b67f3f5e83504e36426fbfc40 +8aa428323512cf769645e2913a72976d32da4c0062ffe468a6062fd009340f0f23c6b63285848a0e7631a907adb032a0 +944800f7d43f41283eb56115ac39ccc5bf107ae5db6abcaba6936b896260cd09428a6b828c0bccebeb00541073dbf38e +8e700ca7c9e1538cf64e161dd8d16af56fc29d53c79648150d6d8c268b0c95c76acded723e29918690d66252bd75f5b3 +b9c4ce35b5b16b4c39b6e85800c76b26e8d0999500fabc1e5b6234a7f8da18c621266ac0d5ebc085354297ff21ac89a5 +a0c706d32063f1877f7e903048ce885f5d012008d4a8019dd00261a8bbc30834bffeba56cdeddc59167d54cc9e65f8fa +839813b736225087cbbcf24506ea7bf69138605036b764ec0514055ac174bbc67c786a405708eb39a6c14c8d7e0ec6ee +b1a5fef055a7e921c664f1a6d3cb8b21943c89b7e61524a307d8e45aa432e5765a27c32efdb32d88062cd80800a260de +b17f8202d9ed42f0f5cb1b1dbda60711de3b917a77f6069546fa3f86d21f372b8dd5cb86f1994b873ba9982404e08daf +b5211d54bd02d44d4d808ad57067606f3e9fa2cad244a5f2acef0edf82de3c496d2b800f7c05f175d01fa6ace28b44d1 +aa9c6f8f489b35fdb7544116fe5102a34ff542de29262f156df4db4ea6e064f5ea20c4bd877d40377ed5d58114b68f19 +826668b1f32e85844ff85dd7e2a8e7f4e0fd349162428bc9d91626b5ab21bdbacd1c9e30cf16f5809b8bf5da4f4fe364 +b30d14917b49437f9fdbae13d50aee3d8a18da3a7f247b39e5d3e975c60bd269da32da4e4cc8844666fca0d65f4e3640 +8c6918d8d94b36c6b9e772e9a432e66df16724e3b0660bde5ea397e6ef88028bb7d26184fbe266a1e86aef4a0dfe5faa +906d80ffd692c1dd03ab89be52e0a5a9e90a9cdbfc523d2b99c138ae81f45d24c34703f9cb5a666b67416e3bb6272bc4 +8b07e8ba22b436e64f011cacf5e89c55cd3bfb72ae8b32a3a8922c4fccb29de6f73662d6e330da6aa6e732a2187ef3c9 +9547466b4553a49adf59cc65d4c3c9401b2178947ebe3bd33c6e63cfb67d6be8729033158594f6f244b272c4487d6958 +aafcccea41e05cb47223fa8dfec0dd55964268bd4d05e24469614077668655ac8a51d2ac2bfb22862f8f4fa817048c2f +870f8c1173e8fd365b0a2e55c66eea3ab55355990c311f3042377803d37e68d712edcc5a0a2e2f5a46df0c1c8e6310c2 +b4288f792008f342935f18d8d9447fe4ddcfea350566e13dba451f58c68e27241af1367f2603a9dff6748e7fe0c53de4 +91c58c0e537d3afdcf7783601dd9cda2aa9956e11f711b15403760cf15fc6dffb40ed643886854571da8c0f84e17adfe +a43fec8ee92febed32e7cdd4e6314a62d9d3052c7a9504057dfba6c71fdfbeff1cef945d8f087bd106b5bec7478ad51f +99cf5e0e3593a92f2ec12eb71d00eccec3eec8662333471b2cb3a7826b7daca2c4d57ffba18299189cf7364e2af5df6d +af50f9ab890b7517ff1f1194c5b3b6f7f82eabc607687a8380be371a6a67b117aeb9b6f725556551b81f8117971706a2 +aa352430887053602a54403bd0d24d6b5181b44aa976dfa190e21851699a88127dcc904c90a48ec44610056b5dcd36c4 +964c821ea1902354736fa382a929c156bd67b9468d6920d47c27b9d0d304b6144118888d124c1f6785da596435ed2410 +b2284a67af26b5f5aff87b4d8e12c78ab37c5eb6e92718fca8549f86f4f001b660fc4520456aff72c9bcddd686603942 +83c54cbb997ea493dc75df4023071dce6da94268feaa2352373789616f012098270ba4fd60c791796a6f5062fb2cd35e +9143e8fee0b8f0f34c65c7750858093dcf165c6a83c026bfac2d5ffa746361eb4b6a14fdb43e403add901ac3735735a3 +97d7748a5b278ee47b18c9e60689b12a0a05be47e58e78bf8c04b9e8b34e2e2f2d3ac3c25c76ab2e0a75e8a54777b7c8 +b4e68f6f2d978a5411414c164c81ddb2a141b01ebe18c65a8626ca75d6432e5988310b50a888a78c3a0a242353525af5 +8976f4cc3eaf2684718cf584712c4adaf00a4d9c521f395f937e13233b30329658b3deacfe7e29fac84c496047f2d36b +a40bcdf4b6e95f1535c88dddcbf2074ef2e746b7fd232bdfd2b88f2f6d4bbf21c6b263cf5fd3e12a03476f2f5ffe00d2 +88c7b6337ee705acd8358ef6d2242d36b140afff0579a7784b3928a0c49698bd39c1f400e8a2e3eda5fbfb2e8f28fe51 +a98612ba8b450a71d2075d51617ebeb7ca401ad3cbd9b8554850c65ef4f093ba78defb00638428c9f1f6f850d619287f +b7e71d3ffa18b185c1a6bd75668ff65d985efc0a0c19f3812cafde9adbfb59ffd108abeb376e6a8877fdf5061562f82b +8a3e5fd776cc26908a108a22b1b122d60cb8c4f483cbedcd8af78a85217bb5a887df3efed2b8b4ec66e68eb02a56ca93 +b0d92b28b169d9422c75f9d5cb0a701e2e47b051e4eacd2fd1aa46e25581a711c16caf32f40de7c7721f5bf19f48b3f5 +88895739d5152282f23e5909cf4beebda0425116eb45fc5a6a162e19207686d164506c53b745fb2e051bb493f6dbad74 +adbccfed12085cd3930bd97534980888ee564dda49e510c4e3ca0c088894855ef6178d5b060bca8a8a1a427afdbec8a8 +87d00674abd3d2e7047a07ed82d887e1d8b8155635887f232dd50d6a0de3fb8e45b80b5a05bc2ec0dea9497b4aa783ac +806e1d3dfadd91cbf10e0d6a5e61738d0dbff83407b523720dce8f21f8468b8a3fc8102acf6ba3cf632ca1cb2af54675 +95a9dff67cf30e993071edede12623d60031fa684dfbe1654f278a1eb1eb7e1be47886d3f8a46c29b032da3176c0d857 +9721973288384c70a9b191436029e85be57970ad001717edc76d44cbfa0dff74f8af61d5279c5cd5c92c9d0f6c793f63 +95c22d1d9b51ef36ba30ee059dcd61d22be3c65f245d0a5179186874219c08e1a4266f687fc973e71f3e33df2b0f7fd3 +b53ec083dd12cc42ae2bae46883a71f2a35443c9ce4ed43aa341eb5f616a53b64211ed5aac717fe09ef1d50f551ed9f0 +a103dab6695c682400f60be8d5851ce07f12e4bd9f454d83b39c41ddcf1443bb14c719b00b4da477a03f341aa1e920cb +b522236988518e5363b1c4bb3f641ff91d3d4c4d64c5f065415b738160b4ce4b0c22e1e054a876aa6c6a52fa4a21dfa2 +a6a00562f0879702cdba5befd256a09f44bf48e61780e0677ff8c3fda81d8e6dc76ba1b05e3494ca9a4cef057eba6610 +b974a2ae631e0b348421f0cda5bd4ce7d73c22dd0fc30404c28852c33499818cab89fbf5c95436d56a0aab3bf2bbab51 +9148cf2a7b7e773245d4df5a9d34cf6d9d42b1a26a4ca6bc3013feca6f3941d6c44f29ba9328b7fe6ce6d7f6565f8e4a +a34035c4a63e98528a135cc53bbbcfcda75572bc4c765f212507f33ac1a4f55563c1a2991624f7133c77b748bbe1a6da +a0c45923cfb7bd272ee113aecb21ae8c94dda7ad1fe051ddb37ab13d3bb7da5d52d86fff9f807273476c24f606a21521 +81ec2ca57f4e7d47897d0c5b232c59d7b56fe9ce0a204be28256a7472808de93d99b43c824a0cd26391e6cac59171daa +8373852f14a3366d46c7a4fc470199f4eebe8ee40379bd5aae36e9dd3336decaead2a284975ba8c84d08236e6b87c369 +b47e878a93779f71773af471ba372cb998f43baca1ae85ea7ff1b93a4dee9327e2fb79691c468ec6e61ab0eae7ceb9f1 +8fc8f260f74303f26360464cfef5ee7eebcbb06073cef3b1b71dab806d7c22f6b3244ce21d0945b35c41f032f7929683 +87e3c4e1dab00596e051ce780b9a8dba02ecdc358f6ddaeb4ec03c326e4b7da248404745392658eb1defff75b1ba25c8 +aac95d8e3b7fe236a7ca347d12a13ec33073f2b2b5a220ecfd1986ca5c3889f0e6a9d9c377a721949aa8991c1821953a +91a483679437ae126a16f5dc3bba6e9bb199dfbba417f0dc479f22819b018c420edc79b602db6183c6591b1909df4488 +94a4b2c663aa87a2417cad4daf21a88b84983a7b212ffcd18048a297b98e07dd4c059617136976fac1d9e94c8c25b8d2 +83e2a690bfa93c79f878a63c0f69f57aabdd8bede16b5966ffba7903dc6ad76775df1fd5347e6f2825f6cd7640f45a45 +a316af7ac11b7780d15312dc729499a1a63b61c4283e103ecce43c3b0cbb0f4bce6ff04e403f5c7cb670dee80c75ab99 +8d0a911c54ee1f9f7e7794732ad87b434c3f356294d196a5e35eac871727fd32a49c27c2dfa10833f9e6f9c7ccbe0064 +8b8db09028298a1f6362b346c8bfeced7cb5d13165a67c0559a9798a95b7a4a9810c02bb852289d47c59f507bd24ce77 +962d57305c518f175ed5d0847fb52ddc4258ca0e4c9ddfc8c333a2ee9f8b4e48d25a3d7e644b785a5953e2e4063da224 +92e0799491898271769250fe88b0cb9dadec98ac92f79de58c418d23ef8c47fcf21ddc90e0cd68bb8f1deb5da82da183 +99855067125f6a6c3a3e58d3bd2700a73ef558926bd8320d2c805a68e94207b63eda6bdc5a925ec36556045900802d51 +a724ae105ab4364a17ddb43d93da1e3fc6b50213f99b7be60954b24dc375c4f93a0737f4a10b4499b6f52667d5f3a64e +82070fb43a63fb50869b118f8940108f0a3e4cc5e4618948417e5cc3801996f2c869d22f90ca4ca1fdbef83c4778421a +b25c04365d6f24d5d3296c10d85a5de87d52a139ddbcbf9e0142074bc18b63a8bc5f5d135bd1e06c111702a4db4cee28 +851093282dcda93e5c98d687a17a7ee828cf868f6c85d372d9ae87f55d0593d8f9f0c273d31f7afa031cf6aea6a7ef93 +93f04f086fa48578210ed207065d80a40abcc82d8bfc99386a4044561d35748ff6c3da6489933c23644ad4b60726da8a +84b1b50d1e876ca5fc341bbedab5b3cc0f6a3f43ea7dd72605f74d0d9c781297b2f12b7872dd600924f1659a4cdf8089 +81b0ba88c582d3956f6b49ca3e031c6400f2ec7e1cd73684f380f608101e9807f54866be0bb9a09c03953c4c74fbb3c8 +a641af6ac644c41a55dee2ef55d3c37abdb19d52bc1835d88e7adda6b6ccd13987c5fd9cba9d318cabb541aa6a0c652e +a7b75b0624d04ad0901070e691eb2d2645b60f87e9d6b26e77a5fb843f846c32fc26e76ae93fd33fe3b857f87bc25162 +a81ba3e2ed0f94c67cd02ba7360e134f8becf7ed2ed2db09b9f5ef0942f7073bfee74ca446067db6092f7b38f74ccc11 +ab80edcabab5830a24210420f880ebac4e41bf7650c11ba230f4889634dbf8e8e2309f36be892b071c67a3bab8fc7ed6 +94d69b64675076fecad40fae4887fb13a8b991b325fa84e9d2d66e3b57646de71a58ad8fd8700fefb46975b18289250b +b44fc0df480cd753a041620fa655be9df74963ae03d4625847d5bb025ceb37f48d19c8c9c444546fba5fe5abb2868506 +b56e2c51324d6200b3d9781b68b5b5e1617a68afccd28b3a12a4be498d2e3aafcd86514c373a9f3a001db733010c29cf +a359a0c172e5cd7ce25080dd2652d863d7c95a4a502ae277ac47f613be5991300f05978404a0acb3bcda93524dcf36e4 +b01427a3dfdf8888727c0c9b01590b8ae372b7b4080d61e17ccb581bac21e61c4a58c75db7a410d1b2a367304e1e4943 +95cb08be4a96c18fbf9d32a4bbf632242029d039a5fdea811488d3634cd86520d4f9806250a8c01855ee2481210f542a +b8594fe6c0717164058f08aedeed1853523f56cec5edbf0d2be271fa5e8bfd61f2974b0f3988d70f5baa2e7888c7ec1f +8f64ee89f59daf74fa1056803247c9d678783ee3917b12a201f30f7523957763e979ceaddb38bae20de40b9885728049 +b6093ee4bdb837bcc59172e236f4bdbd439c0a5a50e2aa16636cbff81b51e92989eb5f80a3f75c37ae7b5b942e55b3d2 +913b6fbb7b43e3e5c49e96cd8e82ed25c655e51c7b8ca82e8fbf92b01ac83c39d52f6f4efab5d39b0591a0538601a86f +81f42668479ca0bec589678dc0973bf716b632578690efe1a0f13de630f306fb4a189a98c2302572fd85d3877ee030b5 +90ff89c38a9a7189f28d35a088657f52283670e7fec842fa91c265660ea2e73b0ad6c46703d649f406f787490b7a7e4b +9077b8b5f1e083183f3152ceb9c5491b5d4b86525a08879f7fb6d5e27f9f1a6867cf0d81b669a4a2d1f1654b67fa8d9c +a7a0275cf5b894adbf2e54a972310cfe113e811872111d6ee497d03750d9f6ffa5517b6c13a99b111a4a91e8e4dfeeee +a08976bf8125b7538313a584bbe710741d630cab067a204ad4501cc4938874ce7aa6a1a826259c2e82ef10a66f1f36fa +8aa45385b5b97f1f3e45f2bbf7a4f3e8ef068e628608484971c97adeb610ebd5deec31317e03eb6536808921062c04db +945b106b8f3ae85e60dfd34ef3dcc079bc6f0aab6df279ed000856efd51321462038ac0a1ca5db3ebf6379bc341e7c55 +a4199c87a96f98cc9d8776fe6de131d2c706b481eb9e9a3bbc50a93d492d7fd724ea469f723fbcfb94920cb5b32c1d76 +a5347b1b2f6149805de67546c5ed72253311099bf1473dbc63edcf14a0a5e68d401f5341338623fbe2e2715b8257e386 +af5dcd03ddc3769e83351d6b958d47a06d4e5224bd5b0ec40ffe6b319763fab8572002f4da294a9673d47762fd0e6e1d +82ec1031b7430419d83b3eea10a4af4c7027f32b91c3ae723de043233b4a2e0c022c9e0f5a1ac49753800f119159112d +8a744d911b67d03b69811f72e9b40d77084547e4da5c05ff33893468b029a08266fc07303f7005fd6099683ca42b3db4 +93ab566bd62d3439b8fc620f3313ef0d4cb369f0f0c352cdaf8e5c9e50b9950ac3540b72f4bf5adcb9635f9f7ce74219 +b2a211d72e314799bc2ac7030b8bbb8ef4c38ebd0ebb09d6cbd43bd40c6c61d80a3aad02cc73f5775a08b9657da20a48 +98d60f0a98d28718e0c6dcccc35a53521ea7f2d8fe08ea474374a336b44cea4cd1c63b31f2ad10186822bfb54aca53e6 +831f89cb94627cfe554d46ae1aad8c1cde7ebe86c4bd8fac4ef73ac2d5b491f5efa5dc4198cb8ffbec563e0606b91d89 +8f8552583bc6cb3fb176b7202236ee4128faf0c8ec608f9150f8e011d8c80b42aab5242c434d622b6d43510eaef752c0 +897bf27baaee0f9a8445200c3d688ae04789c380d1b795557841606a2031092328eb4c47fef31c27fdd64ba841d9d691 +b57589a4af8184b4a8ceb6d8657a35522672229b91692c1cec3ac632951e707922a00086d55d7550d699c4828bcfaab1 +98c2fe98095e026aa34074bcff1215e5a8595076167b6023311176e1c314b92b5a6d5faa9599d28fca286fadd4e3b26c +a034992e563bd31ede3360efd9987ecddc289bc31046aa8680903bb82345724805e6f6cf30f7889b6b95cf7319c3aea1 +85c33d9f10cc7185f54d53c24095e621966065e0ff2689a9aa6bb3d63706796c37a95021738df990c2c19493c0d44b64 +a8c1247d6de2215f45b50dd2dc24945ff9b93184bcc2159b69703b0bba246adcd1a70a12659f34c4ca4ba27dea6e3df5 +83ebdad2834c97bf92aac8717bab2f5cb1f01026b964d78e2f3b44e99d7908e419165b345d2b2f125b903096584e6683 +b0af6f7f81780ceb6e70adfd98e7702ec930c8ca854b50704c4a0fc8b887b9df60a6fe9038b487f3ed0eb8eb457307ea +933ec7e53882453898617f842ab2efae4756eb6f6ea0161cced5b62a0cdde4c08c7700d52f7546d4dd11a4c9e25d624e +adf6e6d4706025f85eb734f506dde66459c9537a1abf6189199cf219ae583b461e11c6242fce5f0795e4d9025270fabf +89e4316319483098761b0b065df4cfb542963b7a2556ba5425b6442fb0e596eb2a4f03e2dc8c617eebe8f243a12e7d10 +90c5a147555759ebc4d0e15e957a548315f9994ef0c7a3f53f2d18da44fb93bf051d96ba8551597a6f3e701b926fd791 +a151a9a5199c72c697b771cd81e550fc6f9596c752ae686ad988b316a7548360cf9785ab4645164d96cfdf9069a94020 +80cba11a3977729d7948db5bcc186159f4cae7c0a835bb38bb781e287dd6c238508e748f23454405c9d5eed28e77df02 +ae4b92ea03cb8ad12ad3ec76869ad05acb09f9d07a3c9a87dec0e50d9a276fe5d3d515a8c446f3aa35cd7d340a22c369 +8630062709a1f180f952de9f1ca3f41acce5420677f43d9619097e905a6237f1908d66db7a4dfdf1b2b92fb087e9944f +81defc33dd383d984c902c014424bddd5e53b013f67f791a919446daa103b09b972fa5242aba1b1dbe4a93149373f6c3 +963891ecaea97e661bac2594642327a54f5a0beb38fcb1c642c44b0b61faab9c87b0c9f544a3369171b533d3ab22f8f1 +932fadbff5f922ddcd4da942d57fe3e6da45c3d230808d800a3ca55f39b0b62f159be31a5924b395d577a259f48c6400 +992ce13bd037723447f88aeb6c7722fd9510c7474192b174ea914ed57c195c44c298aec9a8cabac103f0a5b50051c70b +b032157b3e4fe69db6ce6bb10bdf706a853fbd0bee08c2ab89da51ad827425df5df498b90e7a30247a7f9e954ca986e5 +b2478d4874578da3d5000893736bb65712e6aafe96e6fa5cf5878ae59ba0ce640dbe5d76ec2b5baca75af57def471719 +a387c17b14dd54910fecf472f760e67cf71a95e9e965cc09484e19581ada65e79938b86136a93e287e615fbd4908e080 +98f02be271d0f8841d8d561163f9e55e99b57aff121a93fba7a4654bcf15a0899811f00f5bcbfbebd98e365a0e332e97 +a3c34f01d54cab52a8890391b8cf152cc9cdc16e7e53794ed11aa7b1a21e9a84d39ddcfbcb36c5df6891c12307efc2e0 +a940331f491ec7ad4a9236ca581b280688d7015eb839ee6a64415827693d82d01710dc4bbd5352396be22781fea7a900 +b10874ed88423731535094031c40c4b82af407160dfade4229ac8f4ef09d57b3db95c4a9d73c1a35704f6bd0d5f6c561 +a9c5a4a7680261c1b0596f8ab631d73d4a7881b01e6559c628b5cdafa6dd2b6db2db64f3f2ab5841413a8a52b966a0da +8fc154564a61d5e799badc98b43a3587f804385a850adce9a115cbd2ad911f3fd4072b8e6b22fc6c025a6b7e7ea5a49f +b9caf7c6dcce3d378aa62c182b50bc9c6f651eb791d20fffa37ef4c9925962335fe0b3bc90190539312aa9ccf596b3b9 +90c5b7acf5cb37596d1f64fc91dee90f625f4219fa05e03e29aebea416c8e13384f2996f8d56791bcf44ae67dc808945 +ab8d311fc78f8a1b98830555a447c230c03981f59089e3d8a73069d402a3c7485abe3db82faf6304aaca488a12dbe921 +8a74fda6100c1f8810a8cacc41b62875dd46d5c4a869e3db46202d45a8d9c733b9299dda17ce2ad3e159122412a29372 +8769dcacba90e6fc8cab8592f996c95a9991a3efecfb8646555f93c8e208af9b57cf15569e1d6e603edac0148a94eb87 +854fd65eea71247df6963499bafc7d0e4e9649f970716d5c02fbd8708346dcde878253febb5797a0690bd45a2779fa04 +83e12dc75ef79fd4cc0c89c99d2dace612956723fb2e888432ec15b858545f94c16fae6230561458ceee658738db55ba +8416ef9ac4e93deff8a571f10ed05588bef96a379a4bdcc1d4b31891a922951fa9580e032610ac1bb694f01cb78e099b +93aea6e5561c9470b69d6a3a1801c7eef59d792d2795a428970185c0d59b883ab12e5e30612d5b6cde60323d8b6a4619 +91d383035aa4ec3d71e84675be54f763f03427d26c83afb229f9a59e748fb1919a81aca9c049f2f2b69c17207b0fb410 +b1c438956f015aef0d89304beb1477a82aed7b01703c89372b0e6f114c1d6e02a1b90d961b4acbb411cd730e8cacc022 +a1ee864a62ca6007681d1f859d868e0bcd9e0d27d1da220a983106dc695cb440980cfdb286e31768b0324b39ae797f18 +b57881eba0712599d588258ceada1f9e59c246cc38959747d86e5a286d5780d72d09e77fd1284614122e73da30d5cf5c +a48f9ae05ba0e3a506ba2e8bbce0d04e10c9238fa3dffa273ef3ffe9ec2ed929198a46507c0c9d9b54653427f12160f9 +8db18da7426c7779756790c62daf32ae40d4b797073cd07d74e5a7a3858c73850a3060f5a3506aae904c3219a149e35d +a2bf815f1a18d7be8ce0c452dfc421da00dcd17e794300cdd536e4c195b8c5b7ccc9729f78936940a527672ac538c470 +a34c6f1f2398c5712acc84e2314f16d656055adcafad765575ae909f80ab706cf526d59e5a43074d671c55b3a4c3c718 +b19357c82069a51a856f74cbb848d99166ce37bd9aca993467d5c480a1b54e6122ebddb6aa86d798188ea9f3087f7534 +b440eac6f24d12c293d21f88e7c57c17be2bdb2a0569a593766ae90d43eccf813a884f09d45a0fb044ee0b74ff54146a +b585d42ef5c7f8d5a1f47aa1329f3b1a566c38bf812af522aa26553010a02bfd6e9cc78fdb940ef413e163c836396a5f +aca213b27f3718348e5496342c89fffc7335f6792283084458c4a1aa5fe0a1e534fcec8e7c002f36141308faae73ef2a +b24c07359769f8ffc33bb60c1f463ea2baad440687ef83d8b7c77931592d534b2c44953c405914ace5b90b65646c1913 +b53dfaf381205a87ca4347328ff14a27541fa6436538f697824071d02d4a737ceb76a38dcc6e8dadef3b5bc6442f5109 +b55972d8ed5197215c0a9144fc76f2cd562ca5f4e28c33a4df913363fd1388978b224c44814adb4c065c588a4ac1fe10 +a3303bc650e120c2e9b8e964ad550eb6ac65ffe6b520768b3e8735565ae37eafdc00e3c15fae766d812f66956a460733 +b11e53912ea0e40c3636d81d7637e10c94cc7ed9330a7e78171a66d02b7603f4cb9b3f6968104b158de254e65b81640f +b076bb9f6d396aa09c2f4706ea553b426fdfd87d7d69e438285b74d334e82f73973cb4dbd6cb1647493433dad65dbc41 +9415828b1632175f0b733541e32c26a9c88fe12c721c23e595f2efceaa7f867f359e32564b7c032185686587ac935cf4 +89579a112c306181c79aabdbf683e7806357febcb73bf5e8883862ae29618ef89498b62634404bb612d618fcd16da415 +8761bcd55d04297c4f24899e8fb9f7c1fcd7449ae86371ee985b6a262e228f561c2584980694d9bf354bdf01543edb6a +9100c88bf5f6f00305de0c9cf73555f16a2016d71c50cb77438e8062bd549fa5407793a8a6a7e06398756777680a2069 +9235dfef45aeff9c174898b0755881b7171ed86362854f0eabc3bc9256176c05a5dc27ca527c91c3fa70c0ec5fd5e160 +ac53b1d677cebab6a99381dd9072b8ac1abae9870ec04a1f8d2a59b6f1de797c1492b59af6948f5cf2b20599170f5bba +946542936b0c59156e8fd5c1623b41369bc2cbcc46ece80360dcb5e7cce718a3dd8a021f0b9c223062a4e43d910b634f +b1e9939b34e1fcc026e820fcfa9ce748b79499f8e81d24a3ef0457b3f507fe5fa37b975a47c143e92eb695623b4e253b +9382d9b5766f6ae960d8a8435e8b5666e57ef8e5f56219e7bfd02857afe5cb16f44d70a9e444cfb1008649ae9b863857 +91770ed1215ed97dca1282b60b960be69c78e1473edb17cd833e712632f4338ff74bf435c3b257439497c72d535ae31f +8eb2cbe8681bb289781bf5250e8fa332141548234c5c428ff648700103a7cd31fdc2f17230992516c674aa0ab211af02 +a823b71c82481bc6ac4f157d5c7f84b893a326bbb498c74222427ded463d231bc6e0240d572ab96266e60eb7c8486aea +a13ce4f482089d867e5babcd11c39fa9a9facd41a2c34ee2577de9ce9c249187e16f2b3a984cc55f9e45b9343462d6d2 +8d80e7bc706059cf5151f9f90e761b033db35d16b80b34dc8b538adc8709d305a0c06933dcd391e96629cf3888c8bf87 +abcd36cdd86c0fb57fb7c0d7a3b9af5fd9aed14e9f4e7e84b0796c5c0ad18c41585e8c46e511cef73dc486fe43f6a014 +a947a5b6916f416fa5a69c31aba94add48584791148b27d0b3ed32c02a05dfc06f7fdc5006e3b2503bdf6e410e30f2fb +b158e621580659f1fa061d976b8591ac03b53ecd23d9eb2b08c1a20353d78438287749664d196020d469ef44b3b8752e +90a5a9540281e481ac4b8d29968f477cb006b56bd145529da855d65d7db0cf610062418c41a1d80c4a5a880c0abe62a0 +b2c91808b6289d08a395204a5c416d4e50a8bb1a8d04a4117c596c4ad8f4dd9e3fb9ce5336d745fc6566086ae2b8e94f +af6767c9b4a444b90aeb69dfddae5ee05d73b5d96e307ce0f3c12bccca7bc16475b237ba3bc401d8dafb413865edf71e +8dcecf624419f6517ef038748ac50797623b771d6111aa29194f7d44cfb30097ced26879e24f1b12a1f6b4591af4639b +954437559d082a718b0d6d7cec090532104ab4e85088e1fc8ee781d42e1a7f4cdb99960429707d72f195ff5d00928793 +80f0b7d190baa6e6ab859dc5baab355e277b00ddcca32e5cebe192877ad1b90ead9e4e846ca0c94c26315465aeb21108 +b8c29f181ed0bb6ac5f6a8d9016980303bb9a6e3bd63ce7a1a03b73829ac306d4fab306ac21c4d285e0d9acb289c8f2a +a7685079fe73ecaeabf2a0ef56bad8b8afb6aeca50f550c97bf27e6b4a8b6866601427fcd741dc9cb4ce67a223d52990 +ada2ebf6f2a05708d3757fbf91365ec4d8747eb4c9d7a8728de3198ceac5694516ab6fd6235568aecd8d6d21fef5ef48 +846bc5da33d969c53ab98765396cab8dcdbb73b9836c9bda176470582a3427cb6de26d9732fab5395d042a66bdba704c +800a3a7ea83ce858b5ebc80820f4117efa5e3927a7350d9771cad9cb38b8299a5ad6d1593682bba281c23a48d8b2aa71 +a002b18595dec90b5b7103a5e3ec55bdd7a5602ee2d3e5bd4d635730483d42745d339521c824128423dfe7571e66cbaf +b6b4e2067ac00a32f74b71007d8ab058c2ef6b7f57249cb02301085e1a1e71d5de8f24f79b463376fd5c848f2ab1c5bc +a3e03036db1b6117efe995bf238b0353ad6f12809630dca51f7daaaf69f7db18702e6b265208944bfb1e8d3897878a51 +add16712f66d48aab0885bd8f0f1fb8230227b8e0ffca751951c97077888e496d6bfab678cb8f9ffba34cee7a8027634 +ad211af2dd0748f85a9701b68c19edd4a7c420e497cb2e20afdc9df0e79663841e03b3c52b66d4474736f50d66c713ce +8c8a899ce0f16d797b342dc03c2212dda9ee02244c73c7511626dba845d11a0feb138441da5459c42f97209bf758cd9b +a17efc75c7d34326564ec2fdc3b7450e08ad5d1de4eb353de9d1cd919d90f4be99f7d8e236908b1f29cf07ae1ffe0f84 +862d4a8b844e1b0dd9f4deff180456ebed5333b54290b84f23c0ddb2725ac20307e21cbb7343feac598756fe36d39053 +9187fbb19e728a95629deda66a59e178f3fcd6e9d7877465aa5a02cea3baba2b684bd247b4afbf4aa466b64cb6460485 +85ae5636688d06eab3be16e44fe148515d9448c6123af2365d2c997f511764f16830610a58d747adab6db5031bea3981 +8aa8a82891f4e041ce6df3d6d5d7e5c9aaaffe08e0a345ac0a34df218272664c1b7be2450abb9bc428bd4077e6e5dcc4 +8c3bcc85ea574dfe1b9ca8748565c88024e94374434612925b4e9a09fa9d49c0a56b8d0e44de7bd49a587ef71c4bff5f +9524f9dd866fe62faf8049a0a3f1572b024120d2e27d1be90ad8b8805b4e2c14a58614516281cc646c19460a6b75587c +84580d9c72cfa6726ff07e8d9628f0382dc84ce586d616c0c1bd1fd193d0a49305893eae97388de45ba79afe88052ee9 +b5573e7b9e5f0e423548f0583423a5db453790ab4869bd83d4d860167e13fd78f49f9a1ffe93ddddf5d7cd6ec1402bc4 +aff658033db3dad70170decb471aee2cf477cf4d7e03267a45f1af5fd18200f5505c7ce75516d70af0b0804ec5868a05 +84a0eab4e732a0484c6c9ed51431e80cea807702fa99c8209f4371e55551088a12e33a11a7ef69012202b0bc2b063159 +a68f8e730f8eb49420fe9d7d39bb986f0584c1775817e35bb3f7dae02fd860cddf44f1788dc9e10d5bf837886b51947f +946002dd6cf7a4fd3be4bf451440e3f3fd7e9b09f609fa4e64767180b43146095dfc4b6994287f8cfa6d1390d144be71 +b7f19777d0da06f2ab53d6382751dc5e415249d2c96fce94ef971401935c1d1f7d3b678501e785cf04b237efe2fe736e +81e5c66dd404fc8ffd3ac5fe5e69ead7b32a5a7bc8605a2c19185efcc65c5073e7817be41e1c49143e191c63f35239c1 +b5f49c523532dfa897034977b9151d753e8a0fc834fa326d0f3d6dacc7c7370a53fc6e80f6d5a90a3fbec9bbb61b4b7c +8fc8e78c07319877adfaa154a339e408a4ae7572c4fb33c8c5950376060667fbfc8ede31e1b067933d47e3fdbf8564d7 +859cfef032a1a044532e2346975679545fbb3993a34497ce81bdcc312e8d51b021f153090724e4b08214f38276ee1e0d +ae476722f456c79a9c9dfdc1c501efa37f2bff19ab33a049908409c7309d8dd2c2912aa138a57a8d5cb3790ca3c0ba2f +89acbbeffb37a19d89cfe8ed9aa8b6acf332767a4c54900428dd9ab3bf223b97315aca399c6971fe3b73a10a5e95a325 +90a4a00418fdf4420a4f48e920622aae6feb5bf41fd21a54e44039378e24f0d93ccc858d2d8a302200c199987d7cb5e4 +a3f316b0bd603143eba4c3d2f8efe51173c48afe3c25b4ca69d862c44922c441bd50d9a5040b7b42ba5685b44071c272 +a22f4dc96fedd62b9a9f51812349e04d42d81d0103465c09295a26544e394a34abdc6ded37902d913d7f99752dbfb627 +a49f51baf32d0b228f76796a0fef0fe48a0c43ec5d6af1aa437603d7332505be8b57b1c5e133bc5d413739f5ae2ce9d0 +a9e4fe133057a0cd991898e119b735b31a79811307625277c97491ff5d864c428cfa42ae843601d7bb05c0313472d086 +b987edfe0add1463a797ff3de10492b2b6b7ef0da67c221ab6f0f2b259445768a73fbe495de238c4abbe4d328e817c49 +b7f0e4532a379a4c306bbef98b45af3b82b17175dfe0f884222ed954c12f27d8a5bdd0cdeb1df27ff5832ba42a6dd521 +9471bc5ad5ec554acfd61b2eb97b752cb754536f95ae54ca2cbd1dc2b32eb618881f6d8a8b2802c1a4e58c927067d6cf +b4c84f09225cf963c7cc9d082efe51afbbbe33469dd90b072807438e6bde71db8352a31bb0efde6cd3529619812ef067 +8f08005a83e716062d6659c7e86c7d3b51e27b22be70371c125046de08f10ea51db12d616fbf43e47a52e546e7acaac7 +a8937e66a23f9d9b353224491f06e98750b04eca14a88021ee72caf41bdce17d128957c78127fba8ef3dc47598d768a7 +80ad991de9bd3ad543cddeaa1d69ca4e749aaefb461644de9fc4bd18c3b4376c6555fc73517a8b1268d0e1e1628d3c1f +b22f98bca8fe5a048ba0e155c03e7df3e3cee2bfe8d50e110159abdb16b316d6948f983c056991a737b646b4d1807866 +b0bb925c19ca875cf8cdbefa8879b950016cc98b1deb59df8b819018e8c0ad71ea7413733286f9a1db457066965ce452 +95a991e66d00dd99a1f4753f6171046a5ab4f4d5d4fe0adfe9842795348a772d5a4a714dba06b4264b30f22dafa1322f +ad91e781fa68527a37c7d43dd242455752da9c3f6065cd954c46ae23ce2db08f9df9fec3917e80912f391c7a7f2f7ffa +a202d3becbf28d899fe28f09a58a0a742617c1b9b03209eca1be7f072a8ada1f7eac2cc47e08788d85e1908eb9d3d8ee +a360ccb27e40d774d5a07b4ebed713e59a0d71b3ee3f02374e7582b59ec4a5ce22cc69c55e89742ba036dd9b4edd8f34 +a10b897a946882b7c9e28abbb512a603ffa18f9274369843eb3491524a321df1f572eea349099ac6e749ea253c901ea0 +b782a672cd344da368732ecd7e0a1476c2af04613d3eb6da0e322f80438af932bd6d49be7a6f69f7c877512731723d89 +aeccee8dfd764e1adcfc4bf669e0fa87a94e7c79324333e958df47888bff5cec358b8b5bbb48db54822b54d11bbb4bc6 +ad4953913662a9ee8753a354864339f43916f2c2390d0a3f847c712b42718ee00ee14158d730709971941e8680d54560 +92ccb31d6c9e8940c7e8a4873e7eb9de9fb2fa2bac344fa367062ea451fd49a6920a45218dca3ee968711397d2a01536 +9448d9b2b3d12dde9b702f53373db8b8595f9d1f9de2ebee76de292f966f375316953aadf6bfc0e4e853e1fa12d8f02c +8919230878a7219da8c80a4b7d00b9169fb503e72d79789dd53863c243b8d0fb0a819d46fa636d805d0b9b1d15d1f2d9 +b6581ab01215aac023f5e6f57419b6aa63c0743c07caf57d4e146b56b02d90ce1423f70489ac3a11e5c968cb924f937c +a793ec1b1fe56a76920296af06073caadfd6f1d7e30950f8ca13de3de45fe275ca4b361f5249d9405264c3a06ebb5502 +86385b4a4e1bfb5efe7bfef8fd0dfeba7f4400852237cab60febb1dfa409e497a649e81284b5a15fe680b78927256756 +85d10600de96103daa7c90657174b6cb4a1286df5379f1eda9f11c97f9df57043c290eb1ae83658530fe0fd264867b86 +ae01b2396d0f598c21659cd854c15edd4904a34d22278aef97c9260a14a8b250b52d972d304ac4b187c24d08795d5355 +b91b3e4b6fc06e88081fe023ef1b773d82c628eb0f73a2731a9aa05b0dc89b7aeef2eea60125d302e696f45c407aeac2 +986d0f478e33af7568eab6bb26a55c13ffd7cae27525b4abe2f3a994bdb11bbc73d59bdb9a2f6b6ba420a26f8f620ba6 +9746f4fdeef35feaff1def0ea5366b64f21ed29749ae6349f9cb75987e7f931952f913f446100f2a6b182561f382e8eb +a34a116cfde1acbce0d7de037f72a7ca30ab126d8f4815b2b8bcb88e0e6c89015a4daaf4d4ce8eae23eb5d059cf9a5cf +80c3ea37f6a44f07cc9c9c881990f2a5deb9f9489a382718b18a287aa3c50ee6ebe8fd1b3afb84a3cf87f06556f4ca15 +97cff3bc88cfc72ce5e561f7eeb95d4ffb32697e290190c7902e9570c56b3854753777fc417fd27536fc398c8fefb63b +b8807232455833e4072df9bffa388ae6e8099758c2a739194719af7d9ed4041974a6cd9605f089de8b43f0e12f181358 +96f79fca72f75dc182c71f2343f0c43b06d98563fd02d2e1fbc031b96601608d8a726c811a74bb51ab8b0a3ce3632dc4 +b5262761680a4235a8c1257de4735cdcadf08d5d12c6e9d4f628464d5c05dfff3884a9ef2af3b7724b5a8c97e6be74eb +b6ce0eada73433d98f8fae7d55e4ea2b9d9d7a0ae850d328dd06991f27b1f03e470868fb102800ff3efe4ee1698531b9 +a37b7d9fe9d3fdfbc72c59cf6cacc7e7a89d534dea3d73121f7483331aec8ab3fbff58ffabb943b75d6f86df0ba43262 +93fce9be8a27fcaa1283d90d3e87265a6221ee302ec708161a42bd00ffe8e726743d9e187e1bf4307c0e3f25afbb1d44 +a4ea919021346ae7ea69d5e8f46d860b24c35c676b62f4e577c90e0c05c5646fe73721b143b7c38835dd4b443e6c3676 +b79983a5948453f70dfa4c396ce1945204498fe79f40c0667291bd0fdd96ed0b9ea424571f7ade342275c854c9f03d9e +866f8e395ed730b614b70bf999cad6e87e9086c1f5aea8d69020b562ee285dd0fb93afaca0dd13a0713f74a3f9340f01 +a3fef158782292c6139f9a0d01711aa4ed6f5cac11d4c499e9e65c60469ae3afbde44fb059845973a4b3bbca627b7eb7 +b4a2c0321b68f056e7d8051beede396fa2f0704d8aa34224f79f7b7a62eb485fc81889cb617019622fd5b5fa604516f5 +8f0e3edddbaead9059df94de4139e3a70693c9ea9bc6baaa5695dddfd67263b33926670159846292801941b9a0c6545b +9804e850f961e091dadd985d43d526ba8054d1bf9c573ed38f24bbd87aeaad4dcba4c321480abc515a16b3b28f27bb2a +95f330da28af29e362da3776f153f391703a0595323585220712dae2b54362cc6222070edd2f0dd970acfbe2e3147d5c +82d03b771231179cc31b29fe1e53379d77b5273b5c0a68d973accd7a757c7584dbb37f0507cdfde8807313ec733a6393 +81b3c39a9f632086e97b7c1f0ec7e2eaf9dc3cb0d84dec18a4441dbdc9fe9878fde4bcfa686bca1a9522632a353a5566 +a2db124ab2b493d5f9a1e4ca6b3144593c2fc8bfac129fd79da11dfbb7ef410a234fda9273a50a5ca05d7b37cc2088a2 +aa8550633c9449228702690cc505c0fc4837ea40862058e8f9713622b34d49fdc3a979b9317993c5da53b5bb5b7f4974 +ae783bcf7a736fdc815d0205b4c2c2b2fee0a854765228f76c39638ba503e2d37f1e28f6bdf263923f96fead76b4187b +b5ec86092c1d250251e93bab2f24e321afd2cd24cf49adfcbed9e8bc5142343ae750206c556320551e50fc972142f0da +b3b5791b590a6e9b3f473d5148624014aa244495249322a5d75cde2c64117ff9d32f4b0698b0e4382e5e7f72933061f8 +876c6a9162c17b16d6b35e6ce1ba32e26aec7dd1368bceab261ab880ad845c91e54b96a52c7d3aafbfbafc0e37139dca +902ddb5774d20b0707a704486457c29048776a5b88c377b14af6616c8ddf6cd34f49807df9c9d8866d6b39685cfb0f19 +8b87f71f94bc96de927d77a5d7123fa9cdda8c76aff64a5e6112cbc2eca43b07f8376db3e330f8af6a1db9b948908a6a +a69a5922e572b13d6778218e3657f1e1eea9a9682f6eb1b731d676d03563e14a37ff69bc5e673c74090ecb0969a593f7 +aff3510d78ba72f3cf5e3101847b7c4a956815aa77148689c07864e8a12dd0ef33d5f6c8cb486e0ea55850161f6afed0 +aa9c459cb2a008d94cbee2c6b561d18b0d7c6ffa8a65cbf86ae2c14eec070ee9d5324f5d38f25a945ddcd70307e964c4 +8310e15b050b1e40ece7530b22964bde0fd04f48dfffdec5a0d1fb8af0799a7fdc1d878139fb7cb8d043d3a52c2d1605 +b8f0856ce2c4034ee4041d0383f25fb0eeefc00b82443311a466fc18608313683af2e70e333eb87e7c687e8498e8a1ce +a8200a75c158fbb78474cab8a543caecd430b5d8b9964fc45d2d494dd938021cd00c7c33413ad53aa437d508f460a42a +a310091472b5b42b02176b72d5f8120bdb173025de24b420e3ca3fb9a386c39092a1d1bb591c6f68ee97a268a7ff9e95 +b23f1bf8bcec9cb5232b407115eead855fd06f5bf86ba322ad61d45460c84f0f36911aba303de788c9a0878207eac288 +ae4c129ad6d08be44690bb84370e48bfd92c5d87940750ee2c98c9a2604456f7f42727ab211989657bb202f6d907df04 +95992057d654f3e189a859346aa9aa009f074cb193b7f5720fa70c2b7c9ce887d886f6cff93fa57c1f7c8eaa187603f6 +ad12d560273963da94151dd6be49c665d7624011c67d54ab41447452a866bc997e92a80bdd9ca56a03528e72c456dc76 +8e4eda72e9cfcaa07265bb6a66d88e9ce3390ae1a6b8831045b36ea4156b53d23724824d0f0bca250ce850c5926fa38f +980fe29c1a267c556532c46130fb54a811944bdfea263f1afcdab248fa85591c22ac26167f4133372b18d9f5cce83707 +a7da9f99ddde16c0eac63d534a6b6776ad89b48a5b9718a2f2331dce903a100a2b7855cf7b257565a326ddc76adc71a5 +8ca854c55e256efd790940cb01125f293e60a390b5bd3e7a60e13ac11a24f350a7eb5ebddfa0a2890905ca0f1980b315 +9440335818859b5e8f180893a8acedceabaaa44e320286506721c639a489b5bfb80b42b28902ee87237b0bd3dd49552a +b9da545a20a5e7d60fd0c376dcaf4b144f5c5a62c8ffa7b250c53ce44be69c4e0d5e4e11422ef90593ae58ae1df0e5d3 +b75852a850687f477849fc51e0479703cd44428671c71bfdd27fe3e7930b97d2fc55f20348ca4e5bc08db2fc16a4f23c +b515081d8d099e4b6253c991ca2d3e42633f5832c64aa8f9cde23cb42c097c2c3717c46c5f178f16c58295f97b2b3fe7 +9506c9902419243e73d3197e407985dd5113f16c6be492651bbbf9576621942710aea74522d6fb56d5b52c6ccdaa4307 +952673ae27462a0f6c9545eede245c2f8e2fd6077b72a71f5672f1a5a02c263bc2a66f24f0e30376feb7a8187b715f08 +a8f1e2085ed666a8f86b474d9589dc309d5c83bd53e745f8e09abe0dfbaf53e5384c68580672990344d4aa739438b4d8 +ad6e04d4a67a5a5529ceaf7de6e19416be5b4c436610aa576ac04aee3b73317da88f891121f966393a37f52b775a2dd8 +a35a884736f08c7f76923ae7adb17fdac04e6c505178bca9502eaa2ed16d4d93fa953fb6dcf99e9e9962a6eb3eeead00 +b8af72273360bab4b3ca302cf0659717cbfb335fbc9ad4ffdd3340113ece9e63b2bdbd611e5f6b740a4689286f9a452d +b1a1f4ba2640800c3ed3892e049f6e10f8a571efa3bbe21fe2d6cee8fded171c675a3bb8aa121e2d1d715de84bad2e2b +8102a6c3598b40da4d6e8eccfdd5dadc8d6262e38b69c5b211b0732f4c6e3045d79fba12770a0b2b66f1e9f4664b1510 +90979587d75bf12819f63832beea7dcbef101f6814bf88db4575bfcd9cf0ea8eceba76d4d6db17630b73b46c1acfe011 +8dd98f14d2beb5b5b79cc30f6825ec11ed76bd5a8864593ffc0c2baffab6872bad182e1c64b93aab8dd5adb465fa5cec +8083334dadc49c84f936c603a2857f174eda5659ab2b7214572f318aba3ebd7b1c50e7cbea57272b9edf106bd016df3b +a634d08d2e8641b852e89d7ccab1bab700c32fb143bcbea132f2a5fb2968d74ded2af4107f69818798f0128cc245a8cb +94fc2dccf746d5b3027f7cf4547edf97097cd11db8d6a304c1c2ca6b3aba28c1af17c08d2bbb66f88c14472e0196a45e +b257a6fb01424b35e414c1c002e60487abb3b889d74c60cbdbf591e222739c6f97b95f6962842401f5e2009e91b28c55 +81955bdbf25741f3b85d5044898dc76ae51b1b805a51f7c72a389d3b4d94b2e3e0aa1ec271685bbcf192ed80db7367ab +86eb229b66c542514e42b113b9de7d4f146861a60f2a253264873e7de7da2ac206e156ff11f2de88491b9897174fe2f4 +8b8db00533afbb56b3d7d7a9a4a6af3cebb523699ffcb974603e54f268b3ef739c41cd11850b9651d9640d72217c3402 +8b7cbb72a6c4408d5f1b61001e65de459790444530245d47d4ee8e2d17716695283f21540bd7ac4f5a793a0d00bdf1d4 +875920b9bab4bc1712e6af89ae2e58e9928c22095026070b07e338421b554d9f96e549ac3706c6c8d73f502913a27553 +9455d192db7b039b3e8f0bc186c25ff07dfbe90dab911e3c62e3bd636db8019ed712cbb0ecd5cbb9a36c11034e102aba +8cb0b28e5d3838d69f6c12274d6b1250f8843938065d0665b347977fa3c1c685caef6930bae9483ed0d0a67005baad76 +94df2e14aae1ae2882ab22a7baf3dc768c4a72b346c2d46bfd93d394458398f91315e85dc68be371f35d5720d6ca8e11 +aacd94b416bfbeb5334032701214dd453ad6be312f303b7bec16a9b7d46ab95432a14c0fbf21a90f26aafb50ec7bb887 +b43d26963665244633cbb9b3c000cacce068c688119e94cc0dac7df0e6ee30188e53befff255977788be888a74c60fc2 +b40d67c9ad0078f61e8744be175e19c659a12065fe4363b0e88482b098b2431612e7c2fa7e519a092965de09ceafe25c +82cd4a4e547c798f89ce8b59687614aa128877e6d38b761646d03dc78f6cdd28054649fb3441bcd95c59b65a6d0dd158 +a058e9700f05cef6e40c88b154d66a818298e71ae9c2cf23e2af99a0a7dc8f57fbe529d566cb4247432e3c1dee839b08 +95c6f84406466346c0b4a2a7331ac266177fb08c493d9febb284c5ca0b141ccc17aa32407f579666b208fb187c0227dd +905d1d47a26b154f44d7531c53efbc3743ff70bd7dba50c9b9d26636767b0ae80de3963c56d4604399126f4ad41a0574 +83dfa11c520b4abaefe1b2bc1ce117806e222f373cd4fb724f3c037c228e3379d27a364e68faa73984ba73a0845f1b9a +a16e54786ba308a9c0241aff8f1bf785dece387d93bd74aa31de0969e3431479e2c0abebff9939a6644d2b0af44f80bb +81ac565212365176f5be1c0217f4e7c9fdbc9fe90f16161367635d52edcf57af79290531d2e8b585e1223d33febd957d +a296f4b09915e5d80ff7274dc3ffc9b04f0427e049ea4ef83dca91095275e8a260ef0335c7b6585953b62682da8c8e99 +a9150626208168a21ae871192ca9f11c1f7f6e41e8e02de00732de2324d0d69fe52f8762155c9913ee408a034552e49a +a42a56008ca340c6e9ff5a68c8778bb899ba5de9e7508c0cac355c157979a7ff6a6bd64f98b182114d3831cfa97ee72b +a4f05adf22c051812279258eea9eb00956b04ef095f2ca175f775ff53c710fb0020266adabd1dacaee814c4f1d965299 +967492e78ac0bceb8ad726ea0d2292b760043d16d64a6b1bb896e32630a7bf405c2b20e4e00842ae519a21697ff8db2d +adbf05e9b5931ae3dd24d105b5c523c221a486a4123c727069b9e295a5bc94f3e647a3c2cde1f9f45dbd89df411453c9 +a1759c0ebebd146ee3be0e5461a642938a8e6d0cdd2253ebd61645b227624c10c711e12615cd1e7ea9de9b83d63d1a25 +a4c5945d635b9efc89ad51f5428862aefe3d868d8fb8661911338a6d9e12b6c4e5c15a25e8cb4a7edc889b9fa2b57592 +aff127675ea6ad99cb51c6e17c055c9f8fd6c40130c195a78afdf4f9f7bc9c21eed56230adb316d681fc5cacc97187da +9071294e8ff05b246ff4526105742c8bf2d97a7e7913f4541080838ecfd2dbc67c7be664a8521af48dbc417c1b466a85 +990880b0dd576b04f4b4ce6f0c5d9ff4606ec9d3f56743ac2f469ac6a78c33d25c3105cf54f675e300ac68073b61b97a +a8d1a62ce47a4648988633ed1f22b6dea50a31d11fdddf490c81de08599f6b665e785d9d2a56be05844bd27e6d2e0933 +8ea5a6c06f2096ded450c9538da7d9e402a27d070f43646533c69de8ea7993545673a469c0e59c31520e973de71db1b4 +99d3a098782520612b98a5b1862ae91bcb338ab97d1a75536e44b36a22885f1450a50af05c76da3dd5ca3c718e69fdd4 +b987451526e0389b5fe94c8be92f4e792405745b0a76acd6f777053d0809868657ba630aa5945f4bd7ce51319f8996f7 +afffccc5ddd41313888a4f9fee189f3d20d8b2918aa5ad0617009ea6d608e7968063c71bd5e6a1d7557880d9a639328d +8ac51a02505d5cadfd158dde44932ab33984c420aeceb032ed1ee3a72770d268f9e60ccf80ce8494dfc7434b440daafd +b6543e50bd9c6f8e0862850c3d89835ddd96231527681d4ab7ae039c4a3a5a0b133a6d40cdb35c8a6c8dbb8d421d3e2b +a2ba901f4fde2b62274d0c5b4dbbea8f89518571d8f95ec0705b303b91832f7027704790a30f7d9d2cdafde92f241b3e +a6974b09280591c86998a6854a7d790f2a6fbe544770e062845cfc8f25eb48c58f5dfb1b325b21f049d81998029ad221 +890baeb336bbf6c16a65c839ffaab7b13dd3e55a3e7189f7732dbcb281b2901b6d8ba896650a55caa71f0c2219d9b70e +b694211e0556aebbe4baf9940326e648c34fda17a34e16aa4cefd0133558c8513ffb3b35e4ee436d9d879e11a44ec193 +97cf9eb2611d467421a3e0bfe5c75382696b15346f781311e4c9192b7bca5eb8eaf24fa16156f91248053d44de8c7c6f +8247f88605bd576e97128d4115a53ab1f33a730dc646c40d76c172ca2aa8641c511dddad60ee3a6fbe1bb15cac94a36c +ae7ecd1c4a5e9e6b46b67366bc85b540915623a63ab67e401d42ca1d34ae210a0d5487f2eef96d0021ebecfd8d4cd9a8 +aec5123fff0e5d395babe3cb7c3813e2888eb8d9056ad4777097e4309fb9d0928f5c224c00260a006f0e881be6a3bf8f +8101724fa0ce7c40ea165e81f3c8d52aa55951cc49b4da0696d98c9fafd933e7b6c28119aa33f12928d9f2339a1075d1 +a8360843bab19590e6f20694cdd8c15717a8539616f2c41a3e1690f904b5575adb0849226502a305baefb2ead2024974 +ade5cad933e6ed26bba796c9997b057c68821e87645c4079e38e3048ea75d8372758f8819cde85a3ab3ab8e44a7d9742 +ab1fe373fb2454174bd2bd1fe15251c6140b4ac07bda1a15e5eabf74b6f9a5b47581ef5f0dbd99fdf4d1c8c56a072af7 +b425e1af8651e2be3891213ff47a4d92df7432b8d8ea045bb6670caf37800a4cd563931a4eb13bff77575cbcae8bc14f +b274799fe9dd410e7aed7436f0c562010b3da9106dc867405822b1e593f56478645492dbc101a871f1d20acf554c3be6 +b01a62a9d529cc3156bc3e07f70e7a5614b8d005646c0d193c4feb68be0b449d02b8f0000da3404e75dbdfa9ca655186 +878b95e692d938573cdb8c3a5841de0b05e5484a61e36ea14042f4eadb8b54a24038d2f09745455715d7562b38a8e0df +a89e998e979dba65c5b1a9000ad0fd9bb1b2e1c168970f2744982781306bbe338857e2fac49c8cafda23f7cc7c22f945 +85880fdf30faed6acce9973225e8fe160e680a55fc77a31daacf9df185453ad0c0552eb3fd874698ad8e33c224f7f615 +ac28d20d4bbb35ba77366272474f90f0ed1519a0e4d5de737adee2de774ccd5f115949e309e85c5883dbc63daaa6e27b +a1758ac86db859e323f5231ad82d78acbe11d53d3ebf7e644e581b646eede079d86f90dc23b54e5de55f5b75f7ea7758 +ae4c0b84903f89353bf9a462370f0bf22c04628c38bb0caae23d6e2d91699a58bd064e3c2b1cbda7f0a675d129f67930 +95f21a099ffc21a0f9064d9b94ce227b3ff0a8c5a2af06ff5ee6b7f3248a17a8ca2f78cd7929ef1d0784f81eddefcd48 +8d06fbc1b468f12b381fd1e6108c63c0d898ddf123ea4e2e1247af115043c4f90b52796076277b722dd2b92708f80c21 +a300f39039d8b2452e63b272c6d1f6d14a808b2cd646e04476545da65b71a6e29060f879409f6941c84bde9abe3c7d01 +adecce1ccc5373072ba73930e47b17298e16d19dbb512eed88ad58d3046bb7eec9d90b3e6c9ba6b51e9119cf27ce53f2 +941a7e03a64a2885d9e7bee604ddc186f93ff792877a04209bbee2361ab4cb2aed3291f51a39be10900a1a11479282ca +acbcb1ab19f3add61d4544c5e3c1f6022e5cc20672b5dc28586e0e653819bdae18cda221bb9017dfaa89c217f9394f63 +b8d92cea7766d3562772b0f287df4d2e486657b7ab743ed31ec48fdc15b271c2b41d6264697282b359f5cb4d91200195 +957360ecb5d242f06d13c1b6d4fcd19897fb50a9a27eb1bd4882b400dc3851d0871c0c52716c05c6c6cf3dee3d389002 +abd2a23abbc903fbb00454c44b9fb4a03554a5ef04101b2f66b259101125058346d44d315b903c6d8d678132f30b1393 +ae9572beff080dd51d3c132006107a99c4271210af8fbe78beb98d24a40b782537c89308c5a2bddfdfe770f01f482550 +82c7e5a5e723938eb698602dc84d629042c1999938ebd0a55411be894bccfb2c0206ac1644e11fddd7f7ab5ee3de9fdc +aba22f23c458757dc71adb1ce7ef158f50fdd1917b24d09cfc2fbbcbe430b2d60785ab141cf35ad9f3d0a2b3e2c7f058 +8eff41278e6c512c7552469b74abedf29efa4632f800f1a1058a0b7a9d23da55d21d07fdbb954acb99de3a3e56f12df6 +8abd591e99b7e0169459861a3c2429d1087b4f5c7b3814e8cee12ecc527a14a3bdda3472409f62f49a1eb4b473f92dbf +82dcbff4c49a9970893afc965f1264fcab9bae65e8fb057f883d4417b09e547924123493501c3d6c23a5160277d22a8e +b5a919fcb448a8203ad3a271c618e7824a33fd523ed638c9af7cfe2c23e3290e904d2cd217a7f1f7170a5545f7e49264 +96d6834b592ddb9cf999ad314c89c09bedc34545eeda4698507676674b62c06cc9b5256483f4f114cd1ed9aaec2fba5e +a4e878cf4976eb5ff3b0c8f19b87de0ef10cd8ec06fe3cd0677bd6be80ba052ff721a4b836841bdffb1df79639d0446c +8e15787a8075fd45ab92503120de67beb6d37c1cc0843c4d3774e1f939ac5ed0a85dad7090d92fa217bd9d831319021b +8506c7fea5a90cd12b68fdbbae4486a630372e6fd97a96eea83a31863905def661c5cdead3cf8819515afe258dbcd4d9 +952ef3bc16a93714d611072a6d54008b5e1bf138fd92e57f40a6efb1290d6a1ffcc0e55ff7e1a6f5d106702bd06807cd +a5f7761fa0be1e160470e3e9e6ab4715992587c0a81b028c9e2cf89d6f9531c2f83c31d42b71fca4cc873d85eba74f33 +b4811f0df11ff05bf4c2c108a48eece601109304f48cde358400d4d2fa5c1fdaaf3627f31cb3a1bdd3c98862b221720d +9207ad280b0832f8687def16ad8686f6ce19beb1ca20c01b40dd49b1313f486f2cb837cfbbf243be64d1c2ab9d497c3f +b18a8c1e6363fadd881efb638013e980e4edb68c1313f3744e781ce38730e7777f0cba70ea97440318d93a77059d4a2b +901faf777867995aac092f23c99c61f97eeadf4ac6bcb7791c67fa3c495947baef494b2aace77077c966c5d427abbf92 +a123281aca1c4f98f56cff7ff2ae36862449f234d1723b2f54ebfccd2740d83bd768f9f4008b4771e56c302d7bfc764f +8cffe1266468cad1075652d0765ff9b89f19b3d385e29b40f5395b5a3ad4b157eed62e94279ac3ec5090a6bad089d8b3 +8d39870719bc4ebbcecba2c54322111b949a6ed22bda28a6cea4b150272e98c9ded48cc58fc5c6e3a6002327856726ec +b3d482c00301f6e7667aaeaf261150b322164a5a19a2fa3d7e7c7bf77dc12fa74f5b5685228ab8bf0daf4b87d9092447 +801acb8e2204afb513187936d30eb7cab61f3fbb87bfd4cd69d7f3b3ddba8e232b93050616c5a2e6daa0e64cef6d106f +ac11e18adda82d2a65e1363eb21bda612414b20202ecc0e2e80cc95679a9efa73029034b38fd8745ce7f85172a9ab639 +b631d6990d0f975a3394f800f3df1174a850b60111567784f1c4d5bba709739d8af934acfa4efc784b8fc151e3e4e423 +aeda6279b136b043415479a18b3bbff83f50e4207b113e30a9ccfd16bd1756065fc3b97553a97998a66013c6ac28f3d8 +8840b305dc893f1cb7ad9dd288f40774ec29ea7545477573a6f1b23eaee11b20304939797fd4bcab8703567929ce93ad +963cc84505a28571b705166592bffa4ea5c4eeafe86be90b3e4ae7b699aaaca968a151fe3d1e89709fe0a3f0edf5d61a +8e1ec0d0e51f89afea325051fc2fa69ab77d6c7363cc762e470a9dfa28d4827de5e50f0b474c407b8c8713bad85c4acd +909f313420403cb36c11d392cf929a4c20514aa2cb2d9c80565f79029121efd5410ef74e51faba4e9ba6d06fcf9f1bd1 +b2992b45da467e9c327ac4d8815467cf4d47518fc2094870d4355eb941534d102354fbda5ab7f53fbf9defa7e767ca13 +9563b50feb99df160946da0b435ac26f9c8b26f4470c88a62755cdf57faebeefffff41c7bdc6711511b1f33e025f6870 +a2a364d9536cd5537a4add24867deec61e38d3f5eb3490b649f61c72b20205a17545e61403d1fb0d3a6f382c75da1eb3 +89b6d7c56251304b57b1d1a4255cb588bd7a851e33bf9070ee0b1d841d5c35870f359bc0fdc0c69afe4e0a99f3b16ec2 +a8ae1ee0484fe46b13a627741ddcdae6a71c863b78aafe3852b49775a0e44732eaf54d81715b1dca06bb0f51a604b7e2 +b814ecbfbc9645c46fc3d81c7917268e86314162d270aed649171db8c8603f2bd01370f181f77dbcbcc5caf263bedc6c +8e5d7cc8aad908f3b4e96af00e108754915fecebdb54f0d78d03153d63267b67682e72cd9b427839dca94902d2f3cda7 +8fc5ff6d61dd5b1de8c94053aef5861009cb6781efcca5050172ef9502e727d648838f43df567f2e777b7d3a47c235dd +8788eea19d09e42b0e3e35eb9bcd14f643751c80c6e69a6ff3a9f1711e8031bbe82ccd854a74a5cfcf25dda663a49a62 +95d441d8cd715596343182ddcecb8566d47eaa2d957d8aea1313bbed9d643a52b954443deb90a8037a7fa51c88eec942 +a15efd36ef72783ccdc6336ef22a68cc46b1ecec0f660cfe8a055952a974342bf30f08cb808214bce69e516ff94c14c5 +acc084d36907a16de09a5299f183391e597beaf9fa27d905f74dc227701a7678a0f5a5d1be83657de45c9270a287ec69 +b3fd385764356346061570beb760ccf3808619618fd7521eb0feadc55b8153ef4986ff0cbfcbd4153ad4ea566989d72a +91ec6b26725532e8edfda109daa7ce578235f33bd858238dfa2eb6f3cd214115b44cce262a0f2f46727a96b7311d32e1 +96b867ccddb73afe1049bda018c96cfe4083fff5bb499e6a4d9fd1a88a325144f9a08cb0aee310e1bb4f6a5793777e80 +ad10c18465910152676f1bc6a40986119607b5c272488e6422cfda2eb31da741af13a50f5de84037348014a869c8e686 +86ade2dbc4cceb52b84afe1c874d1e3644691284c189761febc4804b520adf60b25817e46f3f3c08d2ab227d00b93076 +998b949af82065c709fc8f63113a9fecdd1367fc84fc3b88857d92321ba795e630ce1396a39c2e056b5acd206ee011d8 +8dec440bbd17b47dfd04e566c2d1b46f9133023b982fdc5eaeae51404bc83a593f8d10c30b24e13aec709549137cae47 +89436ff47431b99f037cddaee08bb199be836587a7db6ed740317888638e5f4bebbb86b80549edff89678fc137dfb40a +a8e9960746769b3f76246c82cd722d46d66625e124d99a1f71a790c01cec842bcf6c23c19cc7011ec972cedf54dc8a4c +980979dafedfd75ff235b37e09e17361cfdda14a5ac3db0b90ed491abfd551916016b2254538da7f4b86ece3038b1b1c +8ec340ca7654720bb9d2f209985439ebbc3f9990ef27e7d7ae366e0c45b4ed973316943122119604ea9a87fc41ebd29f +ab24440a40ab238d8cd811edb3ef99948ae0f33bf3d257b22c445204016cce22b6f06a1ca979fa72a36c4ddedc2b3195 +a1bcd2473ac7cfebfa61c10e56cae5422c6b261a4a1be60b763fcbcdf2eae4ccf80695f09b062b6cf5654dfab0ee62a5 +9027a613ce7bd827110a3a0e63e83f652e9bc7f4ce8da26c38b28ee893fd0c38bdb20f63a33470a73cb77f776244ab4a +86911cc8aeb628197a22bf44d95a0b49afb8332c38857fba8e390c27c527b8b45335e22b0f2e0a3395c16ced3c1ed2e8 +8f0529a330a3e9967dce09357d774715fd305bd9e47b53b8b71a2a1303d390942a835aa02fb865a14cfed4f6f2f33fe6 +b71ec81a64c834e7e6ef75b7f321a308943b4bad55b92f4dbaf46658613cebf7e4b5b1bc7f1cdc5d50d1a2a0690e2766 +98d66aaed9fb92f4c7bb1b488ccbca5e570aa14433028867562a561d84f673ac72e971cbe2cb3cbbb0a702797dc45a7e +8380aa94d96c6b3efd178de39f92f12ca4edd49fe3fe098b2b7781e7f3e5f81ee71d196fb8e260d1d52f2e300e72e7bc +8c36296ff907893ac58cecadd957b29f5508ae75c6cc61b15ae147b789e38c0eace67963ae62eff556221b3d64a257a2 +97e17676cbc0f62a93555375e82422ee49bc7cf56ad6c3d69bb1989d1dc043f9f7113d0ed84616dde310441b795db843 +a952229615534c7e9a715409d68e33086cdaddf0aec51f4369c4017a94ec3d7113a045054d695fb9d7fd335527259012 +817b90958246f15cbd73a9679e10192ca7f5325b41af6388b666d8436706dea94eafffbc3b8d53057f67ad726dbcd528 +95776e378c8abd9223c55cd6a2608e42e851c827b6f71ad3d4dc255c400f9eccf4847c43155f2d56af0c881abef4acfa +8476c254f4b82858ecbe128ed7d4d69a6563fd9c5f7d4defc3c67e0bfa44e41cfd78b8e2a63b0773ce3076e01d3f6a7d +a64b0b189063d31bcae1d13931e92d5ab0cfc23bf40566ac34b5b8b711d0e7d941102e6beb140547512e1fe2d9342e6c +9678460acff1f6eae81a14d5c8049cdcd50779a8719b5c5861762a035b07f7fa1b1ada8b6173f9decf051fd5a55bebd8 +88398758ce86ed0388b13413a73062adb8a026d6b044cd1e7f52142758bed397befee46f161f8a99900ae6a2b8f6b89f +a7dfaf40637c81d8b28358b6135bd7ad9cc59177bd9bc8e42ba54d687d974cdf56be0457638c46b6a18ceaa02d3c53f3 +b0e885e5d48aa8d7af498c5e00b7862ed4be1dad52002f2135d98e8f2e89ca0b36cf95b3218aad71d5b4ada403b7045b +803b0e69a89e8de138123f8da76f6c3e433402d80d2baba98cde3b775a8eda4168530a49345962c4b25a57257ba9f0a7 +8ce6ef80dadb4b1790167fbc48be10ef24248536834ff2b74887b1716c75cb5480c30aa8439c20474477f1ac69734e61 +824764396e2b1e8dcc9f83827a665ef493faec007276f118b5a1f32526340b117c0df12bea630030a131bf389ec78fc3 +874edb379ce4cc8247d071ef86e6efbd8890ba6fcb41ea7427942c140347ebf93e8cf369d1c91bd5f486eb69b45bce70 +adadcb6eb4cafa1e2a9aef3efb5b09ffa2a5cf3ce21f886d96a136336be680dabc0a7c96ec327d172072f66d6dcdbb39 +b993591b280e1f3527f083d238a8f7cf516d3cf00c3690d384881911c1495192a419b8e37872a565ce8007eb04ebe1b6 +b125faaeca3f0b9af7cb51bb30a7c446adbb9a993b11600c8b533bff43c1278de5cdda8cb46a4df46f2e42adb995bce8 +a7efe1b57326b57c2c01720d4fdf348d6a84d35f229d32a8f2eb5d2be4e561ef8aea4d4d0bcfcbf17da10a8e49835031 +a6bd4f5a87574b90a37b44f778d5c7117d78eb38f3d7874bad15ae141b60eed4ab0a7281ed747297f92e0b3fe5f9cafa +94b5e3067ca1db3c4e82daf6189d7d00246b0360cb863940840358daa36cb33857fde4c01acd0457a90e15accee7d764 +a5ff3ab12197b8a07dd80222a709271ab3b07beba453aacbaf225cfb055d729e5a17a20f0ff9e08febf307823cba4383 +a76dd8aa2b6a957ed82ecec49b72085394af22843272f19360a5b5f700910c6ec65bf2a832e1d70aa53fd6baa43c24f6 +8dfcbe4143ae63c6515f151e78e6690078a349a69bb1602b79f59dc51dea7d00d808cf3e9a88b3f390f29aaae6e69834 +8c6134b95946a1dd54126952e805aeb682bc634c17fe642d5d3d8deffffd7693c90c4cd7d112890abfd874aa26736a93 +933531875561d327c181a2e89aaaac0b53e7f506d59ef2dfc930c166446565bd3df03bab8f7d0da7c65624949cfbae2f +ac6937c5e2193395e5bb69fd45aa6a9ae76b336ea7b6fd3e6aeac124365edcba7e918ec2c663fb5142df2f3ad03411a6 +a8f0f968f2a61d61d2cf01625e6ac423b447d3e48378ea70d6ff38bc98c42e222fe3cbcb04662b19973a160dc9f868a2 +94100a36f63d5c3a6cfb903c25a228389921684cc84f123390f38f90859f37ec9714942ffe6766f9b615101a3c009e43 +b5321b07f5b1eb2c1c20b0c8ab407f72f9705b55a761ec5176c5bcc6e585a01cae78546c54117ca3428b2b63793f2e65 +9922f61ed6763d1c4d12485c142b8ff02119066b5011c43e78da1ee51f10a1cf514329874061e67b55597ca01a7b92ab +a212eb2d72af0c45c9ef547d7c34ac5c4f81a4f5ec41459c4abd83d06ec6b09fdab52f801a2209b79612ae797fa4507b +8577d2d8f17c7d90a90bab477a432602d6918ca3d2af082fbb9e83644b93e21ca0bced7f90f6e9279eaa590f4e41dc4d +9002d424e3bebd908b95c5e6a47180b7e1d83e507bfb81d6ad7903aa106df4808c55f10aa34d1dccad3fab4d3f7a453e +b9050299bf9163f6ebeff57c748cb86f587aea153c2e06e334b709a7c48c4cbfba427babf6188786a0387b0c4f50b5ce +852ae1195cc657c4d4690d4b9a5dea8e0baaa59c8de363ba5fccd9e39ec50c6aa8d2087c8b7589b19248c84608f5d0a8 +a02ff5781417ca0c476d82cf55b35615f9995dc7a482124bc486e29b0b06a215fbe3e79228c04547c143d32cd3bac645 +8d7bc95e34bc914642e514a401448b23cf58bce767bab1277697327eb47c4a99214a78b04c92d2e3f99a654308b96e34 +adb28445d3b1cc7d4e4dd1f8b992a668f6b6f777810465fdab231fd42f06b5bada290ba9ae0472110366fad033da514e +a0c72b15a609f56ff71da17b5b744d8701af24b99fbc24a88588213864f511bfa592775e9ab4d11959f4c8538dc015b8 +933205a40379d5f5a7fb62cda17873fbbd99a0aaa8773ddf4cd2707966d8f3b93a107ebfe98b2bb222fe0de33ef68d03 +90690c1a4635e2e165773249477fc07bf48b1fd4d27c1b41a8f83a898c8d3763efb289867f8d6b0d354d7f4c3f5c7320 +99858d8c4f1be5a462e17a349b60991cb8ce9990895d6e42ae762ce144abc65b5a6f6e14df6592a4a07a680e0f103b2a +b354a7da06bd93fb5269e44925295b7c5049467b5cacce68cbb3cab60135b15e2010037a889cb927e6065053af9ccb77 +af01fc4ac396d9b15a4bbd8cc4fe7b30c32a9f544d39e88cdcb9b20c1c3056f56d92583a9781ddb039ec2eeda31fb653 +a8d889fb7155f7900982cf2a65eb2121eb1cc8525bbee48fae70e5f6275c5b554e923d29ebbd9772b62109ff48fb7c99 +b80edae6e26364c28749fd17c7c10eb96787053c7744a5cc6c44082ae96c5d3a4008c899a284f2747d25b72ecb9cb3d0 +b495b37503d77e7aafc226fca575e974b7bb6af2b7488372b32055feecc465a9f2909729e6114b52a69d8726e08739cb +a877f18b1144ff22e10a4879539968a01321cecde898894cbe0c34348b5e6faa85e1597105c49653faed631b1e913ec7 +8c235c558a065f64e06b4bb4f876fe549aab73302a25d8c06a60df9fad05843915ac91b507febca6fe78c69b51b597de +b4c31398b854ccc3847065e79329a3fdae960f200c1cce020234778d9c519a244ff1988c1fbc12eb3da2540a5fa33327 +b7bd134b3460cb05abf5aed0bc3f9d0ccbfac4647324bedbdf5011da18d8b85dc4178dd128f6ddbe9d56ea58f59d0b5d +92594c786c810cf3b5d24c433c8a947f9277fe6c669e51ceb359f0ae8a2c4e513a6dad1ae71b7ded3cdca823a51e849b +b178535e043f1efcce10fbec720c05458e459fdda727753e0e412ef0114db957dc9793e58ec2c031008e8fb994145d59 +b31da7189abf3e66042053f0261c248d4da142861bfd76a9aced19559be5284523d3e309ef69843772b05e03741a13fe +b190a8c1a477e4187fecff2a93033e77e02de20aae93dda1e154598814b78fdf8b9ff574c5f63047d97e736e69621462 +98234bd1d079c52f404bf5e7f68b349a948ec1f770c999c3c98888a55d370982bfa976e7e32848a1ebb4c7694acc1740 +99b9eeb33a6fb104bba5571a3822ebe612bf4b07d720d46bde17f0db0b8e8b52165f9b569be9356a302614e43df3e087 +a1e3915b0dd90625b424303860d78e243dda73eecd01cba7c33100b30471d0a1ec378c29da0f5a297008b115be366160 +975118bf6ca718671335a427b6f2946ee7ece2d09ccfb1df08aa1e98ff8863b6c8b174c608b6b2f4b1176fb3cbc1e30d +903cb1e469694b99360a5850e2ca4201cad23cfccce15de9441e9065eb3e6e87f51cba774ab9015852abd51194c25e57 +821f7ff4d0b133e3be4e91d7ff241fa46c649ff61fc25a9fdcf23d685fe74cf6fade5729763f206876764a3d1a8e9b24 +a1ee8db859439c17e737b4b789023d8b3ce15f3294ec39684f019e1ea94b234ec8a5402bc6e910c2ed1cd22ff3add4de +af27383148757bdf6631c0ea8a5c382f65fc6ab09f3d342a808ca7e18401e437cd1df3b4383190fdf437a3b35cbcc069 +8310551d240750cef8232cd935869bad092b81add09e2e638e41aa8a50042ce25742120b25fb54ebece0b9f9bdb3f255 +8b1954e0761a6397e8da47dc07133434ebe2f32c1c80cd1f7f941f9965acdf3d0c0b1eb57f7ff45a55697d8b804e1d03 +8c11612381c6be93df17851d9f516395a14a13c7816c8556d9510472b858184bf3cc5b9d14ded8d72e8fb4729f0b23ba +b413ac49121c7e8731e536b59d5f40d73a200c4e8300f8b9f2b01df95a3dc5fe85404027fc79b0e52946e8679b3a8e43 +8451e5c1c83df9b590ec53d1f1717d44229ed0f0b6e7011d01ea355d8b351f572866b88032030af372bd9104124df55a +8d0a5c848ec43299bc3ea106847ed418876bc3cd09b2280c2a9b798c469661505ed147a8f4ffba33af0e1167fdb17508 +a6aa97a1f10709582471000b54ec046925a6ad72f2b37c4435621c9f48026d3e332b8e205b6518f11b90b476405960a9 +97696635b5a2a6c51de823eea97d529f6c94846abb0bd4c322b108825589eba9af97762484efaac04ee4847fb2fb7439 +92fd142181fe6ca8d648736866fed8bc3a158af2a305084442155ba8ce85fa1dfb31af7610c1c52a1d38686ac1306b70 +ae3da824ecc863b5229a1a683145be51dd5b81c042b3910a5409ca5009ba63330e4983020271aa4a1304b63b2a2df69e +aecc0fe31432c577c3592110c2f4058c7681c1d15cd8ed8ffb137da4de53188a5f34ca3593160936119bdcf3502bff7c +821eac5545e7f345a865a65e54807e66de3b114a31ddeb716f38fe76fdd9d117bee0d870dd37f34b91d4c070a60d81f4 +91a02abb7923f37d9d8aa9e22ded576c558188c5f6093c891c04d98ab9886893f82b25b962e9b87f3bf93d2c37a53cb9 +99a96f5d6c612ee68e840d5f052bf6a90fecfd61891d8a973e64be2e2bdd5de555b1d8bffbd2d3c66621f6e8a5072106 +b1d5ec8f833d8fbb0e320ff03141868d4a8fff09d6a401c22dbefadbb64323e6d65932879291090daf25658844c91f2e +a06afd66ebc68af507c7cf5ab514947ca7d6ccc89fb2e2e8cb6e5ae0f471473e5fba40bb84d05f2c0f97c87f9a50cb73 +83de3ca182bcf1eac0cc1db6ad9b1c2a1ecd5e394e78add7faa36e039a1b13cb0d1d2639892489df080fbf43e5cef8d5 +adf77fc7b342ff67a2eddaa4be2f04b4e6ceaca8ea89a9fc45cc892fcce8ac3cf8646cfa5aab10ac9d9706ce4c48a636 +8509a430ef8dc9a0abc30ef8f8ccdb349d66d40390fb39f0d3281f3f44acb034625361270162822ef0743d458a82b836 +8350fc09e8617826f708e8154a3280d8753e7dbbcf87e852f9b789fdbeb10bf3fed84fb76edd7b8239a920c449e2f4b7 +a2e7a29da8391a5b2d762bf86cb6ae855cdfad49821175f83f4713dd0c342a0784beba98d4948356985a44d9b8b9d0f7 +a99c50a1a88b8efe540e0f246439db73263648546d199ef0d5bc941524a07d7e02b3ef6e5b08dc9e316b0b4c6966823e +b34ba55136c341f4ca2927080a07476915b86aa820066230903f1f503afebd79f2acf52a0bc8589b148d3a9a4a99f536 +af637be5a3e71c172af1f2644d3674e022bc49c393df565ea5b05ce6401a27718c38a9232049dd18cbd5bf4f2ce65b32 +a2972ba7bfa7f40c2e175bb35048a8ef9bc296d5e5a6c4ca7ab3728f4264d64f2d81d29dce518dc86849485ff9703d7d +8c9db203e8726299adeb331d6f4c235dc3873a8022138d35796fb7098887e95e06dcfad5d766ceaa2c4fb0f8857f37fa +a82bfbaa9a6379442109e89aad0c0cfc6a27d4a5db5480741a509d549c229cb847b46a974dde9f1398c6b3010530f612 +b2d8ef6e091a76dfc04ab85a24dbe8b5a611c85f0ed529a752c2e4c04500de5b305c539d807184e05f120be2c4a05fc3 +8c6ffc66a87d38cea485d16ee6c63ce79c56b64ae413b7593f99cc9c6d3cd78ef3fa2ab8a7943d2f0e182176642adadb +acbc92de68b2b04e3dc128109511a1cbe07518042f365d5634e8b651cb1ac435ea48eeeb2b921876239183096ef6edee +979c4e1165e0ecfa17ed59fb33f70797e000ddbb64acf5fc478cccde940451df051e51b6449c5b11a36afa7868af82e3 +a5a017c5a94952aeae473976027124231abe50460cec4db3ebeb8b1290525776be7c15d108b749c2a1e4b018de827915 +8b6922ab1db925eed24b2586e95f5c709b79d2408a8fa2a71057045ead3ebdd0cc72bee23d9064cd824166eda1e29318 +89a991087a0b5805fcc5c6c5f6ac27e100da0d3713645aa9c90114e68ca9f185f21155eb7645a2c6c0616a47291fe129 +ae6ef954c942cbfd37f8f2dc58a649e2584d6777e7eb09ae6992ccde283ac4f4ec39e3a5cda7f7c60f467fb308d37f08 +9335ca5ccac59b39eb2bcef09c54b778ebb690415ba13fe5c8e4b6091d9343a01cc9baa6228cefd8dba98f0710f714da +a0211c9328be2b46f90ff13614eeffb4c1285e55580db3874610653219926af1d83bda5b089fd37a7c7440a0f1d94984 +a82e097dfa782c40808fac5d8ed1c4fccf6b95ef92e22276fd8d285303fcf18c46d8f752595a658ee5294088b9dc6fc0 +ad108fcd0ead65f7f839a1337d520f5bd0cb665ee7100fc3f0563ff1d2959eb01617de8eb7a67c9b98b7b4892082acdb +b89e6aeabcb3ee3cbf12e3c836bab29e59d49676bcf17a922f861d63141076833f4149fe9e9c3beed24edfacdf1e248b +8477501bd91211e3b1f66c3bfd399ef785271511bc9366366ce95ec5ea95d9288ab0928a6b7887aba62de4da754d3eaf +aeec40c04b279096946b743ad8171bf27988405e1321c04894d9a34e2cbd71f444ff0d14da6cda47e93aa6fe9c780d50 +a703bd2d8a5c3521a8aad92afef5162aed64e9e6343d5b0096ca87b5b5d05e28ed31ba235ab1a626943533a57872dd01 +b52d9dfc12c359efb548d7e2b36ddedaefdec0ef78eda8ac49a990b3eb0ed7668690a98d4d3c7bec4748a43df73f0271 +af887c008bad761ee267b9c1600054c9f17f9fc71acfe0d26d3b9b55536bca5c8aebe403a80aa66a1e3748bb150b20ef +ad2f7a545ef2c2a2978f25cf2402813665c156bab52c9e436d962e54913c85d815f0ba1ce57f61e944f84d9835ce05ea +91a0a9b3cfd05baf9b7df8e1fb42577ec873f8a46bb69a777a6ac9f702735d6e75e66c9257822c781c47b9f78993a46b +939fdc380fb527f9a1ddecf9c9460f37e406cd06c59ce988e361404acbfcb6379f2664a078531705dbc0c375d724137b +8bbbe5d5a0d102b8e0c8a62e7542e13c8c8a6acb88859e78d8e1d01ec0ddff71d429fcb98099e09ff0aa673c8b399dc4 +b67a70e4ef138f48258f7d905af753c962c3cc21b7b8ae8b311a2356c4753f8cd42fdee09ac5ed6de31296ead88c351a +8d21539e7dca02a271ce7d16431773bbe30e6a03f5aff517132d34cdd215ad0da2f06aa4a2a595be489234b233e0852e +892ae11513f572cc5dc8b734b716bb38c0876e50e5e942631bb380b754e9114c34b0606740301e29b27d88439fb32071 +a8780dc9faa485f51b6f93a986bc4e15b166986b13d22ec2fefc6b25403b8b81c15cc9ac0025acc09d84932b15afa09b +b01af013360cd9f2bb9789a2b909c5e010fe6ff179f15997dee1a2ba9ef1ccec19545afdecfcb476f92fcdd482bb2b5a +b5202e5d5053d3af21375d50ad1ccd92538ef9916d17c60eb55c164767c3c74681886297b6f52e258c98d0304d195d3d +8f6adbcfbb0734bf3a4609d75cf2e10f74ed855a8b07cf04ac89a73d23b2e3e5cf270a1f2547b3d73e9da033a3c514b0 +8abe529cd31e4cb2bd75fa2a5e45bd92cbe3b281e90ffc7dea01ba0df17c9a3df97a3fde373cce5d25b5814cf1128fed +b8bbf51187bb3bb124da3870e2dfecb326f25a9383e5cc3323813487457010b9055811669c3da87105050825dc98a743 +a5c83875fe61ebbdd3fd478540d7e5a1ad0f8c790bad0b7dd3a44831e2c376c4fffbc6b988667afa1b67bfaa2dbbb256 +a0606b3062e4beba9031ba2a8e6e90aa5a43ba7321003976e721fd4eedb56486f2c5b10ba7a7f5383272f4022092eacb +b485cc5e001de6bd1bbc9cd8d777098e426d88275aaa659232f317352e1ddff3478262d06b46a573c45409bc461883e1 +916449580b64a9d8510e2f8c7aee0b467a0e93b11edc3d50725bcbc3ca53c2b8bb231fdc0fc0ed5270bf2df3f64750d9 +b2e687caa9f148c2b20a27a91bada01a88bff47faaf6ed87815db26bb6cdd93672199661654763a6b8b4b2012f59dcca +b6933f7f9dabc8fb69197571366ac61295160d25881adf2fcc8aaabc9c5ed7cf229a493fd9e2f1c2f84facd1f55fee84 +b01eb8b2cf88c75c3e31807cfc7a4d5cafded88b1974ba0a9d5aaeda95a788030898239e12843eda02873b0cabe30e2b +a3ca290fa6ce064514a3431b44ecdb390ef500629270202041f23bc2f74038147f338189c497949fb3126bae3a6e3524 +93b0f8d02bd08af74918b1c22131865aa82aba9429dc47f6b51354ba72e33a8b56684b335a44661aa87774931eb85974 +81eebeb9bd92546c37c98e0a5deba012c159f69331a89615cf40c5b95c73dcdbf3ceb46b8620d94ff44fcdad88020c1e +b350e497932382c453a27bb33d2a9e0dbadf4cd8a858b6b72d1f3a0921afc571371e22b051b97da3bb08694c4ca3a4e8 +8c7052f63ba16f14fa85d885aa857d52f04b3a899a4108493799c90c0410de7549be85bec1f539f1608924668df48e5a +b397574d1fb43de0faaea67d1d9348d67b712b1adce300d6dc497bca94e0994eef8707c285c5c9ac0a66022655a8420b +a934661d2168ae1bd95b1143c2e5c19261708aeb795abad8ec87f23dc1b352fa436de997ebb4903d97cb875adb40dc2b +acf535fa1b77255210e1b8975e0e195624c9e9ffd150286ccd531a276cadc12047a4ded6362977891e145a2bd765e6b9 +8cc32356015d7fd29738dcc13c8008cdbe487755dd87d449ab569c85d0556a1ec520dbce6c3698fc413d470c93cb0c92 +8787c7b3b890e0d3734ac1c196588cacf0a3bde65e2cf42e961e23dbf784eef14c07337d3300ed430f518b03037bd558 +99da90994030cbc2fb8a057350765acac66129a62514bbd3f4ec29d5aab8acdd5f4d69ca83efe7f62b96b36116181e79 +a306424f71e8b58dfa0a0564b2b249f0d02c795c30eee5b0ad276db60423210bba33380fb45dbe2c7fedd6ee83794819 +b207a35d31ce966282348792d53d354bbd29ac1f496f16f3d916e9adbf321dc8a14112ca44965eb67370a42f64ca1850 +89e62e208147a7f57e72290eefccb9d681baa505d615ca33325dfa7b91919214646ca9bdc7749d89c9a2ce78c1b55936 +ac2d0ec2b26552335c6c30f56925baa7f68886a0917e41cfbc6358a7c82c1cb1b536246f59638fb2de84b9e66d2e57eb +8f1487659ecc3b383cebc23a1dc417e5e1808e5c8ae77c7c9d86d5ab705e8041ce5a906a700d1e06921f899f9f0ee615 +a58f1d414f662f4b78b86cae7b0e85dfddae33c15431af47352b6e7168a96c1d307d8b93f9888871fc859f3ed61c6efc +94f3626a225ac8e38a592b9c894e3b9168f9cf7116d5e43e570368ee6ee4ab76e725a59029006a9b12d5c19ddce8f811 +b5986e2601ad9b3260e691c34f78e1a015c3286fdd55101dcef7921f6cbcc910c79025d5b2b336d2b2f6fd86ee4e041e +b6e6798ddd0255fbe5cb04a551a32d4c5d21bdfd8444ff2c879afe722af8878d0a3a2fe92d63936f1f63fea2d213febf +86bea9bfffef8bc11758f93928c9fdfae916703b110c61fa7d8fe65653f8c62c6fecd4ff66a1f1a7f3c5e349492e334c +9595a4606284569f4b41d88111320840159fd3b446e00ec8afd7ddaa53dd5268db523f011074a092f8e931fc301a8081 +83b540a6bc119bf604a7db5f6c0665c33b41c365c12c72ca4fa7b0724115bbb0ff1ae38532c3356e8bb3ac551285929f +92c6daf961ca4eb25293e1794cf85cda4333cf1c128207af8a434e7e0b45d365f0f5baaefc4ebd5cd9720c245139c6e2 +b71465f3d7dba67990afc321384a8bb17f6d59243098dbed5abd9a6ffc7a3133b301dd0c6ca3843abbaa51d0953abbed +b15d93482d2ee5b1fec7921fcc5e218c1f4a9105a554220a4fb1895c7b1d7a41f90bbf8463d195eecf919fcbe8738c51 +a79c98e70931ffd64f4dcf7157fbae601a358261e280fe607eb70cef7d87f03efa44cf6ba0f17fbb283a9c8a437d2fdb +9019d51a6873331f8fe04cb45e728a0c8724a93d904522a9915c748360ddf5cdbf426a47b24abf2005295ed2a676cbf0 +b34cc339fec9a903a0c92ce265e64626029497762ff4dcaaf9bb3994298400ce80f4fb7dbe9ec55fe0c4a522c495cb69 +8fda9be7abfe3b2033cad31661432300e2905aef45a6f9a884e97729224887a6ec13368075df88bd75c11d05247bef15 +9417d120e70d6d5ca4b9369cba255805b5083c84d62dc8afec1a716ead1f874c71a98ad102dac4224467178fe3228f62 +a0a06b64867eebb70d3ce8aaa62908a767fb55438a0af3edf9a8249cd115879cde9f7425778b66bb6778cb0afeb44512 +a44309d3e1624b62754a3a4de28b4421f1969870f005ac5dc7e15183fa5b3ad182bcd09cca44924e03fbdb22f92f8cf8 +aea80f1c3a8fc36cfb5c9357d59470915370b2bec05f51f1d0e1d4437657e2303ba2d1ac3f64cf88f2df412dff158160 +b3f1557883d91b24485123d2f3ae0fce65caa533c09345ae6b30d2ac49953acee61c880c57975be7b4f5558d3a081305 +b52cb1e56f0d147cfb58528b29c7a40bab7cfc9365f2409df7299bfc92614269ff9de3cb2500bbc4909f6a56cf4b9984 +aa4f8fd0f5f87c177ee7242f7da76d352db161846cd31523a2100c069d9e4464170eec0bffc6d4da4f9e87017b415dbd +b5b61f52242985c718461a34504f82495d73cbb4bc51f9554b7fe9799491f26826d773656225f52a1531cd5bd6103cde +ad12ba9697804ede96001181c048f95b24ba60761c93fb41f4b4a27e0f361e6b1434e9b61391bacaf0705fdaa4a3a90e +9319286cbda236f19192ae9eb8177e5a57a195c261082ba1385b20328fb83ed438f29d263dddae2f5278c09548830c4a +88b01ee88c3a7ae2c9f80317dddbaa2b7b0c3a3c23828f03ff196e244500410c9ac81c2e2d3e1f609d4b36ee1732738c +8e31f30600a9d629488d44a008c821c3c57f13734eaee5a19f0182a2de9e538fff7d982980d7fcc725c969f29f7c2572 +b215740eea98b4bb14197a803a8975700ad2f25a25ef3628eae10166d56c823301f6dd62ce3f9ebf2d42d1f33d535004 +8fb0fdb253d4bcc6693642779be13a5b816189532763dfd7da868cfacfdb87cb5ebe53b18b69dfd721f8d4baf3c1d22d +8cdd050a447f431ff792156d10381aaf83c6634a94b614dd5b428274538a9cc1f830073533b4fd0a734d6dd4f8d9c4ce +81b01ee8c72ac668ad9dd19ead2d69cac28c3525e613e036e87aa455c2da9651cc8fcc97c451a8c8a071a4eb69623cd1 +8d9e02dc9ac83f861b3745bd69216232144c47cb468a7dbc49083ed961f978e34265b3f42c400339120bdc4644fe5711 +89e9410455b34cba9db0a5ea738e150fae54dd000d61e614f3274a6c8102ba7cd05b0936f484a85711ad9da7946f51ea +91f9d4949678f8e6f4b8499899818bdd0f510da552b5d79d8e09bf3b69d706ab36524b5e86d3251318899b9223debf6b +8b3c38eec7e1926a4be5e6863038c2d38ab41057bcfa20f2b494e9a0c13bc74c3a44c653402eb62a98e934928d0ebccb +a5cfe465bfbf6e8bfbd19d5e2da2fc434bd71acd651371087450c041aa55e3c4f822361e113c6c3d58646ed3ba89d6da +918665b8810bcb8d573ca88b02a02c62eaa5a4a689efb5c564b0c9183f78144e75d91fd1603e17d2c77586cbe5932954 +997dace0b739aeb52ba786faae5bdf1d48630a90321f9ceebfa9e86d189a3d79d7b04e459ac8e4adcfe83a5ce964eb1c +a5a1ca9f0ccc88017a616d481d912aab3f0e154b673f1131c5d9c9c3f5f147d25b6392b2c31e49f7bb7eb2697d05dbec +a76e99bec509eff01bf6767a06ac97ebc6671cb58bc3d4acc2803580a874885453dbba2e1bba26e45f8d2bda5f688860 +956c1362c8123c5d9ebff7049e851235d69fa645f211ef98e2b6564f2871114a12224e0ec676738d77d23c709dd28a6c +885efede83b1a3e96417e9f2858ab0c7a576fc420e8f1f26cabf3b1abeec36bcaa63e535da177847f5e0afdb211bf347 +affca2257f292a2db52f8b1bab350093f16f27ef17e724728eeaec324e2513cd576f6d2e003cc1c6e881334cb2e8bf22 +8dac963d34dcc9d479207a586715e938c232612107bb2d0af534d8da57ad678555d7c1887fadca6551c4f736ffa61739 +b55e600a6bbde81f5a0384f17679d3facb93a7c62ca50c81a1d520cf6e8008ac0160e9763cb2ca6f2e65d93ca458783b +9485e6c5ab2ebfb51498017e3823547b6ab297d818521ceac85cd6c3aa2d85ae075a0a264ae748fc76ce96a601462ffa +b4d8abca786c0db304a6634fba9b2a40d055c737ed0f933e1739354befdae138dae3c8620a44138f50ebeaf13b91929f +8bde7ca39c7bda95b1677a206b16c3a752db76869ea23c4b445c2ff320f2ee01f7358d67a514982ee3d1fb92b7bd7229 +8f8cd0acc689b6403ee401383e36cae5db2ff36fc2311bbadf8ebb6c31cbcc2ca4ffac4c049da5ba387761ef5ec93b02 +a06f42d5f69a566ff959139c707355bbf7aa033c08d853dce43f74a9933e6d7b90e72010ef3fcb3d12e25852343d1d31 +b10ece7cf6b69a76dba453b41049db0cdf13d116cf09c625312b150ee7437abd71d921eda872403d7d7ce7af1e6dccb7 +a3d820318e0f3b54fba7a4567912a82d6e6adf22b67cfc39784683a8e75f77538e793d9708aae228fa48a71abb596195 +8758fad55b68a260bea3bd113e078fd58d64a92f7935ff877f9f77d8adc0994b27040cfc850126c7777cfdfb2428a3e5 +b504913ee96c10f00b848cd417c555a24bc549bf5c7306140eff0af2ada8cb5e76bed1adb188e494332b210fbf24e781 +a00e019a40acc7aab84c1cc27c69920ad7205c2a3dc9e908a7ef59383695c9cb7093c4bcbc2945aab2655119552e3810 +b1000b4c4f306672e39d634e5e2026886a99930d81b8670a5d4046db9621e44997c4b78f583374a09c60995f18a6fd4f +a6c5053c4e748540ad2b622c28896c9d4ca3978ca4784ac8f09da5314a245f5cdc5d6203c84e6e0bcb3081829720a56d +8e37e67a70205a5c7da95de94ac4d0ebd287c1c9922d60c18eec1705030dfcbf74ae179e377c008bf5a8bc29c7c07cce +a66bd7c0243319b553d5cb7013f17e3504216e8b51ba4f0947b008c53bcb6b4979286b614a4a828ee40d58b5ef83e527 +97e2110b0fb485508a2d82ecc2ce1fbe9e12e188f06c7ef2ac81caeeb3aca2c00e5e6c031243b5ca870a9692e1c4e69b +8734ce8bbc862e12bea5f18d8a8d941d7b16a56ef714792fed912ca9c087497e69b6481fdf14efe1f9d1af0a77dac9b1 +b441dddac94a6a6ae967e0e8d7ab9a52eb9525fb7039e42665e33d697e9a39c7dcef19c28932fb3736e5651d56944756 +918b8997f2d99a3a6150d738daed2ff9eb1f5ed4a1c432d18eab4a898297f7ffbffd1e4ae9037acf589b1cd9e1185ef6 +a0247b8ac4d708cf6b398dc2d5c127a291d98e8bef5f195f820c4fddb490574ba4f62647c2d725237a3e4856eec73af0 +b45636e7e0a823c2a32e8529bb06fcccfd88e9964f61201ee116279223ed77458811d1b23bcb6b70508d16d4570a7afb +a99c1188fa22b30b04fda180d2733586ea6ef414618f1f766d240c71f66b453900d3645541c019361027aebe0a0f305f +b4c2f758e27fe233f7e590e8e0c6de88441164da3fcd5211a228318d3066dfdafc1d40246dd194f2b597f6fe9600b3d7 +972530819445b11374c3043d7855d5f1d3c4922b3b205d0bf40162c51605375dd0b61f49cd7f3d39a533a86a13005989 +992b533a13e5d790259bfdfdf1074f84a5e5a0a0d7be9cd6568cdc1662524f1a6666a46da36cea3792ba6707850f4d86 +9875d130457e04dc6ea2607309bfbb900ad3cb5f3e0574f808d27b20cbf6f88389d87dca19998680c5bc30d1df30a41b +adea8494a69e83221edf360ab847272b5c47eba5404665fb743d98c0682732c30085ae3ec82bc1e8e4aba8454c9b1849 +887d4c624ce05e224216c5f6fa13c5741012ac33330bc291754782f0bfe668decdc98c0e43a1ce28323effe6b639f477 +ab6b167aeb5e93ab155990b94895e7e7ff6dea91384854a42cc8a3b9983495b4b3c33ab1b60b2b6450ccf0418fada158 +a7588d0b7c6a6bc32fc474aa0f4e51dfb8e6e010346ad32c59d6f99e6f0522424111a03a4f56ba4075da8009ee7a63e9 +94d645cc3936db1563568193639badfc064dd5bda8d0631804ee00b09e141b200619e07506b5a8225130541436327194 +8d695c03cc51530bdc01ee8afcd424e1460d2c009e1d7765c335368e5c563cf01a2373c32a36400c10e2bf23c185ed19 +ad824a0a7ed5528e1f9992cbb2050785e092b1ea73edd7fb92b174849794a5b04059e276f2941e945bc0f3e46172f2af +ad6ed2af077a495d84f8eeed7d340b75c0d1c8b7c5a854dfc63ab40a3d0c2b0d45016d30b3373a13f0caae549f657976 +82454126c666023c5028599a24be76d8776d49951dfe403ebf9a5739b8eb2480c6934a34010d32cd384c91c62a9aa251 +b57070006793eca9fa2f5237453ed853994ad22c21deb9b835e1fb3fbc5ac73aec265a4a08de7afae1610dc8c42b7745 +ad94667c791cf58875eb77eb17b6ad02de44e4ba2ddc2efe4d0ff22a5e1a090c670354437847349fd61edc4ba5606f07 +b2aac0c345ffc00badaab331c12a22019617b004d32c099c78fa406d683744d96d51d1237ad0842f9f54655186f8f95b +8fed51076cc939b354e3b69034a594e6c9c98425ccf546154ab087a195375128444732388d2eb28f82877de971ec2f58 +8e521c0093deb9dff37888893db8ffebc139984e7701e68b94d053c544c1be0d85f0f98d84b2657933647b17e10a474c +a2c6c9a307aff9b1dea85f90fa9e3b8057fd854835055edeb73842a7ef7c5ae63d97c51fec19dd8f15d696a18a0424a6 +a3390b25a9c11344ed1e8a0de44c848313026067a0f289481673c2c0e7883a8fc9f6cab6ccd9129729a6d8d0a2498dc2 +82770c42b1c67bbd8698c7fe84dd38cc5f2ad69a898097a33b5d7c5638928eb1520df2cb29853d1fa86a0f1bcc1187e8 +a6fdf7a4af67bc4708b1d589135df81607332a410741f6e1cc87b92362a4d7a1a791b191e145be915aa2d8531ee7a150 +aecac69574188afc5b6394f48ba39607fe5bb2aa1bd606bc0848128a3630d7d27101eb2cea1fb3e6f9380353a1bb2acc +a23fd0c52c95d0dffb7c17ec45b79bf48ed3f760a3a035626f00b6fe151af2e8b83561d0b9f042eaae99fde4cbd0788d +a5f98068525cdd9b9af60e0353beb3ac5ac61e6d3bac1322e55c94b3d29909d414f7f3a3f897d5ae61f86226219215c6 +b2a4d724faac0adf0637c303ff493a1d269b2cdbec5f514c027d2d81af0d740de04fb40c07344e224908f81f5e303c61 +adeadb3521e1f32ef7def50512854b5d99552e540ec0a58ea8e601008de377538c44e593e99060af76f6126d40477641 +a18b7fc2fcd78404fed664272e0fef08766a3e2bc2a46301451df158bd6c1c8aa8cf674dd4d5b3dedfaceb9dd8a68ae3 +83bcfb49313d6db08b58c6827486224115ceef01ca96c620e105f06954298e301399cdd657a5ff6df0b0c696feec1a08 +8c94391eba496e53428ec76dfe5fa38f773c55c0f34a567823316522a0664a3d92bff38ec21cf62ac061d7d1030650c5 +b1fa196ccfd7d5f1535b2e1c002b5cde01165c444757c606b9848bc5f11b7960973038fb7cc3da24300fc1848e34c9af +b139f6c6449449638de220c9d294e53fc09865a171756d63bbf28ec7916bf554f587c24bddf51dd44372d15260d8fe25 +b716242299d4ee72b5b218781b38ca5e005dcf52333364f85130615d1dbf56216af8ee2c9c652d82f7aab5345356538c +9909f24e4ad561aa31afd3a3b9456b2bd13a1d2e21e809a66af62fec5f95b504507ac50e81d2233da2b223f5443e7585 +ae863530a02cf3a757f72b945c8c0725d9f634d2ff26233478d1883595ff9a1eef69e8babffdbfa161452fc204f5b5a1 +8eb82bde283b6a6e692b30236cbf41433b03eda8dad121282772edd56f144b1ebf5fb489d18c6ce8776135771cbb91e2 +9296141fadf8dadc885fff4999c36efa25ec76c5637a8300a1a7dc9cf55bcedfe159e0ef33f90eee9be8c4f085734e10 +b6c07f2e6fcbd6c42a8b51e52fbcd5df3aa9f7c3f0b3c31021de1aec2111d0a1c36b5ab489ba126af44fd43cf31c2594 +a70ca669c357535b363d16b240fd9cb9c5ba1b648510afc21218ea034e9bf5f22717ae31ff43ef89dded95b7132fa58f +b350721f8f6b4d164fd08aca30cd4dece9b4a81aed0ac12119c9399bab691d5945814306f9a61f0106b76d4d96f7b9d6 +b6886076c9d8c344bf3fb6975173d00fa82866012894f31c17e6fc784fbc0dd2d24d6a1cddd17f7379c74566a23219aa +87636e4a83ceadc170a4b2517b19525c98e2163900401996b7a995b2f3da8d6ba2ab92f909eade65074fac07cf42f6fa +8ff61d87c4699a067a54b8540e8642f4c7be09d3783ec18318bcba903c6714fcd61be69165e07e1ca561fe98e07507de +85485d6b569ac20e6b81a9e97ef724e038f4fee482f0c294c755c7b6dad91293814f143bfcfc157f6cfa50b77b677f37 +a49256cb1970cc1011a7aed489128f9b6981f228c68d53b1214d28fbcfb921386cc7cf5059027e667a18073efa525a74 +87bc710444b0c3e6682d19307bedc99c22952af76e2d851465ee4f60e5e1146a69f9e0f0314f38a18342e04ece8e3ed3 +a671a6cabfd19121a421fdfe7732eccbb5105dfb68e8cbcf2b44ae8465c99e78c31b99730beca5bc47db6fc2f167203a +a2f3270c184629f6dfc5bf4bdd6e1b8a41e8840a1e4b152253c35c3d9e7ab4b8e3516dc999c31f567e246243e4a92141 +b9795a5a44f3f68a2460be69ecacdbb4664991ebbedffed5c95952147ad739e2874c099029412b9653d980a2d4307462 +959053faec9a966dd5a4a767a3154e4b8e4f56ca540ae53e373c565dda99fb626f725e5a5e3721c82918f8c5f2e9e0a3 +b3ef9d6a1b3cd44a3e5112819fa91cb8a7becc3f5b164c6f759f93171d568497b01c8e743f4727b341a1296a0dbadf4f +b852dfdfbe2b8c77d938fad45f00737e14eacf71d5fecbb3e4f60052ec9efb502c38c1fcecaf71da69eabe8b33852a67 +921c7007f26bdd4139e919dfe27d87b489a0bc5bd6fb341e949e4451f14c74add0489b108c9c9666a54c5455ac914a9f +86b63d73ba31c02e5337f4138e1684eccdc45ab5e4f30e952fb37d638b54ecec11010414d7a4b7aa91f7cc658f638845 +853c55e0720b66708a648933407795571fc11ad5c234e97f92faabce9e592983dfb97a1705047ee803648ecf9fbb2e5c +995fe7d1dc09bb0c3c3f9557c4146534778f5ea9c1d731c57440fdcf8094f82debf19090b5d23298da1ed71c283b3ae5 +b9c49c911a0c4d716b7baec130f9e615bfa7d504aa8766ed38878a93c22b1f6353503d4f7f425d4902239fb4689429df +80504d964246789a09dcd5c0298680afb6fe50bca3bb9c43d088f044df2424a1828de10e0dbdc5c0aac114fa6d9cf5d1 +90249351f109f6b23a49a610aaa3b2032189fd50e5e87cdc3b20f23ed4998af3a8b292bf9fbab9bd1cbe0a1371081878 +abb5f0148850f0d80b429c2b9e0038772432340ef0862ccb5dcb7347026ca95bf9a5857f538e295aebd3a6a5027adb4c +b92ac9c0f7e73150798348265e5f01f3c752480c72613c6894a95e9330bba1c642b21b9cbd8988442b5975476634b4fa +af3fbcc825abd92c6d7ea259467f27045e288f27a505e6a3c9ec864aa08fcaca0d4123034513dbd4c82d4814075708ab +a738232a66030e0e9c78e093a92fcc545b10e62fb0ecb832bbbc71471b28eb6ec422a498c2402e2c6d74983df801e947 +ae60194ce2035edd1af253b9eefbb4b1b7609c9678256c89c3cb076c332a9f4442c3441ad2ecc9d73265359bdadc926c +8b2fd55e686f16725fc0addb4065f696275852320b03221fd22889825d66fae5bb986b03c47452e32b3a32c1fdfc8dfd +8e2e1a36673b7729b07e7bc5014584e1c03e9552f7440fbfda0a6a7f41953947fcdf8d666f843bfc03dcca5b06a14318 +95a3df04368c069f3fd32a20b627c5f043e952167c9e80bf5914bbf2086879909c60e089bbd488725ab977c0e6051728 +9856403b2211d0152d4eec10db7ec34c16ac35170714b75af3ebc398a676c171b24b6f370361de0f9057ba444293db14 +a2cb484b758af5fd8e2baca7f0406f849c71255e58ef110d685cd0c1137893a25d85a4d8582e3ced7dd14287faa95476 +b0f697b6a42f37916b90ab91994ae4a92c96dc71e4da527af41b9d510bc2db5a9b4f29183a758074b6437a1e62b2d1d7 +b39c49266aae46f257b7ae57322972fb1483125298f9f04c30910a70fe5629dba0ec86b94cc6ba16df3537a55e06f189 +86cd5595b5b769dfd9ceb68b11b451f6c5b2e7a9f6f6958eac8037db1c616e8a9defb68a0d6c2287494d1f18076072c1 +b462e8fa9a372d4c1888fd20708c3bed1cb00c17f7d91a0481238d6584fbbf2d238e25931154f78a17296a12825d7053 +a5ef28286628ba509bac34c9f13158d0013239fdca96b5165161f90b89d6e46295822ebdf63f22d7739911363a0e0e86 +a629a95a24e2545862b41a97ecba61b1efa792fd5555dc0599c175947e9501bffc82b05a605fd5aabc06969ccf14fff4 +af83467e4b1f23a641630cc00c38d4225ff2b4277612b204d88de12a07d9de52fb4d54a2375a7fd91eb768623c255376 +a630f29fb2e9a9e2096d7f3b2f6814ee046ebc515f6911d4bc54ad8a5a821a41511ff9dcfbe3176f35c444338ecd0288 +950dedc11bd29e01ba9744bec681ad9462127c35e9fcadfacc9405ec86b985a1b1c4f9ac374c0f1fa248212e5e170503 +82e8e7be8011ee0fd9c682d26a0ef992d0191e621d07fd46a3a5640ef93a42e1b98a33cad1f8017341a671d28caebb03 +a075860554e712398dac2fb0375067a48d0e4ca655195cefc5ccb1feb8900d77124aa52a12e4f54f7dab2a8f1c905b5b +81d2183d868f08714046128df0525653a2dc2ff9e2c3b17900139c9e315b9f4f796e0fb9d1d8cbadbaa439931c0e0879 +81fb1456969579515a75fb66560f873302088cde2edc67659b99a29172165482ca1f563758c750f00086b362ae405322 +a13c15ab19203c89208c6af48d2734bb0873b70edb660d1d5953141f44db9012528d48fb05aa91d16638cbda2ca8f0cc +8ba46eef93e4ec8d7818124a0b9fcfe2bcf84a98db3545d2b3d0192cfadc81fc667dcc22ab833c3e71508d0f3c621fe4 +b9bd60d2266a7d01e1665631a6ed6d80ffc0cd7f088f115a5d4ea785c518a8f97d955e2115b13c4960302b9825526c92 +b26fa4e87142150250876083a70c229249099331410f0e09096077fdf97b31b88dc57a3e3568d2a66a39af161cf5dfec +b9d147564124728b813d8660ba15fa030c924f0e381ad51d4e0cf11cc92537c512499d3c2983dd15f2e24ca166070d70 +b6fb44e1a111efb3890306fa911fafda88324335da07f7de729b2239921ef15b481630a89c80e228bec7ab6444a0b719 +a6cd9c7acac052909ef0cf848b6012375486b59b7bac55b42c41f0255b332c1d45a801f6212d735be8341053bd5070b9 +864258d69234786af5de874c02856fc64df51eff16d43bfb351b410402ab28f66895aec4025e370a4864f19ff30fd683 +84370fa1243b64b3669dd62e1e041ff9bd62810752603486aac3cba69978bd5f525c93cbc5f120d6f2af24db31ec3638 +b983c2cdc1a310446de71a7380b916f9866d16837855b7d4a3a6c56c54dab3e373a6fc6563b8309dc3b984d4e09275d6 +914f8587f876470f7812fa11c6f67e2dd38bf3090e8928e91fe2fe5595bee96cbe5f93d26fdced6b4e7b94f75662b35d +8b47bcb111d91aa3d80e4ceef283824aa00d1faeb6fe4111aecd9819869c0e1f6f4b6fb2018aebb07a0f997412cda031 +95b2befa98f9992450ca7ff715ae4da8c36dd8adcfef3f0097de6e3a0b68674b05cbf98734f9665051bb4562692641e0 +8bcd1651a2bfce390873a958e5ff9ca62aac5edd1b2fd0f414d6bcf2f4cf5fa828e9004a9d0629621b5e80fbbd5edb90 +af79bed3c4d63239ac050e4fa1516c8ad990e2f3d5cb0930fc9d3ce36c81c1426e6b9fe26ac6a416d148bf5025d29f8b +881257e86b7ab5af385c567fde5badf67a8e7fff9b7521931b3ce3bac60485c0fe7497339194fb7d40e1fad727c5c558 +a1b40b63482cd5109990dfb5a1f1084b114696cbbf444bf3b4200ab78c51dad62c84731879ea9d5d8d1220e297d6e78a +b472212baa2a31480791828ca5538c3dcc92e23f561b0412f8cc9e58839d1625ddcaf09c8078d31ac93470436843cd74 +8f516d252b1863cd3608d852a2857052bb2a3570066d4332fa61cb684b10ac8d1a31c8d32f2a0d1c77eee2ad7a49643d +8d20b75c51daa56117eda2fd5d7a80a62226074b6a3ff201519f2054eecfeff0aa2b2f34b63bea3f53d7d0ce5c036db9 +8282f433229e7948a286ba7f4a25deb0e0a3c5da8870562c3646757bef90ca1e8d3390b0a25b3f2bf45bf259a4569b77 +8a2dbf4b55cc74f0a085d143a88ebc8c2a75a08eab2703d13a00b747eaddc259a3dd57f7330be938131835a6da9a6a68 +aa0bc51617a938ea6a7b0570e98b8a80862dd9e1cf87e572b51b2a973e027bcd444ef08e0d7b5dee642e0da894435e91 +aa7319ca1ac4fe3cc7835e255419eeb7d5b2d9680769cc0ca11283e6147295db75713b71a9312418a8f5505cd45b783d +ab3f9c465663dc90fae327a2ee9cb7b55361a9b6fbe713540a7edd3cff1c716802fb8ad4dd8fb0c945d96b3b44c5795b +913a2ae88acffab12541fc08920ee13ab949f985a117efe9a5b2c76f69f327f60c5b5ad3fa5afa748034ac14298fc45a +9008f044183d2237b723b235953e4d8b47bec6a7b300d98075555478da173b599ba9c7c547c2f111ce1fae5ac646e7a3 +a26b4cc42b353e1c18222d2e088d7f705c36be12e01179db440f10fcfa9691d31fc4fc7e7ee47876f1624e6d44be1021 +995e75824f322294336bfa2c5d1a319f0d77f6a0709beabaf1b43015d8a78d62447eab907349524734170f0294d1ca7a +8b96f04a19dbe4edc71d1f2c6d3475ae77962e070ec5797752453283c027c6b29b6e58e8b7eb5c3f9770557be7e80b67 +8621459865234734bcfaa492ca1b89899525198a7916ccc6f078fb24c8bf01154815bb5b12e1c3d0a10bd4f1e2ea2338 +ab52174541185b72650212e10a0fe2e18ccfd4b266a81233706e6988c4af751b89af87de0989875f7b5107d8d34c6108 +966819d637bdd36db686be5a85065071cf17e1b2c53b0e59594897afc29354ecba73bf5fc6fa8d332959607f8c0a9c27 +b7411209b5ab50b3292c3a30e16f50d46351b67b716b0efb7853f75dc4e59ec530a48c121b0b5410854cd830f6c4b3ea +a5dc04adbadce0af5dc1d6096bad47081110d4233c1bf59a5c48a8e8422858620f4be89bf1f770681be2f4684ee4cce7 +af77a8f83cffb5f8d17be0ab628dedcad63226c9b13ce4975fb047f44bfef7d85e7179aa485abb581624913eddbb27ec +82bf28dc58c893c93712ce297cc0d64f70acb73a641cb4954ccf9bf17597f6d85eecf5a77c8984ab9afbe588562a0ee9 +988a7cef9a178e8edb91f3ec12f878fd68af2ac0762fa0a48a2423e24f765ed8f7837429fd8bc0e547e82e6894e63008 +a5d5969311056d84b3ee87f49286fac0bd9a7220c196cea4f9dced3b858dcdba74718eab95b38bd5d38d2d1184679c98 +af4d51b3ded0aaad8f12bef66c0616e9398fc42618852ac958e6ab2984a720a6111ac55b249d7e4523051740e12b346f +ac635b4a49f6fbb94a5f663660f28431ba9f7c5c18c36ebc84fd51e16077de7753595f64619b10c16510ecbc94c2052d +ae25eb349735ced1fe8952c023a9b186a1f628a7ddf1a4b6f682354a88f98987ac35b80b33189b016182f3428a276936 +ae3ab269690fdd94134403691ba4f5ed291c837c1f5fdc56b63b44e716526e18abb54f68ca5d880e2fb7bea38e74c287 +a748b03b2bd3fbc862572bc4ddc0579fa268ee7089bcfd0d07d0c5776afcd721302dbb67cb94128e0b1b25c75f28e09a +8f09a2aaa9ba3dfe7271f06648aba9cc1ea149e500a7902d94bb9c941a4b01d1bb80226fd0fd2a59ad72c4f85a2a95d0 +853d55ad8446fd7034e67d79e55d73a0afcb5e473ed290e1c3c7aa5497e7f6e9bbf12d513fc29e394a3dc84158a6d630 +b1610417fb404336354f384d0bf9e0eb085073005d236a0b25c515d28235cea5733d6fbd0ac0483d23d4960064306745 +86de805b3d4f6fbb75233b2cf4d22fcc589faa2ac9688b26730cb5f487a3c6800c09bb041b2c6ab0807bfd61b255d4c9 +893b38c72cf2566282ee558d8928588dca01def9ba665fcb9a8d0164ee00dedafbf9d7c6c13bcc6b823294b2e8a6a32c +8e50de7a70ac9a25b0b5cf4abc188d88141605e60ce16d74a17913a2aff3862dec8fbbf7c242cf956f0caae5bcc4c6bf +b5cf09886a4fb4ce9ea07d1601d648f9f9d1a435b5e1e216826c75197cd6dafd6b2b07d0425a4397a38d859a13fdb6dc +859dc05daf98e7f778a7e96591cc344159c1cbe1a7d017d77111db95b491da0a9272866d2638a731923ca559b2345ebe +8ff1792f77ecdfbd9962f791a89521561c7b82031a4e53725f32fe7d99634a97b43af04cbf3e0b0fdff4afa84c49eb99 +81e2cd8a221b68ae46dd7ce97563bd58767dc4ce1192b50ff385423de92206ff585107865c693c707e9d4ed05f3149fb +8fce7da7574e915def0d1a3780aa47ef79b6d13c474192bd1f510539359494ddc07e5412f9aac4fc6c8725ade4529173 +ac02f5df60242734f5ead3b8a62f712fefdb33f434f019868a0b8ddf286770244e2ddfb35e04e5243ba1e42bcd98a6a5 +a8d69783349a442c4a21ecb3abd478a63e2c24312cb2d2b3e10ea37829eb2226a9b8d05a8c9b56db79ffaa10d1f582d1 +b25b5cca48bf01535aba6d435f0d999282845d07ac168f2ca7d5dba56ee556b37eab9221abdb1809767b2de7c01866c1 +8af7e1d1f4df21857d84e5767c3abe9a04de3256652b882672b056a3ab9528e404a8597b1ad87b6644243f8c4cd3799f +a6718308dfa6992ae84fcb5361e172dbbb24a1258a6bd108fd7fc78f44cc1d91be36e423204a219a259be4ab030f27ff +b99cbe3552c1a5259e354c008b58767c53451932162e92231b1bebfc6a962eb97535966a9bd1dfd39010dfcda622d62a +a8458f6b8b259581f894e4b5ce04d865f80c5a900736ca5b7c303c64eaf11fe9cb75e094eece0424ba871b2aee9f7a46 +914f763e646107b513c88f899335d0c93688ffa6e56c3d76bff6c7d35cb35a09f70dc9f2fe31673a364119c67cd21939 +9210f2d39e04374f39b7650debe4aceeb21508f6110ab6fc0ab105ec7b99b825e65753d4d40f35fad283eeff22a63db0 +98729cf927a4222c643b2aa45b3957b418bce3f20715dd9d07997a3c66daa48dd62355dbd95a73be9f1d1516d1910964 +a602c399f1217264325b82e5467a67afed333651c9f97230baf86aec0dd4edeae1e973cafef2ea2236d6d5b26719954d +ac9632921d45900bf3be122c229ba20b105b84d0f0cba208ccdce867d3e9addfb3ef6ece9955950d41e1b98e9191ef42 +a76ce1f53e1dc82245679077cb3bca622558f2269f2d1a1d76b053896eba1c3fc29d6c94d67523beb38a47998b8c0aa7 +b22b51fcc1b328caa67cc97fb4966cb27d0916488a43248309c745cd6e2225f55ad8736d049250fa0d647e5f8daa713c +b7645c1923a6243fa652494fe9033fa0da2d32a0fb3ab7fcb40a97d784282a1ffad3646c499961d4b16dadbc3cbb6fd6 +acab12b490da690db77c4efdc8b2fe6c97ac4ba5afb5165d6647fdd743b4edbad4e78d939fc512bebcf73019c73bae40 +ad7a0fcd4e4ccb937a20e46232a6938fccf66c48a858cf14c8e3035d63db9d1486e68a6bf113227406087b94a0ece6a0 +a78605beaa50c7db7f81ab5d77a8e64180feea00347c059b15dc44c7274f542dc4c6c3a9c3760240df5f196d40f3e78b +8763315981c8efa9b8ae531b5b21cfc1bbc3da3d6de8628a11dcc79dee8706bd8309f9524ec84915f234e685dd744b69 +b4a6c48531190219bf11be8336ec32593b58ff8c789ee0b1024414179814df20402c94f5bfd3157f40eb50e4ef30c520 +8dac8a3f152f608ce07b44aee9f0ed6030fa993fd902e3d12f5ac70bf19f9cde2168777d2683952a00b4b3027d7b45ea +8baf7dfae8a5840c5d94eabfe8960265f6287bb8bc9d0794a6d142266667a48bec99b11d91120907592950a0dddc97d9 +b8595e6ea6b8734d8ae02118da161d3d8d47298d43128a47e13557976032dad8c2ccbfff7080261c741d84d973f65961 +8b93979c51c8d49f4f3825826a5b9121c4351e0241b60434a3c94f2c84f0b46bbf8245f4d03068676166d0280cf4f90c +aceb0fdaf20bf3be6daebf53719604d3ab865807cc2523285f8fef6f3fc4f86f92a83ad65da39de5bd3d73718a9c4bd2 +814dd41764a7d0f1a14a9c92e585f154a26c8dbf2f9bff7c63ae47f1ac588cec94f601ccc12e8a63a7a7fce75a4287f2 +b47b711848e54fa5c73efc079d0a51a095fa6f176e1e4047e4dac4a1c609e72099df905958421aee0460a645cba14006 +aaf7bd7e1282e9449c0bc3a61a4fca3e8e1f55b1c65b29e9c642bb30a8381ce6451f60c5e0403abc8cee91c121fa001f +b8b0e16e93b47f7828826e550f68e71a578a567055c83e031033c1b7f854e7fc8359662a32cc5f857b6de4aff49e8828 +b3eb70b8c8743a64e1657be22a0d5aeb093070f85a5795f0c4cb35dc555958b857c6c6b7727f45bf5bedf6e6dc079f40 +ae68987acd1666f9d5fa8b51a6d760a7fb9f85bf9413a6c80e5a4837eb8e3651a12e4d1c5105bfb5cfa0d134d0d9cfc2 +acd8fa5742b0bac8bd2e68c037b9a940f62284ff74c717f0db0c033bf8637e4f50774a25eb57f17b2db46e5a05e1d13d +a98dac386e7b00397f623f5f4b6c742c48ab3c75d619f3eaf87b1a0692baf7cb7deac13f61e7035423e339c5f9ae8abf +99169bd4d1b4c72852245ebfbc08f18a68fb5bcce6208dd6d78b512b0bc7461f5caf70472b8babf3e6be2b0276e12296 +937d908967f12bf7f728fe7287988c9b3f06c1006d7cd082e079d9820d67080736910bc7e0e458df5bae77adb9a7cbc1 +8c50e90ce67c6b297fd9406c8f9174058c29e861597a0f4ed2126d854a5632fa408dfa62ad9bb8b6b9b6b67b895d5a4d +8f4840a91b0a198226631a28e7a2e893fc6fed4d5eb3cb87b585aac7f4e780855a353631ad56731803296f931e68a8d0 +96a4b8c64d3d29765e877345383bf0e59f4ac08798ac79dd530acd7f3e693256f85823ad3130fb373d21a546fe3ca883 +b0dce7a6ab5e6e98b362442d6e365f8063ba9fef4b2461809b756b5da6f310839ac19b01d3fd96e6d6b178db4ff90ee1 +8f012cb2be5f7cb842b1ffc5b9137cafef4bd807188c1791936248570138f59f646230a1876f45b38a396cbdd3d02e08 +94a87b5ce36253491739ca5325e84d84aaff9556d83dcb718e93f3ff5d1eecf9ae09d0800a20b9e5c54a95dfebfcecd3 +b993ec5f9e82cc9ceeb7c5755d768bc68af92cc84f109dfaf9cf5feb3aa54881e43c3f598ba74ed98e8d6163377440ca +92f845d4d06a5b27d16aef942f1e3bcbe479b10fef313f9ca995315983090511701b39ccbb86b62d0c7c90a2d1f0c071 +b6ec6da0f9e7881e57fa3385f712e77f798abc523609a5b23e017bb05acc6898825541aed7fe2416c4873de129feceea +86b181183655badfe222161d4adf92a59371624a358d0ec10e72ee9fa439d8418f03d635435ec431161b79fd3fa0d611 +b5e28eeed55fb5318b06a0f63dbf23e00128d3b70358f1c6549fd21c08ef34cb1372bc0d4b0906cc18005a2f4cd349bf +85c4d3fddda61dbfb802214aa0f7fc68e81230fb6a99f312848df76cddc7b6dfd02860e8a4feb085dad1c92d9c6c65e0 +80f7fdec119309b2ac575562854f6c2918f80fc51346de4523ec32154d278f95364fdef6f93c7d3537a298dd88df7be6 +9192c1949d058614c25f99d4db48f97d64e265a15254aa6ed429e1ef61d46aa12355769f1909a5545cd925d455a57dbe +a0b1e7d928efc4dcbd79db45df026ae59c20c1a4538d650c0415ab7cb0657bc1e9daeacc3053ee547e8f9c01bdbd59c4 +893e84c41d3a56bca35652983c53c906143b9ad8d37b7c57f9dacbeb7b8dd34defc6a841f5b9857ffb90062bbd8e9dee +a7f89a448349dbc79854cf888980327f92aedc383c7fadd34fdc0eaa4f63d751315b4f979e14f188854ef4d16c9e8107 +833f2774a96187805f8d6b139c22e7476bce93bc5507344d345008080fb01b36d702b96e4c045617a23a8ca1770b4901 +80e46e86d68bd0a48ac6fa0b376d5bb93a5d6b14f08b3a47efa02bb604c8828c2047695f1f88fc5080e5548e1a37130f +943f42b7b4ad930059a26ad06b62e639f06c1c425d66066c55134e97c49abe412358c7cb994fcc1cf517ea296bca1f68 +8b9d4fe835dc6a2cbf85738937bbfb03f0119ab8df04a7d68860716ce6ee757dbe388a1e8854ddb69fe0c9fa7ed51822 +909030c7fde2591f9ea41ae6b8fa6095e6e1a14180dda478e23f9c1a87b42c082a1ea5489c98702f6ccd2ba5812d1133 +a715ec1beb421b41c5155c7ef065bbb50b691d0fa76d7df7ee47683d9e4eb69b9ea3e62fc65196a405d6e5e29e6c2c60 +8c9e801cb7ef780a535be5c2a59b03e56912acbfdb00447bfa22e8fc4b11dceecc528f848d5fba0eec4237d6f81f4c79 +b96b6af857c3bc0344082bd08ec49a9bed478d4d35b85a2099b1849cd6997521c42225305f414cdd82aef94b9e1007d3 +8764db720b4e44a4d2527f7f9b535a494a46c60e28eac06bf1569d0703c4284aefa6cb81fbba9d967286f9202d4b59ea +a66fd2f9158e1ffcdd576cba1413081f43eed00c7eb8f5919226f7b423f34ac783c1c06247819b238de150eb5a48d977 +82c52e817ac3bb0833ea055dec58c276c86ca5181811cf7a483b3703a06ea1bee90ae3aeaa2cffeaeba0b15fe5bf99be +987d07cb276f7f03a492cfb82bba6d841981518286402d3e69e730a9a0e29689a3619298124030da494e2a91974e0258 +b34f2c5740236bc6d4ae940920c5bc2d89ff62a3dd3a3ec9a0d904d812b16f483073db1e53b07f2b62e23f381d7bdbe5 +a1c0679331ab779501516681b3db9eefb7e3c0affb689e33326306ada6d7115fafd2cc8c1c57b2fa6c2072552f90a86e +94805e30d7852fc746e0c105f36961cc62648e438e8b9182fc0140dbf566ec14a37ad6e7f61cacb82596fc82aed321e5 +a42fb00b29a760141ff0faaeb7aca50b44e7bbc0a3f00e9fb8842da7abfcaae6fae9450abe6ba11e8ecf11d449cbe792 +8fb36ce4cfa6187bfe8080ac86b0fa4994f20575fb853bd8ffa57c696179cc39f58ff3b4bd5a2542ff1c8b09015539df +a1c54e7aa64df7fb85ce26521ecfc319563b687ffecd7ca9b9da594bbef03f2d39f51f6aaff9a3b5872d59388c0511c6 +855e48fdb8f771d4e824dbedff79f372fd2d9b71aa3c3ecf39e25bf935e2d6e0429934817d7356429d26bf5fd9f3dd79 +8ae6157a8026352a564de5ee76b9abb292ae598694d0ea16c60f9379e3bb9838ce7fd21def755f331482dc1c880f2306 +a78de754e826989de56fe4f52047b3ffd683c6ceaf3e569a7926f51f0a4c4203354f7b5cfa10c4880ba2a034d55a9b0d +97609477d0a1af746455bbd8cb2216adacc42f22bfd21f0d6124588cd4fec0c74d5bde2cdba04cdbfbff4ac6041b61b1 +a03dc3173417381eb427a4949c2dbfa0835ef6032e038bf4f99297acf4f0ba34a5fc8ccf7e11f95d701f24ee45b70e27 +aad6283e85cd1b873aeb8b5a3759b43343fdadc9c814a5bf2e8cf3137d686b3270f1ec2fb20d155bbfd38c7091f82c44 +92ab94ed989203a283d9c190f84479c2b683615438d37018e9c8de29c2610bb8fccd97bb935dca000d97d91f11a98d65 +8c0444a0b9feb3acb65a53014742e764fa07105e1c1db016aec84f7a3011d9adc168dbba8034da8d0d5db177a244d655 +95a33d25e682f6c542d4e81716cc1c57ef19938409df38bf8f434bc03193b07cedd4e0563414ce00ab1eebbd3256f3e7 +8716c30e3e4b3778f25c021946c6fb5813db765fde55e7e9083a8985c7c815e1b3d3b74925ba108d9a733ddf93b056af +a186aabc10f1fff820376fa4cc254211c850c23a224f967d602324daec041bbe0996bf359ed26806a8c18e13633a18a8 +a1e8489f3db6487c81be0c93bade31e4d56ec89d1a1b00c7df847f5cd7b878671015f5eaa42ee02165087991936660b9 +8f688c969c1304dfa6c1a370119d1988604026a2ab8e059016c5d33393d149aae6e56f3ee2b5d25edc20d4c6c9666ad9 +91950b651fefd13d2fa383fd0fdc022138ce064ee3b0911157768ad67ed1fb862257c06211cf429fba0865e0b1d06fc8 +86cff4080870d3e94ed5c51226a64d0e30266641272666c2348671a02049ae2e8530f5fb1c866c89b28740a9110e8478 +88732c4d9e165d4bb40fb5f98c6d17744a91ff72ca344bc0623d4b215849a420f23338d571a03dd3e973877228334111 +afcc476ad92f09cf2ac7297c5f2eb24d27896d7648ba3e78e1f538c353ceeb1e569917a2447f03f3d4d7735b92687ba5 +b622aa475e70d9b47b56f8f5026e2304d207684726fb470a0f36da7cb17c30dd952813fab6c7eb9c14579aacca76f391 +802cf5630c0407ae0d3c5cf3bef84e223e9eb81e7c697ea10ec12e029fc4697ce7385b5efab7014976dacc4eb834a841 +a08596493f4cd1b8ac2ec8604496ee66aa77f79454bb8ab6fdf84208dc7607b81406c31845d386f6ac8326a9a90e7fc5 +a54652ca9e6b7515cb16e5e60e9eabbccbc40bb52423d56f0532d0bac068aec659a16103342971f2cc68178f29f695db +a3ab54875cb4914c3a75b35d47855df50694310c49eb567f12bbc5fa56296e11f4930162700e85ba2dbfdd94c7339f91 +94183a040285259c8f56bef0f03975a75d4def33222cc7f615f0463798f01b1c25756502385020750ac20ae247f649a1 +b0004261cc47b0dc0b554b7c6ebf7adf3a5ece004f06e6db3bbac880634cdf100523b952256a796998a5c25359f12665 +a25dfeb0e18ebe0eb47339190f6a16f8e116509ab2eef4920f0d3ff354e3ead5abe7f5050b2f74f00b0885ea75b4b590 +ab10ef2f5dc0ede54e20fa8b0bce4439543db8d8b31e7f8600f926b87ec5b8eea0ac2153685c7585e062ffac9e8633c3 +8386eac1d34d033df85690807251e47d0eaacb5fe219df410ab492e9004e8adabb91de7c3e162de5388f30e03336d922 +b6f44245a7d0cb6b1e1a68f5003a9461c3d950c60b2c802e904bc4bc976d79e051900168b17c5ac70a0aed531e442964 +ad12f06af4aa5030b506e6c6f3244f79f139f48aec9fc9e89bbfbd839674cfd5b74cea5b118fb8434ba035bda20180af +88511306dfe1e480a17dba764de9b11b9126b99f340ceb17598b1c1f1e5acbdd1932301806fe7e7e5e9aa487a35e85de +a17cdf656e1492e73321134a7678296a144c9c88c9a413932d1e4ca0983e63afc9cdc20fd34b5c6a545436b4db50f699 +b555b11598a76de00df0f83f0a6b8c866c5b07f7ac2325f64fb4a0c2db5b84e0e094d747186c3c698ee4d0af259dc4c7 +88014560587365e1138d5b95c2a69bdae5d64eb475838fee387b7eb4c41d8c11925c4402b33d6360f0da257907aa2650 +b220634e6adee56e250e211e0339701b09bf1ea21cd68a6bd6ee79b37750da4efe9402001ba0b5f5cbbfcb6a29b20b0c +ac5970adc08bc9acec46121b168af1b3f4697fb38a2f90a0fbc53416a2030da4c7e5864321225526662d26f162559230 +97667115b459b270e6e0f42475f5bce4f143188efc886e0e0977fb6a31aba831a8e8149f39bc8f61848e19bcd60ceb52 +b6c456b36c40a0914417dd7395da9ed608b1d09e228c4f0880719549367f6398116bf215db67efe2813aa2d8122048f2 +ab7aef0d6cda6b4e5b82d554bd8416a566d38ded953ffd61ef1fcca92df96cdcc75b99a266205ff84180ab1c3de852a4 +81d354c70ce31174888c94e6cf28b426e7d5c4f324dc005cd3b13e22d3080f3881d883ca009800f21b0bb32fa323a0cf +94f3440965f12bee4916fcc46723135b56773adba612f5ce5400f58e4d4c21435e70518bdef4f81e595fa89e76d08fc6 +a6683e7a1147f87cbeeb5601184cc10f81bca4c3c257fd7b796a2786c83381e7698fb5d1898eb5b5457571619e89e7d6 +8ca29539600f8040793b3e25d28808127f7dc20c191827a26b830fff284739fb3fc111453ff7333d63bce334653a0875 +98a69644048b63e92670e3e460f9587cf545a05882eb5cba0bcbd2d080636a0a48147048a26743509ab3729484b3cc12 +84d40302889c03c3578c93aca9d09a1b072aadd51873a19ef4a371ca4427267615050c320165abece7f37c13a73d4857 +87954271e3de3f0b061c6469d038108aac36f148c3c97aefb24bf1d3563f342ea6c1c1c44c703e1587a801708a5e03f8 +86b6f5367e04c5caa3ec95fd5678c0df650371edac68f8719910adf1c3b9df902cc709a2bddc4b6dde334568ca8f98ac +a95fed2895a035811a5fee66ca796fdecce1157481dd422f8427033ed50c559692908d05f39cb6bea5b17f78a924633c +8ba05bdadde08a6592a506ea438dbdc3211b97ea853d1ad995681a1065ececce80f954552b1685ef8def4d2d6a72e279 +90b6b7494687923e9c5eb350e4b4b2e2fa362764d9a9d2ebb60ee2ad15b761e0850c9a293123cf2ef74d087693e41015 +8819ea00c5ea7b960eb96ab56a18c10a41fd77e150ab6c409258bc7f88a8d718d053e8f6cb5879825b86563e8740808d +91e42031d866a6c7b4fd336a2ae25da28f8bde7ace6ff15dc509708b693327884e270d889fff725e6403914546055c28 +85763642052f21cf1d8bd15fd2dc0c2b91bba076751e4c4f7a31fbdb28787b4c6a74d434d6ef58b10f3ad5cde53ef56d +8b61c36c7342a1967a1e7b4c01cddf4dce0e2025bc4a4a827c64994825f53e45277550ceb73c34bb277323fb784aa3c6 +80b9634a45c8b3770e993257bd14df6a17709243d5429969ab8b9a4645bf2a94f9b3cd3d759169887b4aa0eb50f4f78c +b5c44db9439dd8aa4edd151d95e48a25c1154e1525c337f97109f40131db81a4898344c8c3144c270bdc835c269b3477 +863080fcbc227eea32d0dc844f42dc642fbda7efc398ab698be3a3c6f3bf8803dea6ba2b51fed6151f9522b4ab2a8722 +8481e871129e9cb9d2d109c513cbba264053e75192e967f89659dcfcc1499de9ae7a1ac4f88f02289150231c70b4da01 +834d8183698d3d2d1352c22c373222cb78d0f4c8cb15e0ad82073dde273b613515ebcd184aa020f48f8e6fc18f3e223c +a227e300f0c5bc1b8d9138411413d56c274cc014ae8747ec9713f3314d5fae48bb6f8cc896f232fd066182af12c924e4 +ab7242835e91ba273de1c21eb4fca8312bdda5b63b080888b96a67a819b50294a7f17a7dc0cd87fae5e7f34bc24c209a +86eb27c898a5d6c3618c3b8927acee195d45fe3f27b0991903520a26fb8021b279e2a8015fbbba5352223ae906c7c5d6 +a61b1c200b0af25da8ad8e29f78d000a98683d1508ae92ee7f4326a7c88e0edb645b6cb5dde393ac74d322895e77ba24 +887739318c710aae457b9fe709debff63bfbb3ffbbb48a582c758b45d6bf47a7d563f954b1f085c3bc633ffd68c93902 +aacfcb0e2b0a868b1c41680487dc6600577ce00aa2edeee8c6141f4dc407217ddb4d37b79e7c9182258c750d12a91508 +ad8cd2cf5ccd350cd675a17f31b86a0e47499c6c4c11df640a5391bb10989c9c70df0a3ddeba9c89c51e15fedaf67644 +8aba897d32c7ef615c4dfa9498436529c91c488a83efc07ba9600875c90c08b00f66a51469eb901451b6e18e7f38ffd7 +aab8a600609b80e36b4a6772308bac77929a0c5d8d92bbc38e9999186a1c2bfdbef4f7a2b1efba9c17a68dc15a9373ab +b95811d1454307a30c2ac8588c8104804b06c1aec783fed75a6f12c9df626be57865850100f1ad28073e3867aca941cf +8b119d3bd4ee644469457df5d8a0020fd99b8b20bd65ab121cf95a7f55e50dd8945fcf1dff9d269d9d0b74b4edbc7726 +a980b912df832ea09353fd755aa3eec9eb4cfd07ca04387f02a27feab26efa036fca54cc290bb0c04a8a42fdfd94ce2f +91288e84da1d4ee2a4dad2df712544da3a098fdb06a5470c981fb6d6f3dcc1c141b6f426d6196ff3df6f551287179820 +98b0473bcffcbd478fd1b49895c61dd2311dab3cdec84f8e3402f8add126c439ffcb09cae3b7f8523754090d8487b5a9 +abe76988cf3065801f62a1eb3cfe9f8185bd6ab6f126c1b4b4fde497ca9118d02a0db3fadccd4ca98826b30475fa67ef +94a316a0faa177273574e9e31989576a43e9feb4cc0f67aa14d5c1967c4e10fc99db3ef4fdca2e63800a0b75f4b84256 +975ad39adadc7e69e34981be2e5dc379b325dc24dddacc0bb22311ff4a551a0020a8bdecf8ab8ac5830ca651b7b630ce +8b3bc73b640dc80ac828541b723a968fb1b51a70fa05872b5db2c2f9b16242c5fe2e8d1d01a1dbeaac67262e0088b7b0 +aa8d892a6c23dbc028aae82c1534acb430a1e7891b2a9337cedb913ff286da5715209cffb4a11008eae2578f072836cb +8dee9747a3ae8ed43ce47d3b4db24905c651663e0f70e2d6d2ddb84841272848a1106c1aa6ba7800c5a9693c8ac2804e +81e2c651b8b448f7b2319173ecdc35005c2180a1263e685a7e3a8af05e27d57ec96d1b2af2cae4e16f6382b9f6ec917c +98a9a47635de61462943f4a9098747a9cf6a9072a6d71903d2173d17c073eff3fc59b2db4168515be31e6867210ecbcd +912b2398505c45b0bb4a749c3f690b1553b76f580b57007f82f7f6cce4fadd290d6df9048258978c8a95ef9c751a59a2 +8ac8f0893fe642111ef98ae4e7b6378313a12041bbca52141e94d23152f78c2e4747ae50521fc9c5874f5eb06976e5cf +946b4a8eb05b529aaed56ac05e7abeb307b186a7835623fa4e85ed9eb41a4910663c09ea1bd932a2c467d28776b67811 +a4be51abeddd40e1da6fdb395d1c741244988ff30e10705417b508574b32dce14d08b464486114709339549794df9254 +b33b6b7d66cb013e7afeabbd7ed1e0734eb0364afe4f0f4c3093938eec15f808985fb7f3976969bf059fa95f4d8e335b +a808adbcf0049f394914482483ee0f711d9a865615ff39b5313ed997f7a0d202ad9ed6e6de5be8a5c1aaafe61df84bca +8856268be15a78465ad00b495162dc14f28d4ef4dcf2b5cba4f383472363716f66dabc961a6dbdda396e900551411e41 +b16ba931e570e1bf124ea3bd3bdf79aed8aa556697ea333e6a7d3f11d41538f98dcde893d0d9ba7050442f1515fb83b1 +91ecde1864c1a9c950fd28fa4c160958246b6f0aa9dda2a442f7222641433f1592d38763c77d3f036a3dbb535b8c6d8f +92cda991f69fbf8e55c6bf281b07fff5dbbb79d1222b8c55686480669247b60212aac27aa7cccd12fcee94e7a759b8af +b1d9b5b4e996b375d505d7250a54c12d32372c004a9cabf1497899054cb8b5584b1cef1105f87b6e97603ccbf2035260 +86e98bde8b484fb809b100f150199f13a70c80813ad8b673bf38e291595e2e362ad1fa6470d07d6fbe2cf7aeac08effc +aa12f7c39ba0597a8b15405057822e083aca3cee6ed30c4e0861eeb22620823588d96c97bb1c3776b711041c4dc3d85d +b477b34f29334f3bae69c7781d574342b7c27326088f9a622559ab93075c7357953ae84eb40e3421f453e04e9b4d5877 +9625067cb2120ce8220a469900aa1d1bb10db8fe1609988786b07eb2b88e0ddb35a3eccd4b6741e1fa2365c0db6b1134 +997b92af7765f587d70ea9718e78a05498cd523fc675ad7b0e54a4aae75fbeac55d0c8d72471471439dacd5bfcfae78d +88b59eaea802e6a2cf0c0075bf3fd6891515adcb9adf480b793f87f1e38d2188c5ed61ac83d16268182771237047ec8a +a57d078b230b1532c706a81eaabfef190fb3eb2932f4764631e916a0f0d837d6014da84ede100abaf610519b01054976 +94ed5c5b96f6afa9f2d5e57e1c847ae711839126ab6efb4b0cf10c4564ff63c819d206fdc706178eb6a0301df2434c01 +980296511019c86cc32212bad6e4a77bc5668b82a2321a1ecabc759a8bbc516183a4787c7f75f9ee7f1338691dc426cc +b10ef97db257343474601fd95f9016c205e28bd22bf7b8f9e30c3b14aca1cc9a11e6404ff412ef269c55fb101fee5a37 +b670d5d9c77fc6aa14212dd3eae100620f3510031b11a9625aa40bf31835c9fd717753b555bd159b1aa64a2104929340 +862054fabf6d6d529a7584d1a48f72d2eb216caf959c782ec36c69c26aef4595415d19a28b041946811b34a629105241 +ae4bf2ccd7b0f3774653848b5b4d39e5517dcbcff30d8441d78bc387ff42b573f16b7b0a7366e6ca5cef1dd9f0816df9 +8f810527badcb49f1542a0ccd12e3541efa084243f7106eae003458c176f4c1f01daae9d4a073c2cb2aced747e8a4576 +8a32c2067aaf6baf32db67acd4974a22a6da33db5444028a7c8c4135f9c84e102dc3b2c635b15afa6dc907d0270daffb +b15fc057f306a60b20c8487125b6b334ab749cf70eb8a30c962f625bb203ebd0d2a315949ee3b7a99e3d91acec384806 +a37f145d321359b21cba7be8b64dfae7c67a20b7b324f27c9db172d58e77a49fa02ed3d06d09d7644bf1fd81f4aab44b +b338d2e39a485ee4297adcf5e58e16c3cc331c5dffeade0be190907c1c5bdfed38537a6d81dc39a2cdfc1bc45e677886 +b69d84d8511b3aedfdc7c7e66f68b24e12e5a2365dbbe014bddd2e99e54143428cf8b74cf12c0e71316038aa5300e87e +ab210cc38661667450561a1857337879633f5d5bf2c434a3df74ff67f5c3ba69a7880872f19ae4dcbbb426462cd7d0fb +94538ef487a58a5ff93a5e9616494c5f066715d02be5b249d881a00bd0edfe2fe19dd7a5daa27f043d1dbb5ac69cf58d +afb47a899c1b25fe800241635fa05de9687a69722802ad45434f551971df91d8ca9edda0d835d82eb8f36ff9378ed7e8 +827a10d7536230887283a9b1dedccc6b95ef89cb883c4ee7b9821058b0f559704d1636670c0ada2b253bf60b7cb8a820 +97cc07965065d64409f19fb2c833b89ca3a249694b16b58818a6f49d3800926627ce0f87e5c0853ae868b4699cfdee5e +ae0c93d44780ef48ea537cf4cb8713fd49227f4b233bc074e339d754b5953e637a7289c6f965162701e4b64e4eaec26d +80953053397c4c0ba9b8e434707f183f9ced2a4c00d5c83b7dc204e247ad7febc1855daeb906c53abfdf3fe3caca30c4 +80f017e87b471b5216ebe25d807be6c027614572337f59f0b19d2d1f3125537478cb58e148f3f29b94985eac526cd92f +8a8e1c0d49801a8dd97e9e7c6955fc8b2c163a63bd6a4be90bb13e7809bb0dddc7a5025cc7d289a165d24048eac4e496 +8530e5b5c551a2e513d04e046672902c29e3bb3436b54869c6dea21bab872d84c4b90465de25dff58669c87c4c7d2292 +ae3589d389766b94428e9bde35e937ed11aac7ead3ce1b8efe4916c9bfff231d83b7e904fe203884825b41022988897a +ac02e629a900438350dd0df7134dfa33e3624169a5386ea7411177b40aa7a638e8d8aef8a528535efdbe1ca549911c0b +b1ac60b7270e789422c3871db0fa6c52946d709087b3b82e6eba0d54f478520b1dc366bb8b7f00ff4cf76e065c4146eb +a7465e1f8e57de1a087144d3c735fee2b8213fcbf2b9e987bb33c2d4f811de237bf007402e8d7f895563e88b864f7933 +8ab0007ba8984dee8695ec831d3c07524c5d253e04ec074f4d9f8bd36e076b7160eb150d33d15de5dd6e6fb94f709006 +9605bbe98dadd29504ce13078c1891eca955f08f366e681d8b5c691eadb74d6b1f2620220b823f90ef72eb4ab7098e16 +942a083d07c9cb7f415fedef01e86af4019b14ef72d8ab39fe6bd474f61ba444b9aac7776bea7e975724adb737e6337a +b9a49a8c4e210022d013b42363ac3609f90ea94b111af014f2c5754fbc2270f6846fa6a8deb81b1513bb8a5d442ea8dc +99cd62b177d5d7ce922e980cc891b4f0a5a8fa5b96dfc3204673fbef2e7fb2d7553bbacd7b2e6eca4efb5e9a86096e2e +94e30b65b3edd7472111566dde7fab0e39a17e1f462686050f7134c7d3897e977550faf00174748cbeaec6c9c928baa8 +a32fbcb29f3391d62092f2720e92b6ef4d687d8a3eae39395e0464669a64a38fe21a887f60bc9519d831b9efde27f0f4 +8f1492c4890d8f9deecb4adada35656e078754dcf40b81291e7ef9666d11ba3747a478f9420a17409d7d242cecd2808f +8942960b319ef65812d74cb1d08a492334db58d41e8437e83ddf32e387d9f3ad36834f59e6a71d1afb31263773c3ec49 +88d692f4976c99e763b027df9c2d95744d224724041dfbe35afc78b1f12626db60b9d0056b3673af3a1741eaf5f61b43 +9920cd37eab256108249a34d3f1cc487829cc5f16d1bce3a2328fe48b4de735ebde56c8b5cf4e532a4d68792387257c5 +87d34c9f5a913b806504a458c843eda9f00ff02ad982142543aa85551208cab36ebf8b3409f1c566a09a60001891a921 +a2ee8339c96f790b3cf86435860219322428b03ea7909784f750fe222bc99128d1da2670ad0b1f45e71a6856c7744e09 +84bd257f755de6e729cc3798777c8e688da0251a2c66d7ba2e0ce5470414db607f94572f5559f55648373ce70e0b560e +8d0e170714ddf5dde98b670846307ab7346d623f7e504874bfd19fbf2a96c85e91351ba198d09caa63489552b708fbc8 +9484cc95d64f5a913ed15d380c2301a74da3d489b8689f92c03c6109a99f7431feb8a07d9f39905dcef25a8e04bcec9b +b14685f67dd781f8ef3f20b4370e8a77fef558aa212982f1014f14b1bdd8b375c8a782d1b8c79efc31b41eec5aa10731 +b22fb1541aa7d2b792aa25d335d66e364193fdbf51b24a90677191cae443f0ce40a52faf5983d2cb5f91f0b62a5f20e1 +b06fa9489123ab7209d85e8c34d7122eb0c35c88ee6c4c5e8ae03a5f1ae7c497c859b0d62e0e91f5e549952330aa95a4 +b5cd71617ff848178650e6f54836d83947714d2e074d8954cfb361d9a01e578e8537d4a42eb345031e3566c294813f73 +848d39ea2975d5de89125a5cbe421496d32414032c1e2fbc96af33501d3062745b94e27dfe1798acaf9626eabff66c79 +ad35955efd5a7b6d06b15d8738c32067ffa7dd21cf24afc8ea4772e11b79b657af706ce58a7adcc3947e026768d9cdaf +aff6d7c4861ff06da7cb9252e3bd447309ad553b2f529200df304953f76b712ac8b24925cf4d80a80b1adaa2396f259a +b4b88d35e03b7404fc14880b029c188feecb4d712057f7ba9dedb77a25d4023e5a2eb29c408fde2c0329718bdaf1ff63 +88e96720e2f7c63236cca923e017ca665b867ba363bc72e653830caf585d802fad485199055b5dba94a4af2c3130a6f6 +982675dc0299aeedba4b122b9b5f523ca06d54dc35da0f21b24f7c56c07f4280265fb64cec2f130993521272c3470504 +95c77d418490e7e28293169cf7a491a7dcc138362f444c65b75d245c1b986d67c9e979a43c6bd8634dae3052df975124 +8fd6c4dff54fb2edc0bdd44ccd1f18238c145859ccd40fbfbc1cf485264445b9d55ffd4089c31a9c7a0543cc411a0398 +b153eb30af9807b5fe05d99735c97471d369c8a1af06b2e2f0b903b991eb787ab5a88c6e406e86225582acf8186ad5ef +826b55de54496751b0134583b35c0c2049b38de82821177e893feeeeb76ceeb747c7a18312cb79a6fc52f2c18f62f33e +91650d7205b232c495f1386bea0c36e136a22b645ffd4f5207f5870b9ce329c44524781c983adf2769f4c05b28a8f385 +b8d51a39162ebb38625e341caacc030913f7971f178b3eee62dc96f979495a94763ea52152198919c6dd4733bc234f64 +a1fbd3673f2ae18a61e402fe3129b7506d9142f2baca78f461579a99183c596b17d65821f00d797519e9d3c44884d8a6 +b7c5f5407263398cf0ed3f0cf3e6fcebdd05c4b8fd4656a152cedcdbf9204315f265fd8a34a2206131585fad978a0d6c +94fa71804e90f0e530a3f2853164bc90929af242e8703671aa33d2baad57928f5336e67c9efdcbd92c5e32a220b4df07 +b75dcea5ad5e3ed9d49062713c158ebc244c2e4455e7a930239998b16836b737dd632a00664fded275abe4f40a286952 +a02f7b37fc30874898618bfcc5b8ff8d85ef19f455f2120c36f4014549d68a60a0473ddfd294530dfd47f87fbd5e992d +8b48e1626917b8ba70c945fe0d92d65cab0609f0a1371fd6614d262d49fe037f96991c697904d02031ec47aab4b32f48 +b368f02c21d4af59c4d11027e583ca03ef727f2b2b7918ef623f529ceac76753a05a4ce724ce2e018da6ecc5c1c1261b +a95cba06eeae3b846fc19a36d840cbcf8036c6b0dc8c2a090afcf3434aaf5f51ef5d14b1e9189b1d8f6e4961bf39bbf8 +b32ca4dfbeb1d3114163152361754e97d3300e0647d255c34ec3025d867ed99e36d67ebafe8255b8c29be41864c08edc +8e4eddefa27d4fe581f331314d203a6a0417c481085134d8376898f9260f133e2bf48576528d62adf29953ad303e63a7 +92b7d5505833f00d5901ae16c87af028de6921c2d1752a4d08a594eb15446756ea905b0036ae6ffe6b8374e85eb49348 +b50e9018d3c4e05ba9b28b74b6634043f622d06aa8123da7cd0bc482b3131912149214d51bdfd887484422e143c3c1c0 +ab980a2f5317dfcb92baa4e2b3eb64a9ac2a755da6c11094d57e781ae5cf43e351824f1dd3abb4c6df75065b3784210b +aaabb009dfcb0bae65a0aee26ed74872c226965c52a6ed0998209e020a9ee806297dba4b15845cf61e1a514de5d125db +a1fe78f67000ebb6e90fe33e1a9dd5489be6e15fedb93b2a37a961932b77137fe85d46e89a132ecf7bcfb7aa95e16757 +85bc6e7d660180de2803d87b19ed719d3f195ea0a92baf9bfff6113c743f4237f51355b048549913e95be8ddf237864d +87a167968c4973105710e6d24ad550302ee47fe1f5079d0f9f9d49f829b9f5c1cd65d832d10fe63533e9ad1fa0ad20f5 +b2ad1a7b95b8a89d58e0b05c8b04ae6b21b571d035ae56dc935f673d2813418e21a271cccaf9d03f0d6fa311f512d28c +8268e555319992d5ac50cb457516bd80c69888d4afa5795fcc693d48a297034f51e79f877487b6f7219cfdd34f373e14 +b235411f1f6d89de3898642f9f110811e82b04ad7e960d1dd66ec7a9bf21de60e00cfabcd3004f3b5c4f89f5d9c7422a +b6963effcfe883f7ed782a3df3c40edd70f54ceca551859bcccb5d3e28fd2c1fcbdd7acc7af24a104687fd02b53c704d +862645c944e1e2909b941578cc5071afd7353fed1c2c99517e2de7573037704ef5d35accf6ec79b8269da27564209d50 +90f585eeb1a053e2f18c1280c9d6a561c0bc510b5f43cd68370ed6daac4b3749852b66c371397b6a7c1ece05ee5906c9 +876d9a3686feb79ce781e87ac3e3fbeef747b6ab031285e808c8a73f73f55b44507850dcaa745c0791d2cae8ad61d74e +a7ecc3b8c10de41a7bd9527228a0d3b695a651a5b5cb552a3664a887077d39ee60e649aecd68ed630da6288d9c3074ad +83529f1f2b4dc731ea05c1ee602fa2e4c3eebe2f963f3625959ba47657be30716d64e05e8b7e645a98bf71c237d9c189 +834ca6b14428c30a4bc8d5a795596820af6f3606f85bee9f3008f3fb94b3adffa968d21a29e2588d7a473d8b5d3a8b42 +b8d08cd8b73430984fd16e8db0525ae2b76253c92cccd7b3470add4d12d082eafb55a72bde04870924d0bdaf61f76c5d +96ef32df669690c2391f82136fc720231e4a185c90ba79eef7beaadedf7fbeb56ed264825564bdc7da01829b47f4aa88 +93d637b2f04d71891a80a1ee93fd9c9046d671bc4c15c4e597cfcc36f4ae85a7efc111359628965fd10d36c39129b160 +89f28dd3f7bc43749d0e3750c136385d4ffaf2c40354d3be38341416d755de7886d8108d83721b36f99feb3bccd73c88 +ac6392e274659f4c293e5cb19859828f101959c4c0939920a8dfed0e2df24a0cbf89a7aa983e947318c58791c893928e +83b2d4ce42c2fa0f672cd911365d1f1a3e19f1c38f32bedc82820ad665d83ae5fac4068e4eca6907bd116898966fed92 +b5e0144d6e59a9d178d4ee9f8c5dba18d22747fcdf8dc4d96d4596a6e048e384cd1e211065f34109c9ed6b96010d37e5 +b1a65e6b38c9e84b3937404d5b86c803c2dac2b369a97cbf532cfdd9478ee7972cf42677296ad23a094da748d910bc48 +849d7f012df85c4c881b4d5c5859ab3fb12407b3258799cfc2cb0a48ae07305923d7c984ff168b3e7166698368a0653d +84d9b7ee22bf4e779c5b1dd5f2d378ef74878899e9dbb475dfdcd30c2d13460f97f71c2e142c4442160b467a84f1c57d +964e497ef289fac7e67673a6cb0e6f0462cd27fc417479ecb5eb882e83be594977fb0c15a360418886aece1aaf9f4828 +ae1226222098a38ce71f88ab72de6ededb2497e30580e7ae63d4829dcc9c093bdd486102b7a7441cb06253cf0df93772 +a72865b66d79009b759022e53b9eedbd647ff4b1aab5d98b188100d01fc6b5d8c02b80eb6f53dc686f1fdda47d4722b8 +93aa8d7d8400bdfa736521133c8485c973d6d989ec0a81db503074fe46957a3999880fd9e4e7f44de92adf6ac0abe99b +a75e5ab84399962ada1f9ebcfc29f64405a1b17cd0a983950d0595b17f66386393d95a5aa4c6c878408984141625141c +91b1e5e75f4b55ec2e8f922897537082a1414eedc2bc92608376a626d8752d5d94f22f0e78ea1970eb0e7969874ad203 +83bf9c308424ef4711bfa2324d722f550d95f37d7f7b4de0487ccf952b89d7219ca94e7fa25bee60309efefd9a0e4716 +a42060476c425ff7979456d3c5484bc205fb1ef2d7149554a4d483d48e2a19119f708c263e902943bcf20a47e6c7d605 +8170c45ea126e6367aa5f4a44b27f7489a5dd50202cb7c69f27a2bdf86d22cf6b00613b0080d75fca22439eeaaaa9707 +8e5a82da70617697e42c6b829e1889b550c9d481408fe4cf8dc9d01daccabdec01f9e1b8c27dc84902a615d539bf9bc6 +80606c51401d0bf5f2700ebce694c807ab1f7d668920bdcccef2775e0939472419a8f404567bd4f9355095517eb4d628 +a40314565d60d0ddf8995673e8c643b1baa77a143b3d29433263730a6871032260abc1320e95af8287b90aa316133da0 +a87e07e84435f9e8a51ce155cd3096aa4b20d18e493c9dcbc0ac997ac180f3a255bf68ccd8195f2564d35ec60551a628 +84d2ab98416643c457bf7ddd9f1aa82967ecea189db08f3558f56803fe7001693ed67ec6ca8574c81ec1293b84a7c542 +937c3b955889ceae77f28054ce53d75f33cfe3a04f28e049cea8b8ade2a0440d5e2e8c4f377e6c1ae2115d68cc95fc16 +885a911f16845fe587b15ce7cd18cc2a84295bf609732340f74e0f5275b698cffed3e9aa1440e19e6940a7fa8f24c89c +ad90059a50c399996aaa0a10a8f637b7bab0dd5d9100301f0159a2c816596da55c30b2568d1717705fd2826b117a42d6 +828de9ff1e095c189da1f1ee18009afe14613ac696025add6f4e330488e02d5f1a90be69edd9a17bfb3355a0ca77b525 +b7aedb8394064a58dd802be6457555c0cf7b94805ed00cc66f38449773f4b1865feaee3a6f166eb51b2123b89d853a4d +b09c564ff37ccea34e90f2d50a40919a94c2e10d4fa58ffeaed656f88f9f4ae712d51c751b1b8f443dc6c9506d442301 +b24882d66b2ebb0271ebb939c72308d81f653940e70d6f1bcaae352f829134aff7f37522cc42de9e7fe6243db2c4806f +8e6f8dd906e0d4eb8d883f527e926ad1d8156b500c4cfa27214450c8112267c319900de2443c87bed1e4bb4466297dd5 +ae42f4578e8d79b6aa2dca422ada767e63553a5ee913ff09cb18918116905b68f365720a1a8c54c62cce4475ba5cdd47 +ade639bcd5017ea83ec84689874175ed9835c91f4ec858039948010a50c2b62abc46b9aee66a26bf9387ab78f968b73e +8d310a57aeb123cc895ee2fd37edc3e36ce12743f1a794ad0e1a46d0f5e4c9a68b3f128719ed003e010f717ec8949f43 +8606c086fcf3e2f92c1b483f7e2a4d034f08aef1a9d5db9e8a598718e544b82544268a0a54dfed65b4d0e6027a901d47 +8ccd95dd673d8cfdfa5554c61bcdbe6bb5b026403a320856fe51571e7c59504fe1c035f2ad87d67827339d84c0e1a0c6 +955a7cb4afcf70f2eb78756fc3a82e85ab4330eb89a87117294809beb197d1d474001e25306e8ad71daab6928abf6d64 +ae6b44ec6294736ea853ddeb18fc00cce0ac63b38170ff0416a7825cd9a0450e2f2b340d27a7f2e9c5ac479b4cb8a5fe +a88ec3f12b7020dd593c54376597b056e70c772c0ec62c24c5bfd258b02f772161b66e5dcd95c0c0fceb23433df9ff23 +b4a83933b4de552dba45eedf3711f32714e58ae41d4dab8a6114daeb06e90a5a5732c70384150d04124ac6936ca9804b +b8b7c4fa549b0fa1dc9c1f0af0750d6573f1648767751882d41f0dd7e430e3934590757e1c8b436ac35381bdde808117 +ab598b911234a98cfde07234cfc0d2fddfc5cb9ea760212aa3e175a787ce012965c8fcfdf52d30347f5f1b79cf4a0f54 +a9d354f9dfbd1976e5921dd80cbb56b2e15df53ce099ecb4368eff416998130d7830209282aaf1d4354129845f47eb80 +8c889afff546c721969e4d8aae6e6716ad7c2e9c1914dd650e30419ee77d630efb54dfffb4ec4ff487687b1864bf5667 +94ed2fa79116c7c8c554dc306b1617834dd3eab58baf8f0d085132c4688ca4a6bd38420281283678b38970a3f02b9a94 +944fdc8f0516d22f1672193d183833d3e3b043e26807fb2123729a0216c299785b1c4e24b5aa56e9bbe74fa54d43e22a +a48521454a3e0c10a13d8e810fad9d0522c68eea841821a8e0e57811362f7064a8f9c50f79c780a02df7df8c277feaef +8f3d26670ab55e1bd63144e785203373b2b13b76cac305f0363e48a6339fac3364caa3fceb245527161fc2fac9890912 +b4d6fe71001cb4141f6d8174dd7586d617cfccb54471e1fbce30debc2b1dead62cab29565abb140b682811c6231acb03 +91dc8afc4934fcc53ef851462a055cc1c3c87d7d767e128806891738427606d2fbfa832664d2a7f95f8ffe2cf0c44dc6 +b297eb432c74071764272c1b1663547ba753e66bf026643bfc0e42a9c5cdfb05a88083ad67d6ddfe6ab290678c607b29 +b343d1df85be154faeb5b21741a5ac454ca93f70a0b83a98f5901d1be173a1b2969d43e646363c5d4975924e1912599e +b2d74a66e4dfc41128aee6a3f0ff1e5137a953ed7a2a0ab5a08d7ea75642f12bd150b965c8f786ad0caf55ef7c26be4f +a54141faa8dd9a567c3cd507e4fc9057535ffe352fa1e8a311538fe17e4a72df073fbf9371523e5390303db02321650e +8e229a58f1acc641202d2a7c7e120210b9924e048603b9f785a9787ad4688294140ef3f4508c8c332d2dedafff2485be +9523554c11d39b56e6a38b3b0fadb7a9a32a73c55e455efdcfda923aff1e9f457d1b7cbc859b5ecbb03094eae8b87d38 +a199ffdff1812aaea10cd21a02b3e7bf3d8e80e501aa20bb2105b5f4cb3d37265abcda4fd4c298d6c555e43fa34517f8 +97f1285229b07f6f9acd84559afef5daad4320de633c9898b8068c6cb3b19b4468b4445607559ddf719f97d2410e2872 +a1dfff82908c90fc38ec7108c484735f104e6ce7f06097e1e80f6545702b6a0bc2a2706203cd85162edb7e9294fdedba +b12a706311c617d6c19e964e296072afce520c2711086b827cff43a18e26577e103434c0086d9d880c709df53947b48c +88503a6f48cef2f5cd3efa96a5aacc85dc3712a3b9abbb720a2cff582a6ea3c2afc49288b6832c8599f894950843ac11 +83ed63e38dfbe062fe8c7e6bc2eeb5a116f1cc505c6b038990038de6051281f9062e761ea882906ccff69c9c5b8a4a25 +911090d5d0231dde1189408dca939daddcb69a812ac408d1326060f0220781bcc131c9229e6015540f529d9fb33d9b0a +8a8352f1d9e5c7e80276e4448f997d420d5a7e0e2d5be58ae4106f47f867d1caa478b2e714d9c3263e93e5cc4c7be08b +9362f1ea9995f9b3850ebb7c8d5bf95927ab5ea25ee00e85d7456b3bf54459798b1fffde049d445c0d0587b0ab0a1694 +8859502b391273f4a00b6c0e87e5cdae676b7baf6c402f12b3360db6a5dfb4931ece4da0e1e4d98c7a71c3d01a183a9b +a9a5edf474120f9bbec9485d8b1e6f83be68b10de3d765219b0bf3e5d2840e478f1fb2bf806d78a8b8ad22ec50cf7555 +82c75daf983b06e49f0d75a042dfaae8cc92af050293d9059d6e8b01ca3ab2597e7adfc1159ed805513488944e739fa5 +a5cf240f04a9bfa65b811702c923d209e01f9535e217fa55ae3e0d1eb3257d6749e5587e727091e860609d1df29a1305 +95608ab8ade1c9fb814bad78d9cc99a36ad3e9562d5319830e4611ceea508ef76be04639294be9062f938667e33bce6e +8e44181f35c38b02133473de15560ae6588ac744cfdaf5cdfc34f30ca8e5ff6c85eb67dddc1c7d764f96ed7717c89f06 +8007b6ddece0646b7e9b694931a6a59e65a5660c723ebdffb036cf3eb4564177725b1e858ed8bc8561220e9352f23166 +a2d9d10fa3879de69c2a5325f31d36e26a7fb789dc3058ee12e6ccdda3394b8b33f6287ba1699fce7989d81f51390465 +81993d0806f877ca59d7ffa97bd9b90c4ebf16455ea44b9fe894323c8de036c5cc64eacf3f53b51461f18fa701a5860d +a20030f457874d903b2940ec32fa482410efecb8a20e93f7406fc55ab444e6c93fa46561786e40e9bf1e3c7d5d130bc8 +80c72d4985346ac71a231e7bbbb3e4a91bf50142af0927e8eb86069303eb4ce7fca1aa5b919d5efc82f2f09b41949acb +91b857d2f47f1408494940281127ba4b9ac93525788e700889aa43402eedea002e70eded017f5f5263741ed3ee53a36c +97445d007f08e285ea7f4d25e34890e955dac97448f87d8baa408e826763c06cbd58dd26416ba038d6c28f55bcea2d3a +a409c89526c2886f6a6439e2cd477351fc7f886d1a48acc221d628e11895a4eedd426112a368a0dbd02440cd577880a8 +a2c6adc7866535f6ffc29e00be4a20fa301357e1b86dff6df5f8b395ad9fb1cdc981ff3f101a1d66672b9b22bd94ec0f +8887fc53ffc45e4335778325463b3242190f65ae5d086c294a1dd587f62dd0d6dc57ca0c784bf1acaa5bbba996af201c +9731d3261a7a0e8c7d2b11886cd7c0b6bb1f5c57816944cc146caa518565034cea250eeee44ddffaeb6e818c6b519f4d +afe91c706efb9ee9e9c871e46abde63573baa8b2ea2b61e426cd70d25de3cc8b46d94c142749094287a71f4dfadd3507 +ae7bdf6ecc4fc0d8d8a7fa7159aae063d035f96ca5a06b6438b6562a4eee2b48d9024dbe0a54cfd075eac39b7a517f2b +a382e5205bfa21a6259f42e9ebc11406b5da2aad47f7a722212fdd6fef39117dd158a9991ff95e82efa0826625168a1c +862760c80bf44c2d41c2a9a15c887889eaeea32acc894f92167fb6f72593377c228499f445ccb59794415597f038ac9e +b4e96595a91a611c4563d09f29a136a4c04f07be74dd71a6bbabc836617ecb95494e48971a8229f980b2189fd108d2e5 +b5e7200357317c36244c2e902de660d3c86774f7da348aca126e2fc2e2ba765fa0facd29eebcb3db3d306260e91a6739 +a64c7133156afee0613701189c37c1362e2b4414f7e99408e66370680c554de67832c30c211c2c678dab5cfcdcecb3f7 +88f4cb67b1db497a91a0823ee3541378133eb98777842d73e43ab99efe8aa52fa02dfb611c1691be23684618394988d6 +89a9382a147d7387d0ff9516ee0c75cd1f8ee23333f4a2c9693d1a8cbe03680bc5b10c43c238c2190db746cac409bf39 +ad510bcc067373d40b05a830bf96fac5487de1ad5b708a13f62484c09b00fba6c5b00b981004e5ab3f28e55c9a5bce26 +8384156d7117675547279ad40dc6bf81e8f9a57b2d8cfebeea6b9cd1d8534dc0cf704068bc3ba0815010cd8731d93932 +a818fb76e53165b2f86c7f2317d64cf5e45f48405a34560983cd88bfbd48369e258ce2952233a8ce09c464e07afcade6 +ab19a4ed90527e30796064634b66cdc023bc5966e2c282468f5abef7879fc52986d5bb873a796b077d10e7b374b60309 +a17dafe2484d633fe295f8533662631b0bb93cdb4e7cd6115271f20336f602f7f8b073983cd23115093c7f9891c4eef5 +804acbc149d0334c0b505a8b04f99c455a01592a12f64d1ec3b82b2f053ccc4107e47f418f813d6f400940c7c8700a4a +965e097a825d8511d095b247554ec736bcb3701ead3ba785bd425cbabd56f4b989764e0965a437fa63e7e16efd991fc0 +b6701675ca27d7a4084f06f89bd61a250b4a292ee0521b2a857c88c32b75f2a70b97f98abce563a25d57555b631844e0 +abbdf65fcbdf7d6551ccd8d6e5edc556f1ecd275ccd87ee2bda8ea577c74615f725aa66e0911e76661a77f5278e0c2b9 +ab715ae372c900239a0758a3524e42063afc605b8fb72f884dc82ab9b0ff16715f3fb2fd06f20f15f9e454f73a34e668 +b45f41ea1d25a90af80a8a67c45dea881775fed000538a15edc72e64c7aa435a5e4375dcdedc5c652397c02b0bc61b16 +86f7be9252f8ed9078e642c31a70a09639899f7ffcd7faaf1a039fec8f37e1fa318fba0ed1097f54fc55d79900265478 +a30e5ed4277dd94007d58d5a3dc2f8d3e729d14d33a83d23c44ddfc31c6eac3c6fe5eb13b5b4be81b6230cfd13517163 +87e723d916f5fcda13fab337af80354e8efe6b1c09ae5a8ceeb52df45bfca618eb4bec95fefef3404671fb21e80bf9db +a521b8a04dc3abd3e9e0454b9a395b3638e5394dc2d60e97fda61b0a1880d1d73a64a4633f3d7acbd379bde113240d03 +851686c79c5403d5f05fbaac4959fcbfdfb51151bec55e10481b3c16e3be019e449907ae782ca154f76a805543d5755d +8ec1929e746b6c62b0c3fdd8f4e255e5c707e6e0d8d57ff9e409ae2dd6e76fdb50af923749992cf92d1b5f2f770bafbc +9175f7b6820d47205c9e44f8c684833e1e81da46c1fdf918a4dcafbc3231173f68370d442a20e45f8902bcab76a4e259 +b4f66c698115333b5ac00c9fe09aa9e1e9c943fbb4cce09c7d8a6ed4f030e5d97b48e944fd6d3e69ac70f1ae49d35332 +b958878b875eead61a4416a4597b1c567ddbb1eaaa971033f4a656f01a277822c1f4ea3972045156c2a5a28d159f5ddf +8188de8ad5258024d0280137a40909d24748137ac7c045dddd2bc794eac8edd5850b9d38f568fa8174b2c0593bb57e96 +91152c7bafce7a0358152221081bc065796fa4736bfc7d78076a0a6845287cde2ee2a2c9b96f500297c0a00410634888 +a5328ab939a2d3bd4c21e5f3894c02986b6590ad551c7734be3f4e70380eb7bc19629e9031b886ce3b4074ee4edee63a +97c4d49db40e266bcedaacb55edca4e1ebf50294679b271f3a2332c841705089b5ba96ef2064040fa56c36bb1375a8d9 +85cf0514f340f9d865b32415710d7451b9d50342dbf2c99a91a502a9691c24cd3403cb20d84809101cd534408ddf74e8 +950c3d167f59f03f803dcba3f34fe841d40adc31e5be7eefff2103d84e77a7cbe4f14bd9c3dfa51cde71feb3468a9c00 +96a69624e29c0fde3b92caf75a63ac0f3921e483f52e398652f27a1ec4e3cc3202f17af1f66224731bc736a25638d3e4 +aeac4170cf4b967227f66212f25edc76157eb4fb44c84190b520ecc2946470c37da505790e225fd1b0682bef7fc12657 +a94146a04e3662c50c2580ae1dba969cbb3fb0f43a038729c9e8be6ed45860b2c7de74f248dfa50ccdbe2ecaf3f2b201 +917b8e2880e85b8db723631c539992ec42536146e7091d4a3f87d37f051b5da934d84393523814f19962c78e6cb12ef8 +931f140ff8f7de79e399f5cd8503558d566b5c2ab41671724dd38aed08dd378210f01ac8fa9911f3047993dbc10cf8c4 +859eb9b560bc36273694f8ae1a70d25e7f206013597c4855a11328162ba1254bb736f1ae41240c8ec8dea8db035e08f2 +b4ad2cb2c3a3e6ab1e174f2dbfb1787a8544f3c9109215aa6d33265ef269455e3cde9858738b4fe04711a9cf9050e7d4 +8a3b342b87b19c0cdb866afff60317e722013c02dee458ba71e7123edc8b5a9f308c533b9074c7dd0d684948467502d1 +89185ac5cc5ea8f10a1f2a3eb968bb5867376d3cff98ef7560b9a0060206c4046ff7001be10b9e4d7ad0836178eba7e4 +845f48301f25868f6d0f55b678eab1f8458e3321137dba02b4cfbb782cbc09f736a7585bf62f485e06a4e205b54a10b7 +931a6c523d4a66b51efadb7eefadba15bf639d52d1df5026d81fd1734e7f8d5b51b3f815f4370b618747e3e8eb19699c +8eb3a64fa83dcd8dd2258942aea3f11e9cf8207f2fdd7617507c6dae5ea603f9c89f19d1a75d56eaa74305a1284ce047 +912a5050ed6058221d780235fb0233207c546236316176a104a9761bc332323cf03786dbac196d80a9084790506e0a88 +945fe10ec8dc5e51aa6f8ba7dace6f489449810f664484e572bfe30c2fe6b64229f3c8801e2eb1a9cb92ff3c4428cdf7 +b62383bf99c7822efd659e3ef667efee67956c5150aea57e412cbd6cd470807dfaad65c857fada374c82fcfca2516ad1 +a727a31c45b2970d08a37e169ea578c21484dde15cb11f9c94eaaf3736652619ce9d3a44e7431d50b0e75b658ebbc1da +97bf54ea9b84b82e4616027bd903ef6152439f1c6a8e1bae6db1d10fdf016af2cac10ff539845833dfd1ddad1403aa8c +a08cf36437e010e59b2057aedb7192e04b16f1cc66382cdef3490b7ad1544ae51f03e87cba0fe43a275841c247a2a0cf +acafab9fa28c1a607df2246490b630ddda1ecf0885ad24c2ecb2c2c1b7b9c7de8066714bf5b9b25f61981d08576789ec +851f0375128d2782586223467d0a595f4c5baa79616622a32f7d6ce1f08af06f8a109bd6527f88d93367dba17be661e8 +a2f1187c2a7cbf776653ff834ed703dd32e68eaf36f0700709be929f4c0ce5fa1d9930d1e3ea2aa01c7a16239e66cb33 +b3721f4a5d24ca112f020cb3f849543bf0e7f84b470fb00126ae80aaaa6f2c208d8359cd82ad9fbafd3ef2ac70656fb2 +98773ac3ce9528c73cfd8e7b95976ce597f67e146357642ac4fb6cb35046f3f39cf6c4a7b5af5c7740dda358aa0d2d08 +92c883a5d820541692af75be1b25dd4a50a4b91f39f367a551a7d5ad6065a26b60d68221a01e4950559717b559c2626a +b82e46dd25fd1234dad26fbcd8bb5177d7b87d79d362ffb9c2f6a5c16eb2ff324d135996fcd6274d919634597869d772 +82a53ed356ced5e94d77ee2a7f6e63f2ad8240aff2d17c5012cf5d1f18512c88c24793339b565dfbb659bd7c48dcbcd2 +84d20c7859b35a1cae1ff2b486d50822f9e6858b6a1f089ce4c598970e63e7c0f7dfbcb3337845e897a9dedf9d449dd3 +974892e5cf5ee809e9353d00e9cd5253d04826a8989d30cf488528c5dcdcad7650e23b4d228c3eb81f6647d2035a9e02 +b2327854910dbf3d97fe668da5fc507e179c4bc941f39bdd62e8b6035f004449c467240f656417e501f32dee109f0365 +88888f73475613d45d0b441276b1dd55835b69adfb27e26c4186936dae047b85478cca56be8dc06107b89a28f3bbb707 +836ba22e40511feff81a5dace3df54e2c822b55e66874dd1a73929994ec29909ffc2a8e39bfc2d16e316b621eb4a5ec6 +a754cedcccf4165a8d998f326f3f37d2989f92ca36d9da066a153c4aab5a62bb0011896bcbf90f14c18e00488d4123bd +86c26fa9584314292c4b7d6fe315f65dadd0f811c699e6e45c95a7a4ea4886c57dc5417b67edd78e597d037c7689568e +b205589648aa49ef56637712490e6867aa3b85b2b31e91437a249fb51bdb31401bff57b865c9e27293b30014b4604246 +afab0843ede582e5a1898ee266235066b94ea378884eaf34919ceaacc0e2738e1074b6ed41e0a1dd9711563e24f0215d +996ed65fbcab7611eada5bd0fd592d3e44705098b8b1dfba6dcdbdcfa1382fe893fa55270a0df0be0e1938bd71ab997c +881bc448a5ef8c3756b67ecb1a378a5792525d0a5adb26cc22a36c5df69e14925f67c9cb747a2f7e5f86ba1435509d7c +b219303c02c9015c6a9a737b35fb38578ab6b85194950a0695f7d521206e1e12956cd010d4d6c3bc3fafd6415845d5d1 +91748829bbd005d2ec37fc36fee97adaccb015208b74d2f89faa2e4295679f7685298f6a94b42d93c75ca9d256487427 +a41d6fd33b9864ebc404d10a07b82ba9d733e904875f75526d9a1f1c1c08b27160dcdb9023c5d99b8ff8a3461d57281f +b68978d39c97d34f2b2fea61174e05e05e6e49cde587e818b584201cf59b7096cf1807b68f315119c6db8d6110b28a9f +b64e66cec798022d64ce52477475d27ea7340817fe7f570617f58c3a9c74071d7ea6b54743d4f520b62aecad9a3a6620 +87b2b9e1c1786b7824f239a857024780a1457e51c64599b858118885833fb87a17d408bc09dcc0607d15ec1e53683a74 +9814799bac07dab4f0c934cc3c051676ca13abd49cf8d4739864e5bb9f2a8474897695113f49239f28832a8658332846 +806931a1526a843a9c2045943d616a8102b02b1f219535a1f1fbda659a1244f1bfead52ca7f1851ff8a97169b91c9ec0 +b8678249595a9641c6404c35f89745b93d8e7b34d9d44da933a1b2f1606972624c5108f1c04eb42e454d0509f441ed9e +81426714851741045a4332eb32b6dfe6422a4a2e75b094fb7c3f37da85648c47ee8af1e54ba26f4e1b57ebe32d0e8392 +b7a1875ea3f119fe0429fd9068548f65cf2869f8519dbbce0b143e66127cb618c81d7578e8391d676b2f3963e9d87f43 +872220a803ea0c6294cdc55aceea42cfacfd7a482982bcb90c0361c351a900c46736a890609cd78f02fb5c8cc21fa04b +974f0380197b68205ff4bb2c9efe5626add52c0ad9441d7b83e6e59ddb2ed93ad4e9bbdbf33b3e0a206ed97e114ea0f2 +a840f2d9a74fca343aedb32ac970a30cbb38991f010d015dc76eb38c5bb0bfe97dd8951de925a692057262e28f2b4e9d +b0913c3ce61f12f9fdc4be3366ed514c3efc438f82fc58c4de60fe76098fbc033a580ec6e4531b9799611c89a8063a66 +a0180d533eee93b070dac618be1496f653a9a0e4e3455b58752bf1703ec68d0be33ec0b786f9431ef4208574b0ad316e +a4a6b871bc95d3aa57bed90e14a0a1dda6e7b92b7ae50e364593ce6773fbf736672b1f4c44e383af4c3cc33e017a545a +a3f44cf19fe52bacc4f911cab435a9accbe137bdbe05d34bdd8951531eb20b41d17e3540e8d81e6b3eea92c744562ee5 +ae6b6d0ff3b30ff0b7f9984ef741cba27ffb70d558de78b897199d586cf60622ec2d8a9d841712fe719cf0f97628842c +87abf72f98c81d6d3a57ab1e224fe4b502ab0d8090d8abc71791271550b721c220d4e2e7da3be94a20c0e63d98e39a50 +b2f73ebdfe7133af57353052f4599776e16862905e64d97e1020c4bb84132e476d1ab79a9fb71611410f3f9d56c95433 +ae1a928253af2b210d31e1b64c765fcbd20a96b8d53823a6b9b6e7fc62249abf4a66c6a6aedb0b687e7384af9a845e0d +99c54398627833ca1435718154de171a47c709e4d5c58589fdabe62e72f2a7a11ae561bc31d7cbe92df4aff23e08cd0e +8a1310bbf1a31fae18189479f470977d324dec6518a5d374ab2ffcc8f64412fb765df57d2ddf69b9a6efaeb2b4c723b8 +898312c6c0d3d3438229b19a8a233eca8f62f680c2897f4dd9bbcacde32c5996d56ac0e63e3e9360158761185491ce93 +81b3f965815b97bc6988d945496a51e4a4d8582679c22d138f3d3bd467ed1f59545da2d66e7b4c2e0373628ae2682686 +b9aca91c6e6f4199beb6976b28e0e35e36e8752618468d436b1cf00d8d23538d0747920e5b2c31f71e34dfe4d5c86a0d +b908f4aa18293295b8cacfda8f3ea731bc791074902c554764c603ab9a1de1bbc72654fd826bffc632d95ce9f79c27d9 +a7316ae1baf4b1196961d53be7fe36535499287aba9bc5f3bed4323039b4121b65bb0bd15a14c1b9cd8b65ede3566da2 +815e39208f205c5fac25ac9988c14a62ab01657c7737a24472d17b0e765644bc2cbb7ff1e8ea169b8b0b17b6996c4704 +89a451d2b740cdaa83ccaa9efb4d0ff5822140783979a4fee89eda68329a08c018a75d58bd9325bdc648b0d08340b944 +8cd08f768438c76bae6bee1809dd7be38ec42e49eb6a4d6862db7698f338bf6b4b409088e4f3d1c5bee430295b12a71f +a4bd8c312103a4bfeb25b0cfffec7a1c15e6e6513b35af685286333c1dce818ffeb52826f2f5bada6b67d109c4ab709e +93afbef5382d89fa539ca527f3e9b4a8e27ab69fd5d5023962cc6d8932b33cb4dfc5f14343e1a3749bfd5e100c9924e5 +8d8e69d046992ec9ff14f21840809166cae8e0e9e7c8f14fb29daf163b05abe6611daa4010960e1141c5ab24373fb58e +96f8e72e96ba673c9265e9cc312f6b9c3b931745fc62d2444d59404bb08e5fb02ddb60715181feb9971cbd954526a616 +8d444c2b8e4d0baadb79e3147a2ee20f1bfe30d72eb9a02f15d632185fb8f4e8c3116066f7de1ebfe38577aaccacb927 +971410c0b10e3698f4f64148b3d2148fc6a4a22217fcf4253583530a9d6fbec77e2cf6f7bb5e819120a29c44653de3fc +99e7e1857bd5ee57007b7b99494b1f1c6bf1b0abd70c054770427d59a3c48eda71b7de7a0d7fcf6084a454469a439b41 +8c8a4cd864894f7a870f35b242b01d17133cb5dfdf2e8007cd5f1753decc0d1fd41be04e1e724df89f1d727e760fdb15 +890a24328bdeaaadf901b120497d1efa17d798f6f4406661e46ecdc64951f9d123d724ab1b2b49e0e9a10d532dd6f06c +a7cbe1f42981c9518608569a133b0b449e9d67c742d62f0d3358112c97e65ee3f08ec0ff4894ce538b64e134d168e5c8 +87c976dea77b3b750c3a50847f25b851af95afbaad635f9bb9f7a6ba8f0c4faeb099dd777cf7eac41072a526474cb594 +9882aa5e9bcc4ea2dd3de4bb5a0878a672bea924b50c58ae077563b6df0268910a60e969d3da1694ae7394ad0d9acd3d +90d35ce677327c461fb5dcb032202e851af1d205e9d21a34ed2b95635f13f8fb8dfa470ea202ccfa4b08140d0cf1d636 +b3b4cbb521cce2b681e45e30a4d22078267e97ccdbdc611b2c9719705650dd87e0ca6e80cf2e174f8f8160be94232c36 +95892b00478e6b27ed09efe23a2092c08e691b4120336109d51e24efbf8aba31d59abf3cf55c0cdab1c210670b9743ba +8643018957fb8ef752673ad73102d0b928796c6496e22f47b6454c9ed5df784306f4908641ae23695db46ebfcfb0b62b +b166ce57669bf0543019ecf832d85164c551c3a3a66c05b17874bccd5d0ae87245925d6f8edc62ac13dbd5db265823a2 +89fb4800ce4b6c5900d58f1a216ad77a170ea186f3aa0e355840aeedcf374e92a15ae442800c9d60334544be020b17a4 +8c65e586215a97bf11ffc591bce5147b4e20750e82486cc868070c7736c3de697debc1f335674aef24b7afdd41922d93 +90f68ce0c97d2661d3df1040ce9c4fa106661a719e97c7b2d7c96f0a958930c57d6b78d823a2d41910261ae1f10e7b0e +adda85e1287371ccbe752aa2a3c1d5285595027ba4a47b67baf7b105a22fb8548fa2b5b3eb93ca6850ecc3995f76d3dd +b26535d218f48d6c846828f028c5b733594ce01186e22e412dd4f4a45b3d87d2ac1bfe5d54c987e4e8aaddeb86366d7d +a081bd86962ea3d4fd13df6481f3aeaabdd7ceae66f7bbb913e601131f95d016cf147d045253d28457a28b56f15643c8 +b3d852cef4c8b4c7a694edbf6f0e103f3ae7f046a45945c77a1a85ec8dad3423636a89058fafc6628aabff4dbb95c2ba +b424ffc94e06e6addc90a6324e0482814229b5902e2a266d0c2d716e40651b952bc9f00d7dad9b6050377a70a72c7f24 +b2cafd908cae0ca22eaa2d9a96175744897a20eb7b0a6d43b0098cb1c69e3cb55373888201e4ed32816655eb7d8a3dd7 +b61177ecf1ae9d7e7852d98cbf6080d9f1e33c90f2436720b4ea4690437e8c7850c3754768fc1312cb4e838d855c5ccc +81b486644e1ae22cf0ba3a37e1df34dc186c82a99ab35ad6f475c37babdea574ddfbe5811d4aa020581292a793d66bd2 +97ae848a823ea7a99f91834e537fb47208f616c08fe32c8f8fe06bd35c9b638698c513265d0b4de9e572a2f9692b98e2 +81b8fef4ea5d399c65e78f40e47c559ada86d890777c549ce362e7ab81b3bfb00d5ff4ae4ee30fd7bda7ee90d28f85d8 +aada6912cc748923ea40bf01922c06c84bc81b2ab0bb3664a0579b646f03d47ce88de733ac7f2cb9be4a8200584cdb71 +89b48b9c79332f8f58eac9100ada5bb7decdc4b1555c5d383e2c1ce447efb0ebdff9c50bb52bc3042107f33a61ab2520 +a32ecca8b870b2b6e9d10b5c1d8f925b3d629d271febad65abed316262bb283c60cade0e91047fbd0fac53ac6db372b9 +b829cd1f13409e3573a8e109c9541b0a9546e98b6c879a11152b5564477ada4d8cb4b3079040e05a5cb63d75ef11eaab +91f3b100baa19e960b170fe9e03b799faac5b9c6f305c56115940bf81f6e64dcb9cda77e8de70ed73a21c0e8a74acc58 +b25b5e872c84065aee04822bbcb4f3bdff57fbd7cea314c383765cc387786c17de3d5bb3de3ae3314bdede14542bfac6 +a89bea9eca1f5a17a3efccfa4987d8e5366b0dba70ef1fef43aaea83c528428d1498c8b056ac27f16e8946ee93f7028e +818a1f7b0b8b06ea0514d6b4a0296da4f69cb18ac8e48c5579e6ba2880b06215fcbe81672566b8b94fcc3c0cadecb191 +98dd6e6b4b4d63d9aa7464a2be08ae8babac4da7716a3f109340bc9187d59c6ca0c88e6877a67c65096f64a3ced22a4b +a2069c5bac4f6590042aefb37570cc20908b0df9d0130180f565ed8a53b4ea476a274de993561fb4d009f529fe7aa1cd +860b7ec2410f033a7b0c5ca08f88a0ad29f951a5ebd5383408a84367e92f1bd33bee3b87adef2466b7e33b47daabf30e +a408855a8414102c3cb49f47dda104edf0887e414723da59b6b6537ada7433529f6a4d1a4ad4fe311c279213cdd59356 +8ca0d81dcb43b89a4c6742747d29598ede83a185a8301d78c6e7f1c02c938441360a1ab62a5e571e3eb16fe17131cbc0 +af7875a495cb4201cdb26e23b7c76492f47f8dd4c81251de2397d73d4c8d5f419cdbad69ba88ef0dc3552e460dbcd22e +80e901e433dca34f3d386f39b975e97f7fc16c7f692808221fb2ee60c1aaa8db079cc48c7d72fd548aaf8dde8d0b8f05 +b6062319e13926416e57a0ffc65668bfa667e708a4e3f5cb26d8a6a32072f5b790d628052d5946c5068dd17cf4a81df8 +90094b569e8975f8799863798912dbf89b12d2c2d62b3e5fac7efc245436fcd33af23b8c509ae28c6591d3f020966e06 +a504f72d3d06a0c9b188a1035c7c6d80047451c378b6c5b2ffa1f8cecdb64871cb6440afb296974c0a528e5e563061a1 +959061c4924e133a419e76e000e7c62204093576ff733ce0b8ae656ec6045ef94c5a1f3c934fb76fa9188c5eb397a548 +a8b9d0b58de38cb86cb88fb039a7c4c0c79e9f07f03954af29013baa18fc2633883f8f9ca847209c61a8da378f9075d3 +b16d8341da4ff003ed6d1bbdb3be4e35654a77277341fe604b4c4e4a1cb95e61362094fb3d20ab8482ea14661c8b9852 +8ea4ca202e3aed58081a208a74b912d1a17f7b99a9aa836cfaa689a4a6aa9d9fbfe48425cad53b972000f23940db4c5c +96a372f55e9a25652db144ec077f17acc1be6aa8b4891e408f1909100cd62644a1c0296a3ddc38cd63ef46bef4e08462 +87df40018ab3a47c3782e053dbd020f199fda791f3109253334a71be4159f893a197a494de8f94d6f09efa5811a99977 +aff82d2ea6b3ad28d0ca1999a4b390641d727689dc2df6829a53e57d4f6418196f63a18495caf19d31fc23fdff26d5e2 +9091053c4a18a22d13ad309313b6d2133a96df10fe167f96ec367f9b8c789ecca7667f47d486fc5ba8531323b9f035ac +a4842090515a1faccc3d8cadbb234b7024254eba5fdfcef0d15265c7cec9dc8727c496ad4e46565d1f08504c77e511d2 +b1d8a37b1a97883d5804d0d2adaa8dbf0c2d334ef4b5095170b19613fb05e9c648484093d0c70d545cf9b043b449c707 +b1ea40f3dd1c3d437072f8adf02c32024f32488dd59389d1c3dfe78aca3df0bab7767f6ded5943cc10f50555da6092f5 +ad219c6a8149f10391452892b65a3268743baa7402736f810a35d56cdfed83d2172b03f15c205f0dc5446baf855907a5 +afe44c3e1373df9fc53a440807fa6af8ebc53f705e8ee44a162891684970b04fb55d60bc2595626b020532cb455ee868 +859ae154b017eae9be9da5c02d151de747cc23094d8f96d5db7d397e529b12fb55666f55e846e2bbe5e6f5b59c9d8b05 +8aa01354697de23e890fe54869cd3ec371f1be32064616ca3a556d3019541ba8e00d683f1396ca08e48988f7f7df5de4 +b8f682487460b9d825302c40a7d6dd0353ff43bf24cd8807cdfa46c043e3f5a7db182b27a8350b28e91888802a015af4 +b6d4d6c3ac40f8976b50be271cf64539eb66dc5d5b7cec06804dfe486d1e386037b01271cf81ef96dba5ea98a35a4b43 +9385a2fd1cd3549b0056af53f9e4a6c2dfcd229801ffda266610118ade9a568b33e75b6964e52fcc49c8e3b900e1e380 +98f4aa0e4ef039786cbd569536204e02b0b1338568d1d22bb5bc47b5e0633fb7ffe1da93eb9d825b40b9b7f291f84d51 +b7b3460cf706dc270a773c66d50b949dabad07075021d373c41fbb56228355324d120703e523ea3f345ef7249bfff99d +81b826255f95201987513d7987cdc0ca0529524d0e043b315a47583136dbada23a114d50d885bb3f855fa8313eff801a +afdc6c35161645a14b54f7b7a799910e2e07c8a5efe1827031a2eecd5d9263b3baa367fdd867360fabc41e85ab687e74 +817b361ce582153f2952f3042e235ee2d229e5a6b51c3d3da7bbe840b5c6ec2f01446125045848d15fd77dc46c8a8fe2 +aeb599265398af6e5613297d97d2b70222534590fcbd534d68b24a0289b6366ac8188b753f6fd1000ee73ef44f8fb7af +a5a9e528b606557be64460c1ad302a43e741357827b92ddc50766a7e6287740fc23bd528d9faf23345ce8bff527d5bc7 +a8d3b3b438d5f75efaae6ce7b67c2212899ece5b5bdc9bac655e271fd1846ea8560e646fdbded3d9363eefe29473d80d +984c7976d557e2f591e779c2885f5033da6f90d63a898d515b5da3adbffa526764cd8eb679b771573fdf7eed82c594ec +8ac748689cc3280e064807e68e27e234609e3cc87cb011f172204e1865ad7fdc78bec1672bd6e6fddcf4e7902b0f38bf +877bb392059540b1c8f45917254b8cc34fb7e423952bdc927e0a1622efec4113fa88988686b48134eb67ddebcb7c3ef4 +ac04b154ccd307ca20428091585e00121b61bae37b22d5d2a1565bc1134be3c81ccf3715fffebe90744164e5091b3d9a +90745c04278c3a47ceea491d9dc70a21a99d52648149b1ab623b5396b7d968fd3c4d1a2d08fc5638e8790463e0cf934e +80bf26ca7301e370f101cc69e7921e187cf5315b484fc80a872dec28bb65886569611a939958f4a3d2d3da4350011298 +87cbf4d6f0c06cc5f24e0f173a5f2f9bf2083a619dcce69a8347c1a6cd1d03325544610f2984eb87a13241e6ab9a22b7 +8909368817a515789ff4d19ed26afafa5729a24b303a368ea945a9287bc9facec9e1c8af19cbec8dab4acbb6a6ddf6c7 +ad8d2f82b08e0990dfd6b09fd54db3a30fd70aad218275550f173fd862347e1258a4716ca2bf4c40e4963850b2277eab +a9467ceacf9337cae4f2c7eeb3e03752ac7d77692b07d5e5d75c438fbe7dc2029ff84f7759372a0ddfa953b4ec7e9e38 +a5feb7669e84b977cb1a50ff3a39c28f7ad1ecc33a893fdf1ddae7a0d8a4c5f6fbaff25cc56631b708af038a961f3b55 +8f2e1fa07963ba18db890b44c3b9ae7f8992b702a5148679df69e4d9d4b1c082b2bd2ae53f96a4fe24b54f3dc1588f17 +896778f35cbecb43f001277c306e38a9c637275101f1a09546f87378b10ccc025644bc650b3b6c36e4fd0c09fbb3df35 +91dc702778176a4d089dc65502d703752dd9a766f125ffef26bdc38fe4abcae07cdea14102c3448d10f8dd6c852ee720 +a5df3004cec6b68b937cadded0dd2f48bd3203a903a3e1c22498c1193f4567659ecaaf3deb7ed7cf43796da9188f5dc6 +b18b4c8ffcb8599c24d9851abf8ee43047cbd4c9074c9cfbf88376a170da4554978988f550afde8a45306ca32713c204 +8370bc38c84da04d236e3c5a6c063e1db6613dcc4b47239d23efdcb0cf86846955b60da3e50f17b17cd3f7e0c29302d9 +ab7d6bb6be10aa52ef43abbe90945e78e488561afb959dc2fe768f8fd660d267c7203a2b7bdfa1b44cd07898f4849e06 +965c96047d82d76ec2cfe5035fd58d483cd2cb7f65c728ab3049562c5d1943096d6a5014c05babc697d79c07907cf284 +9614f7006aef6f0478ebd37fbf17276fe48db877394590e348c724059f07c3d1da80d357120d3063cd2b2bc56c58d9d6 +819c7b2a1a4bb4915b434b40a4e86dd7863ea85177b47a759bc8ecd8017f78d643982e8a091ee9a9e582f2b0208725a5 +8e159a185b5790a3ed444b6daab45f430f72f4ac4026750cbd5c7cd7947b5e00f2b10eaaf5aadf8d23054c5b29245546 +b48cb6f6c0aaea04833e10d735b67607846158b6663da380ef01c5bca3c9d537611716867dc2259883e5bc9daed57473 +8b48ce8b5ab76b7d662c29d0f874f5eec178baf3f14221bffd5d20e952f54f3ed053182a486da1d1f400e0acef58f673 +b6fd3cba177bfbcb5e7ebb1e3c1967cad5848c09c615ba2a6c277908f8b1f4f1ac5f184c33f2a401e8bdafcaed48bb88 +abd8f44c4a447de8fde1c119f4fd43c75b4cc99de9c817a019d219d4b2ad2a73b60606c27e36e9856a86bf03e7fc861f +af9f7e8b3e9e8599c7e355433c503a05171900a5754200520fd2afed072305be0e4aebb9764525d2c37a5a7eede72025 +a0960a58bd2681804edd7684793e3cbb0e20d1d4bd8721b192baf9aee97266be14c4ee8b3a3715845dca157ba2fb2c1d +949a37213209adfbfa4e67c7bad591c128352efd9b881c1202cf526bf4f657140ef213acf0efeb827a0c51a1f18809c4 +9192fae84a2a256f69a5e4a968d673bebf14ea9a2c3953f69fe0416f7b0fafa5166f3e4588d281f00d6deac1b6ec08bc +b1a249662f34a88d2798eae20c096268d19f1769d94879b8f1aa40a37b3764349b8e6ab970558436a88a5aa5c37e150d +aea87086dcd6de0b92886b3da0813ff271a7107ab1a3cb7021b85172c1e816a84dbb1a8fdb47e8a8eb5e6fcddd5b919a +a586b5078b3f113eec9f074430bcf9aabe4e82752e5b421c6e31d1c2a911512e34154bf8143b5197e820c5af42aa8ac7 +a6eda122e400a6600f025daa383685a10f72f62317a621698bd0106b331077b05ac1afc68ece7a2e285c54a366921a3c +8875e9ba654ad7b1d57ede84e2b702600416d40f7475fe2df25dd1b95c0178a227ee187547898e5b9d1ce8ce9ebd15c9 +af2cb289f8c75f4ddae9e3ef9c1977fe4d4d513e411777b03b996f5baa372eb995b5ca96255fad9ace776168806ecc42 +8d24c465d26bd93290f45ef035bb6dde4530d9d7d051baf583b1f8b98e9886de262c88b5709084710cffa7c767b4c27d +8cf35b1b28a7726645971805170392d522f5e7e6cb94157fe9c122a987051c1c90abe3c5bdb957ef97b1c45dd9bba05c +93e2bbd82a3cb872cea663f9248b21d4541d981f3f8d5af80a43920db5194857f69e2884753f6ed03b6d748dbfb33620 +8b774b97657db654ebdafce3654d645f849203452e876e49dad7af562491cb6531bd056f51cb5b2e8f0a99e69bd8566b +b5333c49d3e1c4c52f70f3a52f0ad77165bed6ad9dcbfaf1364e7a8a0f24570e85a218e4c2193f63d58a7dd975ceb7a5 +b4a34c443e4fdaab8e69fcda1fce5e72eaa50cf968f5d3d19084d049c5e005d63ab6e1d63dee038317da36f50ffb6b74 +824a224009c6848b92d6e1c96e77cb913fee098aaac810e2c39a0e64d5adb058e626d6a99be58593d921198edd48b19c +a86f1fdd2e1ba11ebda82411b75536fc0c7d2cdb99424e0896d7db6cae0743ee9349ffa5bff8a8995e011337fa735a9d +b406b5b89b8bed7221628b0b24eb23b91f548e9079a3abd18be2ed49baf38536a2c1ec61ab1ddc17928f14b006623e7b +8a7ea88d1f7420e2aaf06ee90efa4af798e2ec7cd297aacd44141471ed500107fdd93bd43b6de540314ef576646a7535 +a7a8c071e68bbae9aca110394cf56daad89404dff3e91ea3440670cd3d0423b67905e32b1ba7218fd4f24d2f8bd86ce7 +b959830f152e4d31c357be1ded5782aed5d6970e823cf8809434cf4fddd364963bc7cfda15c8f6b53eda16ab20ca3451 +b59232c8396c418238807ce07e0d248ad2045289e032678b811cc52730f99b480eb76f6adf985e6d5e38331d4bb2b9d5 +a14092fddecc1df18847ab659f6cf7c8603769a4e96fbe386d8303b225cebbbe8f61d6ab3dca08e3ed027e7e39f2641f +941cb0632acd395439f615c6b4b7da9ed5abf39700a8f6e6f3d3b87a58a1a7dbb2478a6c9ff1990637ada7f7d883f103 +951b8805ecb46c68101078847737e579206f2029e24b071bae6013e9dde8efa22bce28aa72c71708caf4e37f9789a803 +b2cbf22e53f6535fa950dd8de4aa6a85e72784dd1b800c7f31ec5030709d93595768748785ff2dd196fbedf3b53cd9d7 +8d84ea3a7eafb014b6bd6d57b02cab5ac3533aa7be4b86d2c5d53ce2d281304409071100d508ed276f09df81db9080ea +a2204b60836cba8bf29acd33709e6424226ae4d789ef6b280df8a62e30d940bc9f958ff44b5590d12fa99fcde2a4a7a9 +86692c58214f326c70eb2aaf2d8b26eae66fb624f143a3c144fd00f0249e30e0c832733a7822fac05c8fe74293768ace +b1cb3d64eb5b9ca0e01211128f990506fba602cd1417da02237205aa42879ae2a6457386da5f06434bcb757f745f701d +b3eb4290a53d5ff9b4596e4854516f05283f2c9f616ec928a0934b81c61afc351835f7eca66704a18a8b6695571adb30 +b0bfb1d44b039d067d7e0e2621e7c4444a648bce4231a6245179a58cd99758ec8c9e3f261d0adb22f9f1551fceb13e4a +a29320f71a9e23115672ea2b611764fe60df0374e0d3ff83237d78032e69c591a4bdec514e8b34f4b3aeb98181153081 +8a6abe9c8a048002b2ff34154a02c2f13fc6dbae928da47c77f3e5b553ea93d8f763821a6ead3c6069677870fdff7ff3 +b73ab66a62f427e1a5e315239a2e823e2a43550d245cff243c2799eb2e4701fabb7d5f9ce74a601b5ee65f6555dacf64 +b64858e98b9c10de8c9264b841b87e7396ba1da52f0f25029339ca1d13f7f9d97f4de008cfe12a1e27b0a6b0f2c9e1ab +807d2440d1f79a03f7163f5669021f3518094881f190cb02922eb4e9b17312da5e729316fe7ba9bfffc21ed247b033cb +a7f06458d47ebe932c2af053823433a8a06061c48f44314fad8c34846261c8c3f7f63d585a7930937327ad7d7ca31a6f +82ac2215eba9352b37eb8980f03374f5e0a2f439c0508daa7a32cdce398dde2a600e65a36795a4f5cc95bbcf49b01936 +a1882c83a2f946d54d74a008eac4aed70664db969e6799b142e0d0465e5662ba0d224a1cc33be339438d69bdad446ff6 +8009776f7a34a3c8779e21511fa409b0c5a38e172d1331acc29a16114e002f5f2f001381adb5fb3427a100752d775114 +b24441019af4a0df2dc68e3a736f358da0fd930c288398a18bb5a8d9a1e98ea376395f19d8e03a5f020b83fcb709f1af +ac72b4de3920c4f3c9b8ea90035cd7ed74d34b79e79aab392f057c3e992ebe79050cc1c6ccf87120e4162b29419147de +973e75577cd2a131a0bd568fd44e43554ac5a9ea3bf10f02d1ad3ac6ce9dc7a8a7ea93aacf3325f7d252d094a0de1376 +98a114de2a86f62c86862de37c328bf6a7fccff4d45a124addbe0eb64debe365409fcb72ce763f2a75030e1ff4060c64 +aff753e1dd4707f1a359eaec06ebef1903242889a2cb705d59dd78a79eb5b894731f5a91547479506145ca5768877dec +b856e4234858b5aa515de843e8bd4141c15a4cc02c51640e98a8aaa1e40344f1ff8ef7c3b913ea2ae7411713daa558d2 +863525eb2f8147a6d1d0d4304881795bfed348913cd7f38d815d929a426788b69e41f022dba5fdcaf56c85720e37fefe +a14ad76b145a6de2e0f8d4f615288c1512701a7b3010eb8a95941a2171bc23561e9c643764a08c4599040a3b4f5e936a +a18bfc66f6139dcb0485a193104fec2e7d52043837a4c0cadb95743e229712a05cf9ce4ccb482f36ff1ce021e04b574a +991c8e6678077d6e5f5733267c1819d8f7594e3b2c468b86a5c6346495a50701b1b05967e9590c15cef2f72bc10a38f9 +a034e7f9b547b047c99b99a0dd45509b0ac520d09130519174611de5bcdb9998259e1543470b74dcd112d0305c058bad +95ffe0d02317b5c6d5bfddbcec7f3fdfb257b26ad1783bb5634d983012e2ea1c6b9778009e1b6d10564198562f849ac0 +b3db442aa4adb33577583b2a4ad743f41efe0e1f87bfc66091d1d975333ffc00b4afc43057bcb88a7d68b0c9695d38dd +ad2e97d10d7c53d231619e3f2e8155a27ea4f2fb3c0cecf5c7f14f4cfcdd21f62ea46d843b21df748b2892131633fed2 +905d7aad6d3b56bad48694b6b20b27e370ebca8b91d0821e48e2f9cad39910c26cc11c77c266894db3d470485a63ed11 +99bfadefca796ce6af04ede65ba5ef5bf683ff7e2852bb9c406fda77b95ef382289853dfe4d933525071e4cab8ce3936 +94d9905ed4ef92107d0adb9ea38f085a2a24b8f792108bec702d747c215b1f14aafd486ea0c07ed42602b12d8f602b93 +a78dce23ca09dda2d5e7fe923290062546825286d624de35ac5756b6c8ae030e211f4f9c9c8d18a924f5880e3b383d1f +abce9e2128ff51fa17e73d93e63d7134859b2f328eedbcefb337c39e752d6750d9cffe6abfcd359c135dc5a12018827b +a9ea7d91e8a3524acb3182bedd7e1614d37b48f8eb2d8f677eb682d38408b8d512786d8bb65811f4d96788b9378e59b3 +912c9f804fb57dd1928f8274be58b42618f589fc72a7e5b6cb4d4b5d78c547f80737cdd77ebe5d2b71eaf60b8fd2b663 +b7227ec9a62d5538974547f717fdd554ab522d8782667fc3e9962e9c79a21134ef168371bf3b67e28d0964e92cf44028 +89440a781c812a19c758172bf722139598023ed0425374fbb0d91f33be7b7f62a36d7aa34696c4fb0da533bd5dd41532 +b31e4a9792d6e9c625c95aa3c0cd3519410dec07940afab820ef9f63017415d237a47f957d0b591b6de399ffc2a8a893 +a66ec47393df2693be161daaa88be0cf07b430c709ca97246d10a6080ae79db55c9e206b69a61f52512b868ba543e96b +90ca425dee74cc6a7e8eb1755cf9b7b76ba2a36ab851333b0fb7b35e8e6e189702456f2781ad87b4215993d62230ff4f +88b64741f93a2ae5d7b90b22a5e83c9d56bcee5c6bfcedb86f212acc776cc3ebd0b62cc025f596cd8db4f4b6a7aeebab +a1b6c7d2358bb201b42264f8fbebaa242ef105450bab21b4a2f16f368048c16ad1f3695841787eb33a0192f1f6b595eb +8a932f1cd227ceb18389791ed9ea1ff26571715ed1ab56601a994795713a8f7f031d1e8472ec3eb665b7bfbbca8ca623 +8bb2e34a2bf77f9f657dfc51ff296a6279a4d7d15860924f72b184fb7d5680320c7769954b9dac73c4bfe9c698e65e58 +af54e7367891c09f2cea44cc7d908d37d058162ec40059d32ded3983a4cabfe5057953878cf23bfad5292dbd0e03c0e1 +8a202532b9205385cf79f0299ddcb3156fd9fab09f9197bce762b5623f75c72ab1d74334ee6f0d289007befe222bf588 +83bd0f5896eaad58cfa7c88fc5ed505cd223f815dcfe93881b7b696cdd08b8b5ede03ea5b98e195c1a99c74ac5394c1b +b4a84d9940e58e3b4f804e4dd506f8c242579cfa19323c6e59047e5a1e35150699a2fab2f4862dba2f0ee4ed1d8970f8 +8c9ec477d057abebc2e2f6df5c4356a4f565bde09f499a131967d803d4bf36940ca2ed9d4a72adbe0a4a8b83fc686176 +8598f43c32623fd5b563d1ec8048ffc36db3d7f9b3a784299811687976f64b60585b2a2707050a3c36523b75d1e26716 +b55eb07014fe5ad3e5c9359259733945799e7429435d9bf5c72b2e0418776e329379433e17206f9f0a892d702a342917 +a5ed942eda7b36a3b0f516fafd43d9133986e4c623b14c0f6405db04e29c2d0f22f1c588150f670dbb501edda6e6dd4b +92b6abb28cefab2e332c41c98bfa53d065b7d262638389603a43f4431e6caf837b986254c71f7cdacf4d6cc4064b0195 +b01806178a28cc00d1561db03721eef6f6539676d93dd1fa76a13b42a31d38797e99b1848de92fd11821a342b04f3f72 +a2f10303437acfbb5912e186bbff1c15b27ed194c02cbc1c5b482b0b732c41fa809136e8e314e26b5bfe57690fe3b250 +9990207fcc711102e7e941b3ac105547a3e7301390e84f03086c99c6d3e14efff3a2e2b06e26227f496d88d5cdaa3af1 +b903cdb0c2fd578612398c30fe76d435cd1c2bab755478761244abb1e18ba8506fd9c95b326422affbcaf237309959d7 +99e0c12cae23f244f551d649302aac29bfdeb2c7b95578c591f512ad7ac562bd47e7c7317ac9bac52c9ea246617bdb48 +b996d267ab5149c1c06168ee41e403be83f99c385be118928d6e2c042a782de0659d4d837f0c58b26df0ce22049a5836 +989001b8414743765282f7e9517e4b8983a929341b8971d7dd8a87d246f6c8ba5e550c983566ddd932c22948f4fa5402 +a0b006a2c9124375364b8fc5ddb543a7468fa6d321ea046d0fd2bfdaef79e5e3600b3d56190733491ca499add1298c7f +80881d6f3ee507089b7dfb847fc53dd443d4384ef6fce878d07d9b4a1171eefea98242580e8a6a69664699f31e675cfb +adc48ef53d88b9d70409ed89cc3be592c4bd5eb65d9b1b28f2167dc4b12406889c00f2465c554f3aff673debc2997ccf +a62f5d9f167b9f4a4aab40d9cd8c8a48c519f64a1985823e20e233191b037c02e511b0280487112a9f8b1f1503b02db7 +b89aa2d4fb345a1d21133b0bd87f2326eb3285bd4da78b62174bf43d30a36340e4217dbe233afb925ab59e74c90fccf0 +932ba22acdd2f9d9494da90958bf39d8793af22417647d2082d2c3e6a5e17a2d14b0c096139fa8fa3f03967ca2f84963 +b67b107e71d96de1488b4154da83919d990502601c719e89feabe779049ddf7e4fb7e146eb05e754b70bbead4449efb1 +84509de1b8dc35aa2966d8a48501f725d59b4c65f3abf314b2009b9a573365ae3163c1f276708c66af17de180aae0868 +849153fe837a33fcb32c5fa6722c2db9753e984867c112a364eb880d87467782142d1c53a74b41df1dec7e900c877e1f +903d05c73ae043b69b18e980a058ce2254d008647a8d951175b9c47984164b34fc857108dcc29ad9df0806d7e90405f4 +a6b05917ac32c0b0eeea18f1ef3af5343778c543592078fdf6a1b47165013e2676bfe6a592a24efab9d49c4bd92b8fc0 +8648482f6947a5a8d892a39f098160aae1a648cb93e7724ea9e91b0d1a4f4150b91481f6e67d3bf29ff9d65ba4fa61a8 +a6ecaabc38895013297ae020686f04ea739c4512d2e3d6f2d9caf3f54000fb031f202e804ee615eb3357714a18657bcf +912f5935acc2dd20d5ef42b2ad5b307c925324a84a3c78ff66bc5885751934bd92f244e9636b60a744d750a2a7621198 +a0d6f261a776c5b114298f5de08d6e3372649b562051ea2470d3edfc376048793e18fc57ec84809b463dc72496d94329 +940744cd3118d1598c248b38503f6f1fbdbe7a147e683e5b3635140aa91679f8d6c1472600f8e9c36117a60203be6b4e +ab81737c839fe340f6f1fb7275811cb0c0d5fe8bbc265f6a56c6c68d0291bc7234eaa581ff26f8929d9a5bed4aac7002 +8df47341160f1c728c3e31be17a32e42b54faaa1286ef2c7946882ca4dd46443b8428f3654616c6e4053f1cda2e11994 +a721067e75c3c791f4d9f58d4810ac9621606e29c6badb593d6bb78c39968b45be1777ddb9bf03696d4d4be95b2dc1bf +a4e399213d3c4350c2d0cbe30757ba7e1f9680f58e214ff65433b36232323744c866a87d717851ba1dbd6769599f69a6 +b0be851d1e43dee27abe68f85e2330d94521b5f1c1a356ad83fcd09162c0ca9c2e88bccbcc5bacfa59661764361867a3 +86111bdd3dbfca232aa5802a6db41d639502e43a2e24cb06bb5d05c7f9b5ccac334d16b61d1c5eaac4fa0cab91113b46 +a4f805b11c174c34250748b9beebfb7c8c243198fb13463911906ee4effe7d331258a077e374b639a0c5cdcdff166b7f +87e4cf2c6f46d2dbac726a121127502921decf0195d7165e7bbeec6f976adb2d1c375eaa57f419895a2c70193215dc4c +8ff06de2c1c4d0744483bb4f7c5c80bf9c97b4df23e86c0bb17f1498ea70e0ee3af20827da5e8cb9d7f279dc50d7bd85 +ab112c0116471b4dc3fd1e6d918f99158eb7a08153e891ddbba2fe5bf0eeb188209e3019176e758231c3df937438136c +a67f89194e99e028a5da57747268e5ef66fefb881144043429920d222d37aaf268ebf73ca1da659fcdac3b4e7a65092a +b4da1dcc791566140d6abeaa2923cb6b21a6e6aaa30bb4cc70011e931eefa71f96b7e05358c0654bad7ce45191ab9fa8 +8283933231bca359db588c80e043ad6ea765fb0cba5ef233c5d514ba01ddd1b409efbadb368f26763402e4576dc4655f +97f568ce3edacd06f3e31a15462f5f9818a8c3fdbcf92b1ac5840b0b6e73166a154013dd52e85a18e8ead3fc9e54aca0 +a9cd1601c41e5ab2018f986443914fb703ddb6b06a36c06fb58065f2fee8e1751071ef924ea3ad76f0c19baccb1b5f8b +92aad71bb7e929cc35a48020d16a5822f4f106a7f59985005a5ae5ba8e8016ec33727610393498f56b4f353b3d5161b8 +89427780aa4e7ac894c681fbe2889153b94db883f17f109bc9caa93f0c259dda42aab502bbefaf572c56f70abbc42db8 +aa8cf76ff847dfe59534432ed8520bb48bf412c28497747dce04d2b2a54ba843c3be1564630cb49ec0217167847ba590 +a1570a6748a2303e74a31c2131d05ab372ec006ee92ef74c42f2e9a250663bebdfb3777e7ad91f50c954889a59c2d434 +a4c2b1bbc48199c31ea8d8196729eab00ce0200350d4aa9f23347a3289355e5828cb2f93036a14d2d9ec575fb3835239 +84819d0bedbaab5bf8afdf23f59a7ec5f50da3063cfdd1ef5fc4ca4c1fe68980b5c80e30a49f38e5816765e81dfc5a57 +a57cfb5e877b88202f589be777605deafbfc85ed1357af03a18709cfb4b668a271199899243cd3750f1cb77ebc40bba7 +8d95934bbb0efaf3339f27cb96de46e4486aa58a2c40dbc77c1c3ac7c27a228062824b9045c046631b2e286e8549603a +b99a8356abeee69f40cb3bd8c87e8039a1e076897dde430bfbf989dc495c48609a7122bc6c1d1c32ccac687b47d5558a +aac2edcf2fe5d3f1a84e8f1f27ece920eabe7793bf0ed5290cda380752e55d57a55a362c5253bebb71e4a55f2c437ff6 +af7c76876072c3b0091e22b9c5b27ce99bf1f0079ea1a7816ad9c06e9e5fc407595c7f4f9953e67d86fb2da656443dc3 +9175b64d104f78d3310c9c02f82e04c8e9878d2044ea5ee9c799846a3d23afa5fa2aa4af7350956136c69a0eed03cb2e +b3328e953317494a3d976e7f7c3d264258a5d4b2c88e12d06786a9e7b2affd41086762ef6124c6a6e5b6b028db933c14 +a49d166065e19d39299ee870229e4a04be81acd6af3a2201f3a291a025dd5f8bc3e676ee123cd4b9d8455f6a330b395b +85fa15bc8947ba03681d87b50bd2f8238b1c07849a7ed4e065053fad46aac9dd428186a6dd69dc61b5eba6ffec470831 +b6fcb2f694a47d3879b374b8b2967dcd59bd82a5d67ae6289a7326c18791b1b374e12571e8c8ea16a4bfc5525ced3ec4 +b6115f52566aa90ccac2aab6d2dbf46eca296d047db1eb29a1b8a2bc2eef7a24e90407f8dae528806aceb2a1e684d49e +9707e66220233f6a48a93e8dec7b253d19075eaa79238e519b82ce1ac5562cca184f8a1c14f708a96c34ad234673d646 +a0822903fb3825eae07ee9d3482277c0b8fc811856dfe4a51cf24b373f603924166fc5485185f99c4547cd6476b62270 +88dac6366c439daaeee2532b2ddbe206132cf6e12befbb8e99870ac684e04e62de150cba0e22e395a0b858948f40808b +a72dfba9caad3179f43fead0f75e33ba5342470d8c9cb7c86d30d2c7ce7244a8aafd1d558b0ec8e2a9436de2c2e95ccc +8d696046defcc32cc19954c559213100f0ba273ea12abb55ca7c42818071d853846bd4213af2c41ecd4442f6b4b511b1 +89d6f2d52cf65414da15a2fb1911c53afbfb50bb5f2638844abfc325ff2651cd9130be4beff05dc4046adfc44394a182 +afb91abd7c2a9cfe62855ede3c6960ad037fe8778364a2746ff7c214c55f84e19a474a9a0062b52a380d3170456ee9c6 +87f724a16ec8fdae8c05788fa3f823ecc3613df46581a63fc79b58f7c0dc2519b6b23e3dd441a0ca6946dfe4bc6cd0ce +86760f90f6bedfba404b234e90fbf981d26c29b87f2fa272c09540afa0f22e6682d08c21627b8a153c0feb27150458e2 +ad4d0342f255a232252450ce4209507ba619abfd1ffcb9c5707cfa45f89be41d88f1837acea993a1c47211b110250b4d +ace54b5889bccdf1d46c4ca21ed97cca57f7d12648381411d1b64afdfc64532a12d49655776ea24cf5eabe34145705ad +936dac693d0c1b1e5de1701f0bc46aef6e439e84bc368a23c0abe942eb539a2950e8929265786fcdb18d40a44bda14b9 +94fafbc544decec1d489b9ad6b23410b9de4779f9f44aabd093d7fab08340a4646a8cba31633e49c04d2690b8369a1d7 +98157e757f1a677c5d9d65c47759727a4dbc49fec2da4d9889c4ea90573fb42e2a8d72eaef92b782ac6f320970f09363 +8eaa0498c191c810c7e1ca7398f7c80dd0a7e7d7829ed07039490f60e7c2ae108843c06fe38fa36d45d63da46cba887c +a0ae116e5b0d2dccf83f056ad876037225687904e0290fe513fdc6b2dbe4cbf5fac1d828352e64734895895840b3c57c +b592b318dbbd7ec4872aae5e64bdf2305db2e5e8cfe0ad77b691f542ba5e066dd20b09b0b08ff0d798bd79ad946ddf7f +879e50c8c3e7f414ad2b38632bc482b71759cd561aeb2215550186ebb4559e4cf744cdf980512d8321954b3458d21e11 +aed5c6c7ce0407d7b2c04785fcb9deadb9b9413e37cef5b1d918f474cccc7de012fe1fa6f5fa93cb7ef9ac974d9fbc20 +892274a9f0afc68fa74be276c2a16de5cec674193f96b27a80bbb9f3add163f85716b531f3c920b98577a0225f84e8ca +938fb7a53266b997a7669596577af82f5289b160b7fcf06d76eee2a094696f6f12b28c2c65b833a52529a116c42e6c7e +892083929b6067f5045b1208f3dc8f0ee25bd0533a8831f5c23bb4ff46a82d48f0a34523359df5061d84a86b718d5060 +99159ae9574df6c16273eda66b6d8b79a327940e335b28c75d647f4744a009f4b5f0f385e2017bd3e7fbf59e629cd215 +a03e5757ef7738eba32d396923ff7ef82db2c15bb6adc8770fcb37260b7bda3be62473bc352a9a2ef7ec8ebe0d7688bc +ae3c24a85c9b1fa55158b2acd56d2016f70dca45a23f3ef7e0c6b096f4a7c54c14020d61bec7c7f87be4a595bf254209 +a920a6f9cc803fe31352fca39c13f8ac1e8d494fcf11b206092227c2af38469b1fbc068b8fe014800b70f137107aafc4 +b893853be57519ffa6410da605e7d3a746ebadec4788c7907f6e0dde9f20f5a6a01181148b874b3decf9b4814846a11a +b46f43918c5195729f6532439f815d1eb519e91005bc641a4a30ae88700982bf4ed07a342e77945780317c297c903755 +8e431bf4497d0ef6538c93c4bdda520179301a0104eebcfd104efa1edea876818d7d31079656f01a5ff76c4f5fcd71df +92e3dbcb580dfb9cc998f878052b0c3be1c5119e5249ae9bad3538ebb0f0c4ab5a959b04033b96d61836ef07784e6b64 +b712d9d63aa888156f4ec83e939c6bad53de18045f115f54fbf4261fb02f10a8a46a8d716ab43d4acbad3b02283c32fc +b2334e776988b4f772446a47c87416b4f19f9b44164a5f828424d3f35ef10baa56afe810d49b0b86b786b9c0227681a6 +a3f25ad18e435ef585fa90e6cef65a8ba327e5e33701979e27e64ef7d8e09e2591e52bff9c5749d35643456d18625685 +adcfa48ae43cac6fa9866b4cce10a243969965942c891d5e6c0e5b03bd4763f9b63779fbf40d26ac674534fe7cc478d7 +a0eb3448e045038740e2ee666e88aa0f8b8e24b1b55d7d4964f01bfc0c581f7e9d4c0e79f8cfbfecfa8b024b216c8ea6 +8110aa1d82f11965af4f4eedb4de09ee9c353481b2d7ee7a2bc2f302d2a5ae6c31ebc6451309ba7c305da41070b0f666 +b074fdad419d42783ebda17f19863aa499eec71fda5aab6cdcc389276b7bf08053795d15890175ca3dc89f6d8d17758c +a14665846d95d7d5f0b5381502080c822776ec0994ccb1ae1ffbb3f19205ce9c7c9bf9c2d2ca098807ce99f29e4f07a0 +b4884842670a333cb5548a842fa2971881e26b442dfab0b91d6bf3b4cbdf99adbbc9d14fe2bb46872cfcabedae85db30 +94549b01cb47ba16c0cf6f7522c833545397de0b3388c25d03e60132eddada6401682f9ffd8c50d1a61b4d2dde37461f +a790c9b4cec96e4c54777f3e03cea5769b20382cdcaf1de494bac2b9425eaf453eff643c62ab284cc1af33bbd36013be +b1b45fd298ed11609aa1ae6c5ac655e365bb451de1b9fc92aad40422ba85c6a454f33b8142acabe55171328c13d92edf +a74cea9e7096e38327064f058a3cdaa34e6eafaa9c7d58f753c40be67998152380fbd612b9dc0751bda7befcdffcc749 +b18978dfc5efb07b7ef992c7b0cf5d1b4ca551578b1dd13057b7aced8b1deb9f2036e1e3116248a803e922659d206545 +8153c07603cdff6622835a9853b795274390abf7197d7a192193bec44acb43e8cd50b56c11a03f4a2a27124c36974f3d +86b987f30bb9a37cc91d22dffffcd346ec5773e846a6c2b8f9e03b25ffcae859c470c901c4e29695d325dfe4eee927bd +af5e980b9507d10d5269c1a5d02bc16f4f009b663e413ea6a7c655250f3a21c608c12f4002269a05d3779907e7be7d69 +a6f737fab2af9f27bfb8ca87f5fdab6ad51e73ccf074e90576db57b309dfa0a95f9624526dfa4feaef39c388802f2ae9 +b7ed51f699f615f58a7ff4f99d52c4ce7a8d662843c1f4d91f1620fa119b80a0f6848f9fb6c4b9822dc019830e7dfd11 +b71f27f291aa6ef0723ed79c13a1c7a1c40198ffb780a129d9d20e250406bc91f459705b2b6674c9bb412a7b5dd9ff07 +9698cf8f638c3d2916fefa5f28c6050784479f84c2ee76a8aeda7e562630a6ae135b445ec4e29af8588ca5ad94a67f49 +9270aa5030966a9990d8bc71b00b9a7a1d7c1ad8f4c7f78a31b3d7f86467332f21407c74a89ba4f574d723acaf0d2042 +b1b82faceed8e2297cd49cc355471d15ff8dc2ccc78f6944c8f7a75d3ad1629a2e2f1d0a2ff7fa2b3c38cd19839aa5e9 +8a8c4ed49dc9bd961773edf8d41d04385b11bbd3577024639a39319cc7068380236bf73fce0b83e6535bd3f95cef0e65 +8d04ec1e7d148b7e66910ab45a0e6bf409612a3b560bfa784e26f2963152821c646a655cf17a0ce3d4ba4c4ebeeb4a1e +8e9d707f6186d93accb60813715ed1f6b3001ff6d2f87daf8b906bd0b988c1833b2ccd80dee9bdefb45901e81bb82971 +9762317ca6a5e6fe0b2991e0fa54b5fbf419dd0550d70074957d65cd7ebf79ceba607dd40d709ed635c822b3b4da2cac +82b53cd9a1eca2f5d3256723dc4b6531ca422bd87bab36243c727d1952db58d7288ab11467305d875d172ce165b1e4a5 +b4dbeafa05c87029ae257bee1ed7603645fab41f6ba7ac8b57ced5b4774a72ba3e671c2433a93acc3c498795b5cccc42 +a916d3ab7f0e7cef294e11c97c910a19c338ad8e615406e6d1c8995b4a19c3b2527100cc6b97a950ec5a4f3f6db7d01a +b9a785c7123609bdc96f8dd74500c6c77831d9d246f73244de964910b4045ce3242c881271bb1a4bc207d67de7b62e97 +b5f94084f695d0821c472e59c0b761e625b537c8ae3a09f11d9a57259e148cfadba1e43bf22c681b6b32390121cec208 +8f91b36d8570f19a90cf3ed6d5bb25f49a3315ddb566280c091fe2795c4e25ed2c6a1ef8d2669b83f2d7bb78fc8c40f5 +80f27359a73ed8fdd52762f0c7b9f676be2398b1f33c67877261480bf375f975f626c2ca3e7a9f59634db176ed672c98 +b96b91e3d5148ca793edefe4ca776b949c9305acb6f3a3cf87767a684014d2c8f2937c2c672eef8510f17d2da5d51385 +99c4e1ca2cabd4388ea2437dbdf809013d19be9bd09ff6088c8c0cfdb9ecf8fd514391a07b4288dd362434638b8834d9 +b6fdfb812e145f74853892c14f77c29b0c877d8b00055fd084b81360425b3660cd42236ecc853eadb25253e1cd8445c4 +a714af044ef500104576898b9409a9a326ef4286a45c3dae440bd9003fdf689c5f498f24a6f6d18502ce705c60a1cf14 +a9444e201be4a4d8c72119b3d3b13098afee6e5d13c5448fa2e9845cc9188239778f29b208749c960571dfa02b484f05 +91c826a6b8425f93ff395d9fdfa60dbfa655534c36c40a295906578540b9a0e6b94fd8d025b8b8611433022fbbc4fb0b +a355d76bc3cc48ba07026197130f25a593ec730d2ef0d5d2642bfcad745ecbe5c391324bc2485944060ff3100c952557 +b5f9b5a289a6f9a7252cc1f381c892bdb6836a5998f323ee21ae387936148ad1ad7cc6eca37ecece36404b958ae01e8e +a3c7ae04a6208851f6cc40ff270047283b95218905396c5dedc490e405061cbefd1251ecf77837d08c5ec1c77d2776ce +aa02ee387dd2cc7a23cf5cd582da0bc84bb33a7158d76545cbd6e06b26a6f30565dc712d7a8594c29f0529a892138802 +8aff025c841f167fadaf77a68284c355ace41d6df3a9f1e41a6e91454b336f0b69ea34cce495839b642a7c43997a8fd9 +82eccf0b6b4b6460f676d677266451d50f775446df313fc89bdf4c96e082340f6811939d215a54ba0fe30c69b3e43e25 +af324d871b038ff45a04366817c31d2c1e810359776fb57ac44907c6157004e3705476574e676b405d48a48bfb596f59 +9411dcca93ef5620ce375f379fea5c1017a2dd299e288e77b1ab126273631a299d7436f3bf3c860bf795e5faaaefa804 +934fca809e66f582c690c3778ea49de2e7940c0aeb8d7edad68f2edccdfda853d2c4844abd366fbc2215348935e4b2e2 +a1b1fa4c088418f2609d4dea0656b02a8ee664db25f40d53d8f4b1be89a55e5abecbf2c44c0499874abeb3d3a80acf71 +ae6ed7a0ba6280c679b0bf86111afad76fc5d930e9fb199df08134ba807f781d7e0b8b9b2c8c03b02d8cc20dbe949a28 +937d200a72fe4ab8d52f6cb849e322bc5959632b85a93c89744b33e832e8dcf1dddd6ffac0c049b03c105afb8930f7f5 +b4b4a46ebe0c5db16004933c08ad039d365db600a13d68be5346b1c840cce154f56c858874e866de8c3711e755c6e5dd +afcbcb7170c8caa2b77d2b3388dc2f640aeb9eff55798aeceb6eb6494438be05a2ae82f7034b2d439a45ad31d8c64b07 +a2c676273081b8761f58e0b11306ddb6a4cde3d90e7c47b434468700c5b749932819b01efd7637ca820e10fc28dfb427 +b445715162d834c9ee75ac2ff8932ace91c8242d67926b2a650217e4765e0531c2393c9438a52852d63dbbe2cceaafc5 +a0c0ebdc1480fb238a25fbfc77fae0db6e5e74b91809f0ff20a819e56b8c3141549615d1bd7b99829898f6028e8c86be +b3d11933e9d1db8ca617934261ed26c6f5ca06ba16369e7541482bf99c4f86520d43fbb10f4effb2fdf3cc70a189fdb5 +888ac610f8fd87a36b5646e1016eaf6dbca04aa0cc43f53a1046d74a658c4d2794606e79fb07fae57cf9d71ed339f4b6 +979818dab00c58435dc0d0d21185943f95819d2a13531abd2d798e1773c4bbd90047f4eebe117868743db75604a50227 +a6fbcd2656e475065fe44e995e8e2b5309b286b787a7597117e7acc3bb159e591a3e7304ef26f567b5720799d8ae1836 +a03f0ac08d2101ec4d99ca1443eea0efa767a65448a8ecd73a7818a99e863a04392bec8c5b8e5192834e8f98d4683f13 +b3c4ea8c6c3ee8aab2873d446ad702000b0e927e0991c9e30d83c6fe62a604efdc3ac92453313ff0d5e0ac6952922366 +ab25c857f26830631113d50145e961441b5e35d47b9e57f92466654dffebde43e4f78b0867d20929f97c2888c2f06509 +98950aa5a70ef41f274775f021a284d4d801a2efe2dea38460db8a3a8c08c243836d176e69127c2cd17497b0ca393e9e +a9698113febfb6d87fcb84bad82ce52d85a279d3a2933bdd179d53cfe8d6c6c68770e549a1e2947e7528a0e82c95d582 +832b504513266259db78478bd1b5a3b0f3bf2c6d25f1013e64bf0cfae9dc23da8ecd25f7f1047d2efb90e5f1d9b4b3cc +b588bba7bcc0d268ab260d5c1db2122cee7fd01583c7cc27a8ae6b48b29f34c6ea8a6acbb71b9b09c6156ec0a0766142 +a73d2223c7afadc381951a2e9e7bcb7b5c232369f27108c9f3c2ced2dc173e0f49531d0ca527eb142fbb70285307433f +9152cd6b97bd3278465348dde2095892f46342aed0e3d48675848c05b9aee6ef5ad7fe26e0dcd4ab176532289d40eedd +a7812a95a43b020721f688dd726356dda8ebe4de79b4f0fdef78615795e29681bff7c6ff710ff5b2d6ae3fd81bdb8507 +83724c16049e9eaae3269ea8e65caa212f0592e0190b47159bb3346208ccb9af3cfe8f6c3176fa566377da1046044ab8 +877634ec37c7dcd3b83705b103c31013697012795f11e8abf88d54bc84f2c060f665f0c3b14ef8087d3c6a8a7982d64f +b3e53aaacef7a20327bdbba8cd84513534d2e12fd5e1dcf2849f43146e098143b539ebd555623d0ecc46f5ebb4051fca +952d58ecafca9b7ffc25768ee4f05ce138f0289d72978eb5e5d3b23a0daedcb17478890afdce42e30d924d680e13c561 +a10dcc725f9a261de53dd3133858c126f6aa684cf26d92bce63a70e0ff5fff9610ad00d2b87e598b0a7548cfd1ffe713 +b7bc5d0c6b665d5e6f4d0af1c539d8a636550a327e50a0915c898ac494c42b3100e5fae0074c282d1c5073bf4a5456fb +8adc330d3b49ddf3ed210166afc944491aaedb28cb4e67472aeb496f66ce59184c842aa583bfb1a26d67d03b85065134 +b2df992a1310936394a1ebca94a7885b4c0a785638f92a7b567cfb4e68504ac5966a9e2b14891d0aa67d035a99e6583a +96f5da525d140739d19cebb706e2e1e0211edea1f518e040d361d5aca4c80f15be797f58cb4cd3908e4c360c18821243 +b2c0d9173a3d4867c8842e9b58feb1fb47f139f25d1e2332d6b70a85a58811ef99324bf8e52e144e839a4fe2d484e37b +ad95a7631ddb4846d9343d16533493524dfd22e8cbfc280a202343fccee86ab14446f6e7dad9bad9b4185c43fd5f862e +97f38ab82a51a7a792d459a90e7ea71c5a2f02d58e7d542eb3776d82413932737d9431bd6b74ec2a6a8b980d22d55887 +ad4e4c57ec3def5350c37659e8c15bd76d4c13d6de5453493123198dda2c2f40df349f20190e84d740a6b05e0b8f3deb +a691bc10810d11172a6662e46b6bbc48c351df32f325b319553377f525af44a50aaa02790c915b3a49824aa43f17fff0 +a80ccac79bb4014ee366dbf6e380beb61552bd30ef649d4ec39ab307e4139b7775e776fab30831517674ff3d673566f6 +b11e010b855d80e171705ab9e94364c45998e69d9120e4ca4127049b7a620c2eec1377356e7b877874e767f7c44afef4 +96bfab7777769a1e00ce16ada6667a0d21d709e71bd0371c03002427d138d9172640cdd5c529c710fea74bb9d19270c7 +a5bffd2c30e29633b4ecf637c1e792c0378252e2a99b385a093675940b48de2f262c275332ed4765f4a02467f98e3ddd +8d11929d67a6bd8a835b80660a89496250c766e713bddb2cd7052d67b92c39a38ce49005d38b4877856c4bef30fb9af4 +8e704597a0dba1dbd1ff8c9755ddac3f334eeeb513fd1c6b78366603ebc1778231deb8e18f2889421f0091e2c24d3668 +904fbb3f78a49e391a0544cf1faa96ba9402cba818359582258d00aff5319e3c214156cff8c603fbc53a45ede22443e9 +af12ac61eaa9c636481a46fd91903c8a16e7647534fc6fd9baa58ae2998c38ffbd9f03182062311c8adfef0a338aa075 +87f2e544b2993349ab305ab8c3bf050e7764f47d3f3031e26e084e907523d49e1d46c63d0c97b790394f25868e12b932 +a279a7bef6de9d4e183e2bedaf8c553fadfc623a9af8785fe7577cadced02b86e3dab1e97b492d4680c060ea0126abeb +8ece08667ed826f0a239cea72e11359f7e85d891826292b61d4edbdc672f8342e32c66bec3e6498016b8194168ba0e0d +90a15162586e991b302427bc0307790a957b53ab0e83c8b2216f6e6302bc496cb256f0f054ff2cccdfe042763de00976 +9966c0413b086a983f031a39080efde41a9fedcaf8e92897ce92e0c573b37981f5ea266b39dc4f4fb926a1bce5e95ad7 +9515be2f65a57e6960d71bfb1917d33f3f6d8b06f8f31df30fc76622949770fea90ff20be525ae3294c56bc91efb7654 +86e71c9b4059dc4fd1ce7e28883e4f579a51449cab5899e371118cdb6afe2758b1485961ca637c299896dea7c732151b +8695b4ff746d573f8d150f564e69fe51c0726c5d14aa1d72d944f4195e96165eca7eba8cac583fd19d26718b0ce3eb61 +813eecf402151c99c1a55b4c931716e95810fc4e6d117dfc44abbf5ef8dcdf3f971d90d7fa5e5def393681b9584637e0 +a9caf7219eed1db14b7b8f626f20294a3305ed1f6c22f6a26962772c2fa3e50b5234f6d9ba7fa5c3448824c2a15271b3 +b2b2ee20de9b334f2d82cbe0d2e426ca1f35f76218737d0069af9b727a1bfc12d40cf8b88d4afcbeaadf317b7f7ad418 +b853960749521a17ff45f16ac46813d249c4e26e3c08fd33d31ef1ed2b2e157c9cb18bd2454fb5c62690bdd090a48f60 +88772297d2972471b3db71f3ddbf5945a90154768ca49fa6729a5e2299f1795445fb3d4d969d1620e87dca618fbc8a6c +a2bb783fd13aee993e3efd3a963ebc8a8eacfc8450042f018f2040353de88c71ac784b0898bdff27f606c60a3d5ef2c6 +9210903ac619edca0cb8c288ed6dcc93c472f45182cd6614a8e2390801ddea41d48a4ac04a40e2f0adfd48f91aabe2ea +a621d00f83260c22db9fa28757ea81dabcc78b10eeaaf58b06b401db6cc7a7d9a6831a16f171ead4e8506d0c46a752ca +b25c525bf6761a18bbd156ac141df2595940c7b011ed849dbb8ac3a2cd2da6b63ba4755324d70dc14c959deb29fb9ad3 +a35111d0db3e862e1b06249d289e0fc6b110877d254f2ae1604fb21292c227a8b6d87dd17a7b31166038d6860b1bd249 +90bf057309867d95f27637bd10ef15ceb788f07d38aca7ad7920042293d7c4a1a13d4ca1d6db202864d86d20a93e16cf +a88510e110b268d15dcd163ba1e403e44b656771399ac3a049dcb672a1201e88bf60bdd1d303158888a3d30d616cc0bd +b33b7e1f765e9cbd5eeb925e69c39b0a9ea3348ab17f1dbb84b66f4a4b3233e28cbdeb0903d6cfe49ec4fc2f27378ff9 +b777da64fa64d9bc3d2d81b088933fce0e5fcc29c15536159c82af3622a2604c2b968991edea7b6882c9e6f76b544203 +8ea598e402a056fd8031fbf3b9e392347999adc1bd5b68c5797a791a787d006e96918c799467af9ac7f5f57eb30b4f94 +b6901a389bf3b3045e679d015c714d24f8bbe6183349b7f6b42f43409a09f0d5bd4b794012257d735c5fdf6d1812554b +b5866426336d1805447e6efc3f3deb629b945b2781f618df9a2cc48c96020846e9108f9d8507a42ba58d7617cb796c31 +a18ccc6ad1caa8462fa9bec79510689dd2a68d2e8b8e0ddbeb50be4d77728e1d6a18748a11e27edd8d3336c212689a4d +abbd48c48a271b6b7c95518a9352d01a84fb165f7963b87cdc95d5891119a219571a920f0d9ceedc8f9f0de4ab9deb65 +94a4e5f4d7e49229e435530b12a1ff0e9259a44a4f183fb1fe5b7b59970436e19cf932625f83f7b75702fd2456c3b801 +af0a6f2a0d0af7fc72e8cb690f0c4b4b57b82e1034cca3d627e8ef85415adec8eb5df359932c570b1ee077c1d7a5a335 +9728025e03114b9e37ed43e9dcba54a2d67f1c99c34c6139e03d4f9c57c9e28b6b27941d9fca4051d32f9b89bec6537b +941601742d1e1ec8426591733a4f1c13785b0a9b0a6b2275909301a6a3c6c1e2fb1ffa5fdcc08d7fb69f836ae641ced5 +b84b90480defd22f309e294379d1ca324a76b8f0ba13b8496b75a6657494e97d48b0ea5cfdb8e8ac7f2065360e4b1048 +95cc438ee8e370fc857fd36c3679c5660cf6a6c870f56ef8adf671e6bf4b25d1dbad78872cc3989fdfe39b29fc30486d +8aafba32e4a30cad79c5800c8709241b4041b0c13185ea1aa9bc510858709870b931d70b5d9a629f47579b161f1d8af7 +865b0155d9013e80cba57f204c21910edbd4d15e53ae4fee79992cb854dc8b8a73f0a9be92f74893e30eb70f270511bc +b9a49ce58d40b429ac7192cdbf76da31300efc88c827b1e441dd5bdb2f1c180d57808c48992492a2dc5231008629159f +8d1438b10f6cd996494d4c7b5a0841617ec7cf237c9e0956eac04fda3f9ded5110ec99776b816e3c78abd24eb4a9c635 +af2dd18211bb8a3e77c0a49d5773da6e29e4e6fa6632a6eeb56c4be233f6afe81655d977932548de2be16567c54ffbd7 +92b92443f44464f2b48002a966664a4267eae559fa24051983bcf09d81bed5bcc15cb6ff95139d991707697a5d0cc1ab +a1864a2bac0c0dd5b2fb1a79913dd675fe0a5ae08603a9f69d8ca33268239ac7f2fed4f6bf6182a4775683cb9ccd92a8 +948e8f1cf5bd594c5372845b940db4cb2cb5694f62f687952c73eb77532993de2e2d7d974a2ced58730d12c8255c30a2 +aa825c08284fa74a99fcfc473576e8a9788277f72f8c87f29be1dd41229c286c2753ff7444c753767bd8180226763dfc +8384d8d51415e1a4d6fe4324504e958c1b86374cc0513ddf5bcbffabb3edcf4b7d401421e5d1aa9da9010f07ef502677 +8b8223a42585409041d8a6e3326342df02b2fe0bcc1758ff950288e8e4677e3dc17b0641286eaf759a68e005791c249c +a98a98cc2fb14e71928da7f8ce53ab1fb339851c9f1f4bceb5f1d896c46906bd027ef5950ca53b3c8850407439efedd4 +866f44d2e35a4dbffe6cd539b6ef5901924061e37f9a0e7007696fb23526379c9b8d095b417effe1eecda698de744dcb +91774f44bf15edafdf43957fdf254682a97e493eb49d0779c745cb5dbe5d313bf30b372edd343f6d2220475084430a2e +ab52fc3766c499a5f5c838210aada2c3bcc1a2ec1a82f5227d4243df60809ee7be10026642010869cfbf53b335834608 +a0e613af98f92467339c1f3dc4450b7af396d30cefd35713388ccd600a3d7436620e433bf294285876a92f2e845b90d0 +8a1b5ca60a9ae7adc6999c2143c07a855042013d93b733595d7a78b2dc94a9daa8787e2e41b89197a0043343dbd7610f +ae7e4557bc47b1a9af81667583d30d0da0d4a9bb0c922450c04ec2a4ae796c3f6b0ede7596a7a3d4e8a64c1f9ee8ff36 +8d4e7368b542f9f028309c296b4f84d4bde4837350cf71cfe2fa9d4a71bce7b860f48e556db5e72bc21cf994ffdf8e13 +af6ed1fbff52dd7d67d6a0edfa193aa0aab1536979d27dba36e348759d3649779f74b559194b56e9378b41e896c4886f +a069ba90a349ac462cac0b44d02c52a4adf06f40428aef5a2ddff713de31f991f2247fc63426193a3ea1b1e50aa69ded +8750f5f4baf49a5987470f5022921108abe0ead3829ddef00e61aedd71f11b1cdd4be8c958e169440b6a8f8140f4fbf9 +a0c53cefc08a8d125abd6e9731bd351d3d05f078117ff9c47ae6b71c8b8d8257f0d830481f941f0c349fc469f01c9368 +94eea18c5ed056900c8285b05ba47c940dff0a4593b627fdd8f952c7d0122b2c26200861ef3e5c9688511857535be823 +8e1b7bd80d13460787e5060064c65fbcdac000c989886d43c7244ccb5f62dcc771defc6eb9e00bae91b47e23aeb9a21f +b4b23f9dd17d12e145e7c9d3c6c0b0665d1b180a7cfdf7f8d1ab40b501c4b103566570dca2d2f837431b4bf698984cad +847a47c6b225a8eb5325af43026fb9ef737eede996257e63601f80302092516013fde27b93b40ff8a631887e654f7a54 +9582d7afb77429461bd8ebb5781e6390a4dde12a9e710e183581031ccfacd9067686cfaf47584efaafeb1936eae495cc +8e4fd5dbd9002720202151608f49ef260b2af647bd618eb48ebeceeb903b5d855aa3e3f233632587a88dc4d12a482df9 +87b99fe6a9c1d8413a06a60d110d9e56bb06d9f0268dc12e4ab0f17dd6ca088a16ade8f4fb7f15d3322cbe7bfd319ae1 +b562d23002ed00386db1187f519018edd963a72fca7d2b9fcaab9a2213ac862803101b879d1d8ac28d1ccae3b4868a05 +b4cc8b2acacf2ce7219a17af5d42ce50530300029bc7e8e6e2a3c14ff02a5b33f0a7fecb0bb4a7900ea63befa854a840 +9789f0fe18d832ff72df45befa7cabf0a326b42ada3657d164c821c35ac7ed7b2e0eba3d67856e8c387626770059b0c3 +986c6fe6771418549fa3263fa8203e48552d5ecb4e619d35483cb4e348d849851f09692821c9233ae9f16f36979c30c2 +a9160182a9550c5756f35cea1fe752c647d1b64a12426a0b5b8d48af06a12896833ec5f5d9b90185764db0160905ca01 +82614dbd89d54c1e0af4f6ffe8710e6e871f57ef833cbcb3d3d7c617a75ec31e2a459a89ebb716b18fc77867ff8d5d47 +8fc298ffba280d903a7873d1b5232ce0d302201957226cddff120ffe8df9fee34e08420302c6b301d90e3d58f10beeb9 +898da9ac8494e31705bdf684545eee1c99b564b9601877d226d0def9ec67a20e06f8c8ba2a5202cc57a643487b94af19 +88218478d51c3ed2de35b310beedf2715e30208c18f046ee65e824f5e6fd9def921f6d5f75fd6dde47fa670c9520f91a +89703ae7dff9b3bc2a93b44cdbab12c3d8496063a3c658e21a7c2078e4c00be0eecae6379ee8c400c67c879748f1d909 +a44d463477dece0d45abb0ebb5f130bfb9c0a3bbcd3be62adf84a47bbd6938568a89bc92a53ca638ff1a2118c1744738 +95df2b4d392143ee4c39ad72f636d0ed72922de492769c6264015776a652f394a688f1d2b5cf46077d01fda8319ba265 +aa989867375710ed07ad6789bfb32f85bdc71d207f6f838bd3bde9da5a169325481ac326076b72358808bd5c763ba5bb +b859d97d0173920d16bc01eb7d3ddd47273daac72f86c4c30392f8de05fee643e8d6aa8bebdbc5c2d89037bc68a8a105 +b0249ec97411fa39aa06b3d9a6e04bbbcd5e99a7bc527273b6aa95e7ae5f437b495385adaefa4327231562d232c9f822 +8209e156fe525d67e1c83ec2340d50d45eba5363f617f2e5738117cdcc4a829c4cc37639afd7745cbe929c66754fd486 +99fd2728ceb4c62e5f0763337e6d28bf11fbe5df114217f002bc5cd3543c9f62a05a8a41b2e02295360d007eaab796a6 +902ebc68b8372feeaf2e0b40bd6998a0e17981db9cc9d23f932c34fbcc680292a0d8adcea2ad3fb2c9ed89e7019445c2 +8b5653f4770df67f87cb68970555b9131c3d01e597f514e0a399eec8056e4c5a7deed0371a27b3b2be426d8e860bf9f2 +8f5af27fdc98a29c647de60d01b9e9fd0039013003b44ba7aa75a4b9c42c91feb41c8ae06f39e22d3aed0932a137affa +81babb9c1f5bcc0fd3b97d11dd871b1bbd9a56947794ff70ab4758ae9850122c2e78d53cb30db69ece23538dc4ee033e +b8b65d972734f8ecae10dd4e072fa73c9a1bf37484abcfa87e0d2fcecac57294695765f63be87e1ba4ec0eb95688403a +b0fe17d0e53060aef1947d776b06ab5b461a8ef41235b619ca477e3182fadaf9574f12ffc76420f074f82ac4a9aa7071 +ae265c0b90bf064d7a938e224cb1cd3b7eca3e348fbc4f50a29ac0930a803b96e0640992354aa14b303ea313cb523697 +8bc10ffde3224e8668700a3450463ab460ec6f198e1deb016e2c9d1643cc2fe1b377319223f41ffeb0b85afd35400d40 +8d5113b43aea2e0cc6f8ec740d6254698aff7881d72a6d77affd6e6b182909b4de8eb5f524714b5971b418627f15d218 +ae2ef0a401278b7b5d333f0588773ec62ead58807cdee679f72b1af343c1689c5f314989d9e6c9369f8da9ce76979db6 +b9c1cb996a78d4f7793956daaa8d8825dd43c4c37877bc04026db4866144b1bf37aa804d2fe0a63c374cf89e55e9069f +a35f73851081f6540e536a24a28808d478a2bb1fd15ee7ff61b1562e44fbafc0004b9c92c9f96328d546b1287e523e48 +82007f34e3383c628c8f490654369744592aa95a63a72be6e90848ad54f8bc2d0434b62f92a7c802c93017214ecf326e +9127db515b1ed3644c64eaf17a6656e6663838fed4c6612a444a6761636eaaeb6a27b72d0e6d438c863f67b0d3ec25c5 +984c9fcc3deccf83df3bbbb9844204c68f6331f0f8742119ba30634c8c5d786cd708aa99555196cf6563c953816aec44 +a0f9daf900112029474c56ddd9eb3b84af3ed2f52cd83b4eb34531cf5218e7c58b3cab4027b9fc17831e1b6078f3bf4a +90adbcc921369023866a23f5cea7b0e587d129ad71cab0449e2e2137838cea759dec27b0b922c59ac4870ef6146ea283 +8c5650b6b9293c168af98cf60ad35c945a30f5545992a5a8c05d42e09f43b04d370c4d800f474b2323b4269281ca50f8 +868d95be8b34a337b5da5d886651e843c073f324f9f1b4fbd1db14f74aba6559449f94c599f387856c5f8a7bc83b52a1 +812df0401d299c9e95a8296f9c520ef12d9a3dd88749b51eab8c1b7cc97961608ab9fc241a7e2888a693141962c8fd6d +abda319119d8a4d089393846830eee19d5d6e65059bf78713b307d0b4aad245673608b0880aa31c27e96c8d02eff39c0 +887f11ae9e488b99cb647506dcaa5e2518b169ee70a55cd49e45882fe5bfb35ffaf11feb2bf460c17d5e0490b7c1c14d +b36b6e9f95ffff917ca472a38fa7028c38dc650e1e906e384c10fe38a6f55e9b84b56ffa3a429d3b0c3e2cf8169e66a9 +a0450514d20622b7c534f54be3260bab8309632ca21c6093aa0ccc975b8eed33a922cbcc30a730ccc506edf9b188a879 +87cfaf7bcd5d26875ca665ac45f9decd3854701b0443332da0f9b213e69d6f5521ae0217ec375489cd4fad7b4babf724 +842ad67c1baf7a9d4504c10c5c979ce0a4d1b86a263899e2b5757407c2adcdcf7ed58173ad9d156d84075ef8798cb1c4 +ac1a05755fe4d3fb2ab5b951bafe65cca7c7842022ca567b32cddf7741782cbf8c4990c1dd4ea05dc087a4712844aebb +a000c8cecc4fddeb926dc8dd619952bc51d00d7c662e025f973387a3fc8b1ef5c7c10b6a62e963eb785e0ec04cb1ffbe +8a573c9986dbeb469547dfd09f60078eab252d8ec17351fe373a38068af046b0037967f2b3722fa73ed73512afd038d2 +b8dff15dff931f58ba05b6010716c613631d7dd9562ae5138dbec966630bcdb0e72552e4eefc0351a6a6b7912d785094 +990e81fd459433522e8b475e67e847cb342c4742f0dbf71acc5754244ccd1d9ff75919168588d8f18b8aea17092dd2a4 +b012f8644da2113bef7dd6cdc622a55cfa0734bd267b847d11bba2e257a97a2a465c2bb616c240e197ff7b23e2ce8d8e +a659bd590fde467766e2091c34a0b070772f79380be069eef1afecc470368a95afd9eed6520d542c09c0d1a9dca23bd0 +b9239f318b849079477d1cf0a60a3d530391adacd95c449373da1c9f83f03c496c42097c3f9aca10c1b9b3dbe5d98923 +851e9a6add6e4a0ee9994962178d06f6d4fbc0def97feef1ba4c86d3bcf027a59bafa0cf25876ca33e515a1e1696e5cc +803b9c5276eed78092de2f340b2f0d0165349a24d546e495bd275fe16f89a291e4c74c22fdee5185f8fce0c7fbced201 +95915654ca4656d07575168fb7290f50dc5dcbbcdf55a44df9ec25a9754a6571ab8ca8a159bc27d9fa47c35ffd8f7ffd +88f865919764e8e765948780c4fdd76f79af556cd95e56105d603c257d3bfb28f11efca1dfb2ce77162f9a5b1700bac8 +b1233131f666579b4cc8b37cfa160fc10551b1ec33b784b82685251464d3c095cdde53d0407c73f862520aa8667b1981 +a91115a15cf4a83bda1b46f9b9719cfba14ffb8b6e77add8d5a0b61bea2e4ea8ce208e3d4ed8ca1aab50802b800e763a +93553b6c92b14546ae6011a34600a46021ce7d5b6fbfcda2a70335c232612205dbe6bfb1cc42db6d49bd4042c8919525 +8c2a498e5d102e80c93786f13ccf3c9cab7f4c538ccf0aee8d8191da0dbca5d07dff4448383e0cf5146f6d7e629d64f8 +a66ab92c0d2c07ea0c36787a86b63ee200499527c93b9048b4180fc77e0bb0aa919f4222c4bec46eeb3f93845ab2f657 +917e4fc34081a400fc413335fdf5a076495ae19705f8542c09db2f55fa913d6958fa6d711f49ad191aec107befc2f967 +940631a5118587291c48ac8576cdc7e4a904dd9272acb79407a7d3549c3742d9b3669338adbc1386724cc17ee0cc1ca3 +ae23ae3a531900550671fd10447a35d3653c5f03f65b0fdffe092844c1c95d0e67cab814d36e6388db5f8bd0667cd232 +ae545727fca94fd02f43e848f0fbbb1381fd0e568a1a082bf3929434cc73065bfbc9f2c840b270dda8cc2e08cd4d44b0 +8a9bc9b90e98f55007c3a830233c7e5dc3c4760e4e09091ff30ee484b54c5c269e1292ce4e05c303f6462a2a1bd5de33 +a5a2e7515ce5e5c1a05e5f4c42f99835f6fde14d47ecb4a4877b924246038f5bc1b91622e2ff97ed58737ed58319acfa +8fa9f5edf9153618b72b413586e10aaa6c4b6e5d2d9c3e8693ca6b87804c58dc4bf23a480c0f80cb821ebc3cf20ea4fc +925134501859a181913aadac9f07f73d82555058d55a7d5aaa305067fbd0c43017178702facc404e952ea5cfd39db59b +8b5ab1d9b5127cb590d6bddbf698ffe08770b6fc6527023d6c381f39754aecc43f985c47a46be23fe29f6ca170249b44 +aa39c6b9626354c967d93943f4ef09d637e13c505e36352c385b66e996c19c5603b9f0488ad4014bb5fc2e051b2876cc +8e77399c6e9cb8345002195feb7408eb571e6a81c0418590d2d775af7414fc17e61fe0cd37af8e737b59b89c849d3a28 +a0150aeca2ddc9627c7ea0af0dd4426726583389169bc8174fc1597cc8048299cc594b22d234a4e013dff7232b2d946c +98659422ef91f193e6104b09ff607d1ed856bb6baed2a6386c9457efbc748bd1bf436573d80465ebc54f8c340b697ea5 +8d6fb015898d3672eb580e1ffdf623fc4b23076664623b66bfb18f450d29522e8cb9c90f00d28ccf00af34f730bff7ac +996a8538efa9e2937c1caad58dc6564e5c185ada6cdcef07d5ec0056eb1259b0e4cef410252a1b5dbaee0da0b98dac91 +aa0ae2548149d462362a33f96c3ce9b5010ebf202602e81e0ef77e22cfc57ecf03946a3076b6171bea3d3dc9681187d7 +a5ce876b29f6b89050700df46d679bed85690daf7bad5c0df65e6f3bde5673e6055e6c29a4f4dcb82b93ccecf3bad9cc +81d824bb283c2f55554340c3514e15f7f1db8e9e95dd60a912826b1cccb1096f993a6440834dad3f2a5de70071b4b4b5 +914e7291da286a89dfc923749da8f0bf61a04faa3803d6d10633261a717184065dcc4980114ad852e359f79794877dd9 +ae49dc760db497c8e834510fe89419cc81f33fd2a2d33de3e5e680d9a95a0e6a3ccbdf7c0953beeb3d1caf0a08b3e131 +b24f527d83e624d71700a4b238016835a2d06f905f3740f0005105f4b2e49fc62f7e800e33cdc900d805429267e42fc0 +b03471ecaa7a3bf54503347f470a6c611e44a3cee8218ad3fcad61d286cfb7bb6a1113dad18475ec3354a71fcc4ec1e2 +881289b82b30aff4c8f467c2a25fced6064e1eece97c0de083e224b21735da61c51592a60f2913e8c8ba4437801f1a83 +b4ce59c0fc1e0ecad88e79b056c2fd09542d53c40f41dea0f094b7f354ad88db92c560b9aeb3c0ef48137b1a0b1c3f95 +a1ffb30eb8ef0e3ea749b5f300241ebe748ed7cf480e283dfcda7380aa1c15347491be97e65bc96bdf3fe62d8b74b3ae +b8954a826c59d18c6bfab24719f8730cc901868a95438838cd61dac468a2d79b1d42f77284e86e3382bf4f2a22044927 +818e7e7c59b6b5e22b3c2c19c163f2e787f2ff3758d395a4da02766948935eb44413c3ddd2bf45804a3c19744aa332f3 +a29556e49866e4e6f01d4f042eed803beeda781462884a603927791bd3750331a11bc013138f3270c216ab3aa5d39221 +b40885fa0287dc92859b8b030c7cca4497e96c387dcfe6ed13eb7f596b1eb18fb813e4ae139475d692f196431acb58fe +89cd634682fd99ee74843ae619832780cf7cd717f230ea30f0b1821caf2f312b41c91f459bdba723f780c7e3eed15676 +b48c550db835750d45a7f3f06c58f8f3bf8766a441265ca80089ead0346f2e17cbb1a5e843557216f5611978235e0f83 +90936ee810039783c09392857164ab732334be3a3b9c6776b8b19f5685379c623b1997fb0cdd43af5061d042247bc72f +a6258a6bae36525794432f058d4b3b7772ba6a37f74ef1c1106c80a380fc894cbeac4f340674b4e2f7a0f9213b001afd +8f26943a32cf239c4e2976314e97f2309a1c775777710393c672a4aab042a8c6ee8aa9ac168aed7c408a436965a47aeb +820f793573ca5cc3084fe5cef86894c5351b6078df9807d4e1b9341f9d5422dd29d19a73b0843a14ad63e8827a75d2da +a3c4fca786603cd28f2282ba02afe7cf9287529e0e924ca90d6cdfd1a3912478ebb3076b370ee72e00df5517134fe17f +8f3cdabd0b64a35b9ee9c6384d3a8426cc49ae6063632fb1a56a0ae94affa833955f458976ff309dafd0b2dd540786ae +945a0630cd8fa111cfd776471075e5d2bbe8eb7512408b5c79c8999bfaeca6c097f988fb1c38fa9c1048bac2bca19f2e +8a7f6c4e0ba1920c98d0b0235b4dda73b631f511e209b10c05c550f51e91b4ba3893996d1562f04ac7105a141464e0e9 +ab3c13d8b78203b4980412edc8a8f579e999bf79569e028993da9138058711d19417cf20b477ef7ed627fa4a234c727a +82b00d9a3e29ed8d14c366f7bb25b8cfe953b7be275db9590373a7d8a86ea927d56dc3070a09ef7f265f6dd99a7c896e +b6e48a282de57949821e0c06bc9ba686f79e76fb7cbf50ea8b4651ccd29bc4b6da67efea4662536ba9912d197b78d915 +a749e9edcba6b4f72880d3f84a493f4e8146c845637009f6ff227ff98521dbbe556a3446340483c705a87e40d07364bc +b9b93c94bd0603ce5922e9c4c29a60066b64a767b3aed81d8f046f48539469f5886f14c09d83b5c4742f1b03f84bb619 +afa70b349988f85ed438faafa982df35f242dd7869bda95ae630b7fd48b5674ef0f2b4d7a1ca8d3a2041eff9523e9333 +a8e7e09b93010982f50bd0930842898c0dcd30cdb9b123923e9d5ef662b31468222fc50f559edc57fcfdc597151ebb6e +8ce73be5ac29b0c2f5ab17cae32c715a91380288137d7f8474610d2f28d06d458495d42b9cb156fb1b2a7dfdcc437e1c +85596c1d81f722826d778e62b604eb0867337b0204c9fae636399fa25bb81204b501e5a5912654d215ec28ff48b2cb07 +96ff380229393ea94d9d07e96d15233f76467b43a3e245ca100cbecbdbb6ad8852046ea91b95bb03d8c91750b1dfe6e1 +b7417d9860b09f788eb95ef89deb8e528befcfa24efddbc18deaf0b8b9867b92361662db49db8121aeea85a9396f64fd +97b07705332a59cdba830cc8490da53624ab938e76869b2ce56452e696dcc18eb63c95da6dffa933fb5ffb7585070e2d +971f757d08504b154f9fc1c5fd88e01396175b36acf7f7abcfed4fff0e421b859879ed268e2ac13424c043b96fbe99fc +b9adb5d3605954943a7185bddf847d4dbe7bafe970e55dc0ec84d484967124c26dd60f57800d0a8d38833b91e4da476a +b4856741667bb45cae466379d9d6e1e4191f319b5001b4f963128b0c4f01819785732d990b2f5db7a3452722a61cd8cc +a81ec9f2ab890d099fb078a0c430d64e1d06cbbe00b1f140d75fc24c99fe35c13020af22de25bbe3acf6195869429ba5 +99dcea976c093a73c08e574d930d7b2ae49d7fe43064c3c52199307e54db9e048abe3a370b615798b05fe8425a260ba0 +a1f7437c0588f8958b06beb07498e55cd6553429a68cd807082aa4cc031ab2d998d16305a618b3d92221f446e6cd766d +806e4e0958e0b5217996d6763293f39c4f4f77016b3373b9a88f7b1221728d14227fce01b885a43b916ff6c7a8bc2e06 +8e210b7d1aff606a6fc9e02898168d48ec39bc687086a7fe4be79622dd12284a5991eb53c4adfe848251f20d5bfe9de0 +82810111e10c654a6c07cbfd1aff66727039ebc3226eef8883d570f25117acf259b1683742f916ac287097223afc6343 +92f0e28cca06fd543f2f620cc975303b6e9a3d7c96a760e1d65b740514ccd713dc7a27a356a4be733570ca199edd17ba +900810aa4f98a0d6e13baf5403761a0aeb6422249361380c52f98b2c79c651e3c72f7807b5b5e3a30d65d6ff7a2a9203 +b0740bfefea7470c4c94e85185dbe6e20685523d870ff3ef4eb2c97735cef41a6ab9d8f074a37a81c35f3f8a7d259f0e +af022e98f2f418efbbe2de6fefb2aa133c726174f0f36925a4eafd2c6fd6c744edb91386bafb205ce13561de4294f3a6 +95e4592e21ba97e950abb463e1bc7b0d65f726e84c06a98eb200b1d8bfc75d4b8cff3f55924837009e88272542fd25ec +b13bd6b18cd8a63f76c9831d547c39bbd553bda66562c3085999c4da5e95b26b74803d7847af86b613a2e80e2f08caae +a5625658b474a95aba3e4888c57d82fb61c356859a170bc5022077aa6c1245022e94d3a800bf7bd5f2b9ab1348a8834e +a097ee9e6f1d43e686df800c6ce8cfc1962e5a39bb6de3cf5222b220a41b3d608922dae499bce5c89675c286a98fdabd +94230ba8e9a5e9749cd476257b3f14a6bf9683e534fb5c33ca21330617533c773cb80e508e96150763699ad6ecd5aee7 +b5fea7e1f4448449c4bc5f9cc01ac32333d05f464d0ed222bf20e113bab0ee7b1b778cd083ceae03fdfd43d73f690728 +a18a41a78a80a7db8860a6352642cdeef8a305714543b857ca53a0ee6bed70a69eeba8cfcf617b11586a5cc66af4fc4f +85d7f4b3ff9054944ac80a51ef43c04189d491e61a58abed3f0283d041f0855612b714a8a0736d3d25c27239ab08f2ec +b1da94f1e2aedd357cb35d152e265ccfc43120825d86733fa007fc1e291192e8ff8342306bef0c28183d1df0ccec99d0 +852893687532527d0fbeea7543ac89a37195eadab2f8f0312a77c73bdeed4ad09d0520f008d7611539425f3e1b542cfd +99e3bd4d26df088fc9019a8c0b82611fd4769003b2a262be6b880651d687257ded4b4d18ccb102cba48c5e53891535e4 +98c407bc3bbc0e8f24bedf7a24510a5d16bce1df22940515a4fbdacd20d06d522ef9405f5f9b9b55964915dd474e2b5c +80de0a12f917717c6fc9dc3ccc9732c28bae36cff4a9f229d5eaf0d3e43f0581a635ba2e38386442c973f7cb3f0fdfa7 +94f9615f51466ae4bb9c8478200634b9a3d762d63f2a16366849096f9fc57f56b2e68fe0ca5d4d1327a4f737b3c30154 +a3dcbe16499be5ccb822dfcd7c2c8848ba574f73f9912e9aa93d08d7f030b5076ca412ad4bf6225b6c67235e0ab6a748 +98f137bf2e1aea18289750978feb2e379054021e5d574f66ca7b062410dcfe7abb521fab428f5b293bbe2268a9af3aa4 +8f5021c8254ba426f646e2a15b6d96b337a588f4dfb8cbae2d593a4d49652ca2ada438878de5e7c2dbbd69b299506070 +8cc3f67dd0edcdb51dfd0c390586622e4538c7a179512f3a4f84dd7368153a28b1cf343afd848ac167cb3fcaa6aee811 +863690f09ac98484d6189c95bc0d9e8f3b01c489cb3f9f25bf7a13a9b6c1deaf8275ad74a95f519932149d9c2a41db42 +8494e70d629543de6f937b62beca44d10a04875bd782c9a457d510f82c85c52e6d34b9c3d4415dd7a461abbcc916c3c4 +925b5e1e38fbc7f20371b126d76522c0ea1649eb6f8af8efb389764ddcf2653775ef99a58a2dcf1812ce882964909798 +94d0494dcc44893c65152e7d42f4fb0dc46af5dc5674d3c607227160447939a56d9f9ea2b3d3736074eef255f7ec7566 +b0484d33f0ef80ff9b9d693c0721c77e518d0238918498ddf71f14133eb484defb9f9f7b9083d52bc6d6ba2012c7b036 +8979e41e0bb3b501a7ebbd024567ce7f0171acfea8403a530fe9e791e6e859dfbd60b742b3186d7cf5ab264b14d34d04 +af93185677d39e94a2b5d08867b44be2ba0bb50642edca906066d80facde22df4e6a7a2bd8b2460a22bdf6a6e59c5fdd +90f0ef0d7e7ab878170a196da1b8523488d33e0fde7481f6351558b312d00fa2b6b725b38539063f035d2a56a0f5e8f1 +a9ca028ccb373f9886574c2d0ea5184bc5b94d519aa07978a4814d649e1b6c93168f77ae9c6aa3872dd0eea17968ec22 +82e7aa6e2b322f9f9c180af585b9213fb9d3ad153281f456a02056f2d31b20d0f1e8807ff0c85e71e7baca8283695403 +affce186f842c547e9db2dffc0f3567b175be754891f616214e8c341213cbf7345c9ecd2f704bb0f4b6eba8845c8d8a7 +ab119eb621fade27536e98c6d1bc596388bb8f5cad65194ea75c893edbe6b4d860006160f1a9053aea2946bd663e5653 +99cd2c1c38ead1676657059dc9b43d104e8bd00ae548600d5fc5094a4d875d5b2c529fac4af601a262045e1af3892b5e +b531a43b0714cc638123487ef2f03dfb5272ff399ff1aa67e8bc6a307130d996910fb27075cbe53050c0f2902fc32ffe +923b59ac752c77d16b64a2d0a5f824e718460ef78d732b70c4c776fecc43718ecfaf35f11afbb544016232f445ecab66 +a53439cd05e6e1633cdce4a14f01221efcd3f496ac1a38331365c3cadc30013e5a71600c097965927ee824b9983a79cb +8af976ffab688d2d3f9e537e2829323dda9abf7f805f973b7e0a01e25c88425b881466dee37b25fda4ea683a0e7b2c03 +92e5f40230a9bfbb078fa965f58912abb753b236f6a5c28676fb35be9b7f525e25428160caeaf0e3645f2be01f1a6599 +8c4e7b04e2f968be527feba16f98428508a157b7b4687399df87666a86583b4446a9f4b86358b153e1660bb80bd92e8b +97cd622d4d8e94dceb753c7a4d49ea7914f2eb7d70c9f56d1d9a6e5e5cc198a3e3e29809a1d07d563c67c1f8b8a5665a +967bfa8f411e98bec142c7e379c21f5561f6fd503aaf3af1a0699db04c716c2795d1cb909cccbcb917794916fdb849f1 +b3c18a6caa5ca2be52dd500f083b02a4745e3bcaed47b6a000ce7149cee4ed7a78d2d7012bf3731b1c15c6f04cbd0bd1 +b3f651f1f84026f1936872956a88f39fcfe3e5a767233349123f52af160f6c59f2c908c2b5691255561f0e70620c8998 +ae23b59dc2d81cec2aebcaaf607d7d29cf588f0cbf7fa768c422be911985ca1f532bb39405f3653cc5bf0dcba4194298 +a1f4da396f2eec8a9b3252ea0e2d4ca205f7e003695621ae5571f62f5708d51ca3494ac09c824fca4f4d287a18beea9a +a036fa15e929abed7aac95aa2718e9f912f31e3defd224e5ed379bf6e1b43a3ad75b4b41208c43d7b2c55e8a6fedca72 +80e8372d8a2979ee90afbdb842624ace72ab3803542365a9d1a778219d47f6b01531185f5a573db72213ab69e3ffa318 +af68b5cdc39e5c4587e491b2e858a728d79ae7e5817a93b1ea39d34aec23dea452687046c8feae4714def4d0ed71da16 +b36658dfb756e7e9eec175918d3fe1f45b398679f296119cd53be6c6792d765ef5c7d5afadc5f3886e3f165042f4667f +ad831da03b759716f51099d7c046c1a8e7bf8bb45a52d2f2bfd769e171c8c6871741ef8474f06e2aca6d2b141cf2971f +8bae1202dde053c2f59efc1b05cb8268ba9876e4bd3ff1140fa0cc5fa290b13529aede965f5efdff3f72e1a579efc9cc +86344afbc9fe077021558e43d2a032fcc83b328f72948dba1a074bb1058e8a8faec85b1c019fc9836f0d11d2585d69c8 +831d1fc7aa28f069585d84c46bdc030d6cb12440cfaae28098365577fc911c4b8f566d88f80f3a3381be2ec8088bf119 +899de139797ac1c8f0135f0656f04ad4f9b0fa2c83a264d320eb855a3c0b9a4907fc3dc01521d33c07b5531e6a997064 +855bc752146d3e5b8ba7f382b198d7dc65321b93cdfc76250eabc28dba5bbf0ad1be8ccda1adf2024125107cb52c6a6e +af0aeccab48eb35f8986cabf07253c5b876dd103933e1eee0d99dc0105936236b2a6c413228490ed3db4fa69aab51a80 +ae62e9d706fbf535319c909855909b3deba3e06eaf560803fa37bce3b5aab5ea6329f7609fea84298b9da48977c00c3b +823a8d222e8282d653082d55a9508d9eaf9703ce54d0ab7e2b3c661af745a8b6571647ec5bd3809ae6dddae96a220ea7 +a4c87e0ea142fc287092bc994e013c85e884bc7c2dde771df30ca887a07f955325c387b548de3caa9efa97106da8176a +b55d925e2f614f2495651502cf4c3f17f055041fa305bb20195146d896b7b542b1e45d37fa709ca4bfc6b0d49756af92 +b0ebe8947f8c68dc381d7bd460995340efcbb4a2b89f17077f5fde3a9e76aef4a9a430d1f85b2274993afc0f17fdbead +8baaa640d654e2652808afd68772f6489df7cad37b7455b9cd9456bdddae80555a3f84b68906cc04185b8462273dcfc9 +add9aa08f827e7dc292ac80e374c593cd40ac5e34ad4391708b3db2fe89550f293181ea11b5c0a341b5e3f7813512739 +909e31846576c6bdd2c162f0f29eea819b6125098452caad42451491a7cde9fd257689858f815131194200bca54511f4 +abc4b34098db10d71ce7297658ef03edfa7377bd7ed36b2ffbab437f8fd47a60e2bcfbc93ff74c85cfce74ca9f93106c +857dbecc5879c1b952f847139484ef207cecf80a3d879849080758ef7ac96acfe16a11afffb42daf160dc4b324279d9b +aab0b49beecbcf3af7c08fbf38a6601c21061bed7c8875d6e3c2b557ecb47fd93e2114a3b09b522a114562467fcd2f7d +94306dec35e7b93d43ed7f89468b15d3ce7d7723f5179cacc8781f0cf500f66f8c9f4e196607fd14d56257d7df7bf332 +9201784d571da4a96ef5b8764f776a0b86615500d74ec72bc89e49d1e63a3763b867deca07964e2f3914e576e2ca0ded +aabe1260a638112f4280d3bdea3c84ce3c158b81266d5df480be02942cecf3de1ac1284b9964c93d2db33f3555373dcc +8ef28607ca2e0075aa07de9af5a0f2d0a97f554897cab8827dfe3623a5e9d007d92755d114b7c390d29e988b40466db9 +87a9b1b097c3a7b5055cd9cb0c35ba6251c50e21c74f6a0bca1e87e6463efc38385d3acc9d839b4698dfa2eb4cb7a2ef +aee277e90d2ffce9c090295c575e7cd3bafc214d1b5794dd145e6d02d987a015cb807bd89fd6268cd4c59350e7907ee2 +836ad3c9324eaa5e022e9835ff1418c8644a8f4cd8e4378bd4b7be5632b616bb6f6c53399752b96d77472f99ece123cd +8ffffdb67faa5f56887c834f9d489bb5b4dab613b72eac8abf7e4bcb799ccd0dbd88a2e73077cadf7e761cb159fb5ec5 +9158f6cd4f5e88e6cdb700fddcbc5a99b2d31a7a1b37dce704bd9dd3385cca69607a615483350a2b1153345526c8e05d +a7ff0958e9f0ccff76742fc6b60d2dd91c552e408c84172c3a736f64acb133633540b2b7f33bc7970220b35ce787cd4e +8f196938892e2a79f23403e1b1fb4687a62e3a951f69a7874ec0081909eb4627973a7a983f741c65438aff004f03ba6f +97e3c1981c5cdb0a388f1e4d50b9b5b5f3b86d83417831c27b143698b432bb5dba3f2e590d6d211931ed0f3d80780e77 +903a53430b87a7280d37816946245db03a49e38a789f866fe00469b7613ee7a22d455fb271d42825957282c8a4e159d9 +b78955f686254c3994f610e49f1c089717f5fb030da4f9b66e9a7f82d72381ba77e230764ab593335ff29a1874848a09 +938b6d04356b9d7c8c56be93b0049d0d0c61745af7790edf4ef04e64de2b4740b038069c95be5c91a0ba6a1bb38512a9 +a769073b9648fe21bc66893a9ef3b8848d06f4068805a43f1c180fdd0d37c176b4546f8e5e450f7b09223c2f735b006f +863c30ebe92427cdd7e72d758f2c645ab422e51ecef6c402eb1a073fd7f715017cd58a2ad1afe7edccdf4ff01309e306 +a617b0213d161964eccfc68a7ad00a3ee4365223b479576e887c41ef658f846f69edf928bd8da8785b6e9887031f6a57 +a699834bf3b20d345082f13f360c5f8a86499e498e459b9e65b5a56ae8a65a9fcb5c1f93c949391b4795ef214c952e08 +9921f1da00130f22e38908dd2e44c5f662ead6c4526ebb50011bc2f2819e8e3fca64c9428b5106fa8924db76b7651f35 +98da928be52eb5b0287912fd1c648f8bbda00f5fd0289baf161b5a7dbda685db6ad6bdc121bc9ffa7ed6ae03a13dbee3 +927b91d95676ff3c99de1312c20f19251e21878bfb47ad9f19c9791bc7fb9d6f5c03e3e61575c0760180d3445be86125 +b8e4977a892100635310dfcb46d8b74931ac59ae687b06469b3cee060888a3b6b52d89de54e173d9e1641234754b32b1 +98f6fd5f81ca6e2184abd7a3a59b764d4953d408cec155b4e5cf87cd1f6245d8bdd58b52e1e024e22903e85ae15273f1 +909aaacbbfe30950cf7587faa190dc36c05e3c8131749cc21a0c92dc4afc4002275762ca7f66f91aa751b630ad3e324d +91712141592758f0e43398c075aaa7180f245189e5308e6605a6305d01886d2b22d144976b30460d8ce17312bb819e8f +947d85cb299b189f9116431f1c5449f0f8c3f1a70061aa9ebf962aa159ab76ee2e39b4706365d44a5dbf43120a0ac255 +b39eced3e9a2e293e04d236976e7ee11e2471fe59b43e7b6dd32ab74f51a3d372afee70be1d90af017452ec635574e0e +8a4ba456491911fc17e1cadcbb3020500587c5b42cf6b538d1cb907f04c65c168add71275fbf21d3875e731404f3f529 +8f6858752363e2a94c295e0448078e9144bf033ccd4d74f4f6b95d582f3a7638b6d3f921e2d89fcd6afd878b12977a9d +b7f349aa3e8feb844a56a42f82b6b00f2bfe42cab19f5a68579a6e8a57f5cf93e3cdb56cbbb9163ab4d6b599d6c0f6aa +a4a24dc618a6b4a0857fb96338ac3e10b19336efc26986e801434c8fdde42ca8777420722f45dfe7b67b9ed9d7ce8fb1 +aafe4d415f939e0730512fc2e61e37d65c32e435991fb95fb73017493014e3f8278cd0d213379d2330b06902f21fe4e1 +845cc6f0f0a41cc6a010d5cb938c0ef8183ff5ed623b70f7ea65a8bdbc7b512ea33c0ee8b8f31fdf5f39ec88953f0c1e +811173b4dd89d761c0bdffe224cd664ef303c4647e6cf5ef0ed665d843ed556b04882c2a4adfc77709e40af1cfdea40b +93ba1db7c20bfba22da123b6813cb38c12933b680902cef3037f01f03ab003f76260acc12e01e364c0d0cf8d45fca694 +b41694db978b2cf0f4d2aa06fcfc4182d65fb7c9b5e909650705f779b28e47672c47707d0e5308cd680c5746c37e1bc7 +a0e92c4c5be56a4ccf1f94d289e453a5f80e172fc90786e5b03c1c14ce2f3c392c349f76e48a7df02c8ae535326ea8fe +96cbeb1d0693f4f0b0b71ad30def5ccc7ad9ebe58dbe9d3b077f2ac16256cde10468875e4866d63e88ce82751aaf8ef6 +935b87fd336f0bf366046e10f7c2f7c2a2148fa6f53af5607ad66f91f850894527ecec7d23d81118d3b2ee23351ed6ed +b7c2c1fa6295735f6b31510777b597bc8a7bfb014e71b4d1b5859be0d8d64f62a1587caafc669dfe865b365eb27bd94f +b25d93af43d8704ffd53b1e5c16953fd45e57a9a4b7acfcfa6dd4bf30ee2a8e98d2a76f3c8eba8dc7d08d9012b9694c6 +b5a005cd9f891e33882f5884f6662479d5190b7e2aec1aa5a6d15a8cb60c9c983d1e7928e25e4cf43ec804eaea1d97b0 +93f9f0725a06e4a0fb83892102b7375cf5438b5ebc9e7be5a655f3478d18706cf7dbb1cd1adcee7444c575516378aa1b +900d7cbf43fd6ac64961287fe593c08446874bfc1eb09231fc93de858ac7a8bca496c9c457bced5881f7bf245b6789e0 +90c198526b8b265d75160ef3ed787988e7632d5f3330e8c322b8faf2ac51eef6f0ce5a45f3b3a890b90aecf1244a3436 +b499707399009f9fe7617d8e73939cb1560037ad59ac9f343041201d7cc25379df250219fd73fa012b9ade0b04e92efa +94415f6c3a0705a9be6a414be19d478181d82752b9af760dda0dbd24a8ff0f873c4d89e61ad2c13ebf01de55892d07fa +90a9f0b9f1edb87751c696d390e5f253586aae6ebfc31eb3b2125d23877a497b4aa778de8b11ec85efe49969021eaa5a +a9942c56506e5cd8f9289be8205823b403a2ea233ba211cf72c2b3827064fd34cd9b61ff698a4158e7379891ca4120d8 +83bb2ee8c07be1ab3a488ec06b0c85e10b83a531758a2a6741c17a3ccfa6774b34336926a50e11c8543d30b56a6ac570 +8a08a3e5ebe10353e0b7fff5f887e7e25d09bb65becf7c74a03c60c166132efaada27e5aea242c8b9f43b472561ae3ed +957c7a24cefaa631fe8a28446bc44b09a3d8274591ade53ba489757b854db54820d98df47c8a0fbee0e094f8ad7a5dc4 +b63556e1f47ed3ee283777ed46b69be8585d5930960d973f8a5a43508fc56000009605662224daec2de54ea52a8dcd82 +abed2b3d16641f0f459113b105f884886d171519b1229758f846a488c7a474a718857323c3e239faa222c1ab24513766 +882d36eed6756d86335de2f7b13d753f91c0a4d42ef50e30195cc3e5e4f1441afa5ff863022434acb66854eda5de8715 +a65ea7f8745bb8a623b44e43f19158fd96e7d6b0a5406290f2c1348fc8674fbfc27beb4f724cc2b217c6042cb82bc178 +a038116a0c76af090a069ca289eb2c3a615b96093efacfe68ea1610890b291a274e26b445d34f414cfec00c333906148 +90294f452f8b80b0a47c3bcb6e30bdd6854e3b01deaf93f5e82a1889a4a1036d17ecb59b48efa7dc41412168d7a523dd +88faf969c8978a756f48c6114f7f33a1ca3fd7b5865c688aa9cd32578b1f7ba7c06120502f8dc9aee174ecd41597f055 +8883763b2762dfff0d9be9ac19428d9fd00357ac8b805efda213993152b9b7eb7ba3b1b2623015d60778bffda07a724d +a30a1a5a9213636aa9b0f8623345dc7cf5c563b906e11cc4feb97d530a1480f23211073dcb81105b55193dcde5a381d2 +b45ee93c58139a5f6be82572d6e14e937ef9fcbb6154a2d77cb4bf2e4b63c5aabc3277527ecf4e531fe3c58f521cc5e3 +ac5a73e4f686978e06131a333f089932adda6c7614217fcaf0e9423b96e16fd73e913e5e40bf8d7800bed4318b48d4b1 +b6c1e6cdd14a48a7fe27cd370d2e3f7a52a91f3e8d80fb405f142391479f6c6f31aa5c59a4a0fdc9e88247c42688e0cf +ab1760530312380152d05c650826a16c26223960fc8e3bf813161d129c01bac77583eff04ce8678ff52987a69886526b +a4252dffae7429d4f81dfaeeecc48ab922e60d6a50986cf063964f282e47407b7e9c64cf819da6f93735de000a70f0b2 +94c19f96d5ecf4a15c9c5a24598802d2d21acbbd9ee8780b1bc234b794b8442437c36badc0a24e8d2cff410e892bb1d2 +89fafe1799cf7b48a9ea24f707d912fccb99a8700d7287c6438a8879f3a3ca3e60a0f66640e31744722624139ba30396 +b0108405df25cf421c2f1873b20b28552f4d5d1b4a0bf1c202307673927931cbd59f5781e6b8748ddb1206a5ec332c0b +aa0f0e7d09f12b48f1e44d55ec3904aa5707e263774126e0b30f912e2f83df9eb933ca073752e6b86876adaf822d14ba +b0cbe8abb58876d055c8150d9fdbde4fea881a517a2499e7c2ea4d55c518a3c2d00b3494f6a8fd1a660bfca102f86d2a +b1ef80ec903bac55f58b75933dc00f1751060690fd9dfb54cf448a7a4b779c2a80391f5fda65609274bd9e0d83f36141 +8b52e05b1845498c4879bb12816097be7fc268ce1cf747f83a479c8e08a44159fc7b244cf24d55aca06dccf0b97d11e1 +b632a2fc4fdb178687e983a2876ae23587fd5b7b5e0bb8c0eb4cfe6d921a2c99894762e2aaccdc5da6c48da3c3c72f6c +953ef80ab5f74274ae70667e41363ae6e2e98ccbd6b7d21f7283f0c1cafb120338b7a8b64e7c189d935a4e5b87651587 +b929cfd311017c9731eed9d08d073f6cf7e9d4cd560cddd3fdcb1149ab20c6610a7674a66a3616785b13500f8f43ee86 +870fb0d02704b6a328e68721fb6a4b0f8647681bfcb0d92ec3e241e94b7a53aecc365ed384e721c747b13fbf251002f1 +979501159833a8ba5422ed9b86f87b5961711f5b474d8b0e891373fe2d0b98ff41a3a7a74a8b154615bb412b662a48be +b20f9c13cdeceef67f877b3878839ef425f645b16a69c785fe38f687c87a03b9de9ae31ac2edb1e1dd3a9f2c0f09d35d +8c7705ed93290731b1cf6f3bf87fc4d7159bb2c039d1a9f2246cda462d9cdf2beef62d9f658cfeea2e6aef7869a6fc00 +aa439eb15705ad729b9163daee2598d98a32a8a412777c0d12fd48dc7796d422227a014705e445cc9d66f115c96bbc24 +a32307e16f89749fe98b5df1effef0429801c067e0d8067794e56b01c4fef742ad5e7ab42a1a4cc4741808f47a0b7cb8 +b31e65c549003c1207258a2912a72f5bad9844e18f16b0773ea7af8ff124390eb33b2f715910fc156c104572d4866b91 +85608d918ed7b08a0dc03aee60ea5589713304d85eee7b4c8c762b6b34c9355d9d2e192575af0fd523318ae36e19ae1c +a6497dbaf0e7035160b7a787150971b19cf5ba272c235b0113542288611ebecefa2b22f08008d3f17db6a70a542c258d +87862adb1ac0510614ab909457c49f9ec86dc8bdf0e4682f76d2739df11f6ffcfb59975527f279e890d22964a1fba9b6 +8717ac3b483b3094c3b642f3fafe4fbafc52a5d4f2f5d43c29d9cfe02a569daee34c178ee081144494f3a2ca6e67d7b1 +855100ac1ec85c8b437fdd844abaa0ca4ac9830a5bdd065b68dafb37046fcf8625dd482dc0253476926e80a4c438c9ec +ae74821bf265ca3c8702c557cf9ef0732ede7ef6ed658283af669d19c6f6b6055aca807cf2fa1a64785ec91c42b18ae5 +812a745b1419a306f7f20429103d6813cbdea68f82ff635ac59da08630cd61bda6e0fa9a3735bfd4378f58ad179c1332 +867dbbfe0d698f89451c37ca6d0585fd71ee07c3817e362ef6779b7b1d70b27c989cdd5f85ac33a0498db1c4d14521fe +84db735d3eb4ff7f16502dccc3b604338c3a4a301220ad495991d6f507659db4b9f81bba9c528c5a6114bcdba0160252 +aadc83d1c4e5e32bf786cfb26f2f12a78c8024f1f5271427b086370cdef7a71d8a5bf7cd7690bae40df56c38b1ad2411 +a27860eb0caaea37298095507f54f7729d8930ac1929de3b7a968df9737f4c6da3173bda9d64ff797ed4c6f3a1718092 +a3cdcaa74235c0440a34171506ed03d1f72b150d55904ce60ec7b90fcd9a6f46f0e45feab0f9166708b533836686d909 +b209a30bdac5c62e95924928f9d0d0b4113ebb8b346d7f3a572c024821af7f036222a3bd38bd8efd2ee1dbf9ac9556cd +83c93987eff8bc56506e7275b6bef0946672621ded641d09b28266657db08f75846dcbde80d8abc9470e1b24db4ca65b +800c09b3ee5d0251bdaef4a82a7fe8173de997cc1603a2e8df020dd688a0c368ad1ebef016b35136db63e774b266c74c +93fb52de00d9f799a9bce3e3e31aaf49e0a4fc865473feb728217bd70f1bc8a732ec37ac3582bf30ab60e8c7fdf3cb8d +a1aff6b4a50d02f079a8895c74443539231bfdf474600910febf52c9151da7b31127242334ac63f3093e83a047769146 +8c4532d8e3abb5f0da851138bfa97599039bcd240d87bbdf4fd6553b2329abb4781074b63caf09bc724ceb4d36cb3952 +8bd9b0ae3da5acda9eb3881172d308b03beec55014cd73b15026299541c42fd38bab4983a85c06894ebb7a2af2a23d4c +979441e7f5a0e6006812f21b0d236c5f505bb30f7d023cb4eb84ec2aa54a33ac91d87ece704b8069259d237f40901356 +a1c6d2d82e89957d6a3e9fef48deb112eb00519732d66d55aa0f8161e19a01e83b9f7c42ac2b94f337dcc9865f0da837 +97a0b8e04e889d18947d5bf77d06c25bbd62b19ce4be36aaa90ddbeafd93a07353308194199ba138efaadf1b928cd8d2 +822f7fbe9d966b8ec3db0fc8169ab39334e91bf027e35b8cc7e1fe3ead894d8982505c092f15ddfe5d8f726b360ac058 +a6e517eedd216949e3a10bf12c8c8ddbfde43cddcd2c0950565360a38444459191bdbc6c0af0e2e6e98bc6a813601c6d +858b5f15c46c074adb879b6ba5520966549420cb58721273119f1f8bc335605aeb4aa6dbe64aae9e573ca7cc1c705cdc +b5191bb105b60deb10466d8114d48fb95c4d72036164dd35939976e41406dff3ee3974c49f00391abfad51b695b3258c +b1b375353ed33c734f4a366d4afad77168c4809aff1b972a078fd2257036fd6b7a7edad569533abf71bc141144a14d62 +a94c502a9cdd38c0a0e0187de1637178ad4fa0763887f97cc5bdd55cb6a840cb68a60d7dbb7e4e0e51231f7d92addcff +8fe2082c1b410486a3e24481ae0630f28eb5b488e0bb2546af3492a3d9318c0d4c52db1407e8b9b1d1f23a7ffbaf260a +b73fe7aa2b73f9cae6001af589bf8a9e73ea2bb3bb01b46743e39390c08d8e1be5e85a3d562857a9c9b802b780c78e6d +8e347f51330ae62275441ccd60f5ac14e1a925a54ced8a51893d956acc26914df1bb8595385d240aa9b0e5ada7b520ea +8dc573d6357c0113b026a0191a5807dbe42dcd2e19772d14b2ca735e1e67c70e319ef571db1f2a20e62254ed7fb5bcd6 +a5dacbe51549fe412e64af100b8b5eba5ec2258cc2a7c27a34bc10177d1894baf8707886d2f2ef438f077596a07681e9 +8349153c64961d637a5ff56f49003cb24106de19a5bbcf674016a466bfbe0877f5d1e74ccb7c2920665ef90a437b1b7e +96ad35429d40a262fdc8f34b379f2e05a411057d7852c3d77b9c6c01359421c71ef8620f23854e0f5d231a1d037e3a0d +b52385e40af0ed16e31c2154d73d1517e10a01435489fc801fbea65b92b3866ab46dab38d2c25e5fb603b029ae727317 +8e801c7a3e8fa91d9c22ebd3e14a999023a7b5beea13ec0456f7845425d28c92452922ca35ec64012276acb3bbc93515 +a8630870297d415e9b709c7f42aa4a32210b602f03a3015410123f0988aea2688d8bcfc6d07dc3602884abbf6199b23f +8cd518392e09df2a3771a736f72c05af60efc030d62dbbb9cd68dc6cbbe1fb0854eb78b6ed38337010eb1bb44a5d5d30 +921aa4c66590f6c54bf2fa2b324f08cbe866329cc31f6e3477f97f73e1a1721d5eb50ed4eacc38051fe9eda76ba17632 +a37e595cb63524cb033c5540b6343c3a292569fc115e813979f63fe1a3c384b554cecc2cae76b510b640fe3a18800c81 +b0bb57e4e31ae3ce9f28cef158ed52dabfad5aa612f5fcc75b3f7f344b7cec56b989b5690dacd294e49c922d550ee36b +a3c618ce4d091e768c7295d37e3f9b11c44c37507ae1f89867441f564bf0108f67bf64b4cf45d73c2afc17a4dc8b2c68 +999e6650eda5455e474c22a8c7a3fd5b547ec2875dc3043077ad70c332f1ccd02135e7b524fcbf3621d386dec9e614fa +b018f080888dec3c2ca7fcfeb0d3d9984699b8435d8823079fc9e1af4ca44e257fbe8da2f6f641ee6152b5c7110e3e3c +a2bcd4bcd9b40c341e9bba76b86481842f408166c9a7159205726f0776dcb7f15a033079e7589699e9e94ce24b2a77fd +b03de48f024a520bb9c54985ca356fd087ca35ac1dd6e95168694d9dae653138c9755e18d5981946a080e32004e238fe +a6c1a54973c0c32a410092441e20594aa9aa3700513ed90c8854956e98894552944b0b7ee9edf6e62e487dc4565baa2f +845d7abf577c27c4c1fafc955dcad99a1f2b84b2c978cfe4bd3cd2a6185979491f3f3b0ec693818739ed9184aba52654 +9531bcfc0d3fcd4d7459484d15607d6e6181cee440ba6344b12a21daa62ff1153a4e9a0b5c3c33d373a0a56a7ad18025 +a0bbf49b2dd581be423a23e8939528ceaae7fb8c04b362066fe7d754ca2546304a2a90e6ac25cdf6396bf0096fae9781 +a1ec264c352e34ed2bf49681b4e294ffea7d763846be62b96b234d9a28905cdece4be310a56ec6a00fc0361d615b547c +87c575e85b5dfbfd215432cb355a86f69256fff5318e8fda457763ac513b53baa90499dc37574bdfad96b117f71cb45e +9972edfdeec56897bef4123385ee643a1b9dc24e522752b5a197ce6bd2e53d4b6b782b9d529ca50592ee65b60e4c9c3c +b8bcf8d4ab6ad37bdd6ad9913a1ba0aba160cb83d1d6f33a8524064a27ba74a33984cc64beeee9d834393c2636ff831a +83082b7ec5b224422d0ff036fbb89dc68918e6fde4077dfc0b8e2ee02595195ecadb60c9ab0ad69deb1bac9be75024fa +8b061fce6df6a0e5c486fd8d8809f6f3c93bd3378a537ff844970492384fb769d3845d0805edd7f0fcd19efabf32f197 +b9597e717bb53e6afae2278dbc45d98959c7a10c87c1001ed317414803b5f707f3c559be6784119d08f0c06547ec60b1 +b9d990fd7677dd80300714cfd09336e7748bbf26f4bb0597406fcb756d8828c33695743d7a3e3bd6ddf4f508149610ef +b45f7d2b00ceea3bf6131b230b5b401e13a6c63ba8d583a4795701226bf9eb5c88506f4a93219ac90ccbceef0bfd9d49 +a8ccaa13ca7986bc34e4a4f5e477b11ae91abb45c8f8bf44a1f5e839289681495aba3daa8fb987e321d439bbf00be789 +ae0f59f7a94288a0ead9a398fdd088c2f16cccb68624de4e77b70616a17ddf7406ca9dc88769dadeb5673ff9346d6006 +b28e965dcc08c07112ae3817e98f8d8b103a279ad7e1b7c3de59d9dbd14ab5a3e3266775a5b8bbf0868a14ae4ab110f1 +84751c1a945a6db3df997fcbde9d4fe824bc7ba51aa6cb572bb5a8f9561bef144c952198a783b0b5e06f9dd8aa421be8 +a83586db6d90ef7b4fa1cbda1de1df68ee0019f9328aded59b884329b616d888f300abb90e4964021334d6afdea058fd +8fcea1ce0abf212a56c145f0b8d47376730611e012b443b3d1563498299f55cbcbe8cbd02f10b78224818bb8cbbd9aaa +8d66c30a40c34f23bae0ea0999754d19c0eb84c6c0aa1b2cf7b0740a96f55dd44b8fee82b625e2dd6c3182c021340ac6 +92c9b35076e2998f1a0f720d5a507a602bd6bd9d44ffc29ede964044b17c710d24ce3c0b4a53c12195de93278f9ec83b +a37d213913aff0b792ee93da5d7e876f211e10a027883326d582ad7c41deebdfce52f86b57d07868918585908ebd070a +a03995b4c6863f80dd02ed0169b4f1609dc48174ec736de78be1cdff386648426d031f6d81d1d2a7f2c683b31e7628c0 +b08b628d481302aa68daf0fa31fd909064380d62d8ed23a49037cb38569058e4c16c80e600e84828d37a89a33c323d1f +a0ee2e2dd8e27661d7b607c61ac36f590909aa97f80bdfd5b42463ca147b610ac31a9f173cbecdd2260f0f9ea9e56033 +967162fba8b69ffce9679aac49214debb691c6d9f604effd6493ce551abacbe4c8cc2b0ccee6c9927c3d3cfbdcb0be11 +8deab0c5ed531ce99dadb98b8d37b3ff017f07438bc6d50840577f0f3b56be3e801181333b4e8a070135f9d82872b7f2 +b1bfa00ec8c9365b3d5b4d77a718cb3a66ed6b6cf1f5cf5c5565d3aa20f63d3c06bb13d47d2524e159debf81325ba623 +90109780e53aeacd540b9fe9fc9b88e83c73eaf3507e2b76edc67f97a656c06a8a9e1ec5bce58bfd98b59a6b9f81b89d +88a1009a39a40421fdcc0ffc3c78a4fbace96a4e53420b111218091223494e780a998ebecf5a0abd0243e1523df90b28 +90b77146711ee8d91b0346de40eca2823f4e4671a12dad486a8ec104c01ef5ee7ab9bd0398f35b02b8cb62917455f8b3 +b262c5e25f24ae7e0e321b66fdb73b3bf562ded566a2d6a0152cf8bafb56138d87b6a917a82f5ace65efc73cfc177d81 +ae65a438c7ea46c82925b5ec5f71314558ca5146f5d90311431d363cfeac0537223c02cbb50fa6535d72fc2d949f4482 +8984208bfc193a6ef4720cc9d40c17f4be2f14595ef887980f2e61fa6927f9d73c00220937013b46290963116cbe66ac +a8f33a580508f667fac866456dce5d9246562188ad0f568eb1a2f28cf9fd3452dd20dc613adb1d07a5542319a37ecf1a +aedadd705fc086d8d2b647c62e209e2d499624ab37c8b19af80229f85e64a6e608d9cd414cb95ae38cf147d80ec3f894 +ae28077a235cd959f37dc3daedc3706f7a7c2ffe324e695f2e65f454bf5a9fc27b10149a6268ebfaa961ad67bb9b75d7 +a234c7f5a5e0e30f2026d62657bd92d91a9907ec6a2177f91383f86abb919778121ff78afb8f52c473fe6fb731018b52 +816a2ea7826b778f559a815267b6c6eb588558391c0a675d61bb19470d87489ba6c1e2486ea81dd5420a42ee7c35a8de +9218b61948c14234f549c438105ae98367ef6b727ad185f17ad69a6965c044bb857c585b84d72ef4c5fb46962974eed7 +a628031217a0b1330b497351758cf72d90fb87d8bdf542ea32092e14ff32d5ef4ca700653794bb78514d4b0edfd7a8d7 +ab4e977141be639a78eb9ed17366f9642f9335873aca87cce2bae0dddc161621d0e23264a54a7395ae706d748c690ee9 +b1538c4edff59bcf5668557d994bac77d508c757e382512c4368c1ded4242a41f6200b73fe8809fb528a7a0c1fc96feb +965caabe5590e2ff8c9f1048bbdda2817e7a2847e287944bfab40d94cb48389441ac42ff3a7b559760bfab42ff82e1e0 +a64b7484d22c4b8047c7a8ef54dc88cb8d110c61ef28ba853821b61e87d318b2b4226f7f0d1f3cdf086a0e1666d0212c +8915ab7e41d974eef9a651b01c2521392e8899e6ab91c22aeee61605c78fb2b052399ba1d03473aa9cfb52d1a8ba4257 +8dd26875d4a1716db2f75a621d01e971983267770e2da92399aecf08f74af1f7e73643ac6f0a9b610eda54e5460f70ed +83dabcb84c9cbce67e1a24ecbfa4473766b9519588b22288edbaa29aca34cefd9884f7310e7771f8f7a7cbced2e7eea0 +956be00c67987fb4971afca261065a7f6fcef9fb6b1fcb1939f664bbc5b704223253ebfda48565624a68fb249742c2cf +a374824a24db1ab298bee759cee8d8260e0ac92cd1c196f896600fd57484a9f9be1912ded01203976ac4fab66c0e5091 +a225f2ed0de4e06c500876e68e0c58be49535885378584a1442aae2140c38d3ca35c1bc41936a3baf8a78e7ab516f790 +8e79c8de591a6c70e2ef2de35971888ab0ca6fd926fdb6e845fb4b63eb3831c5839f084201b951984f6d66a214b946b8 +91babc849a9e67ab40192342c3d0d6ce58798101cb85c9bd7fc0ac4509ffc17b5ea19e58045cf1ca09ec0dee0e18c8f9 +8b4897fc2aef5bbe0fa3c3015ca09fc9414fdb2315f54dbecc03b9ae3099be6c0767b636b007a804d8b248c56e670713 +8f63ba42e7459ea191a8ad18de0b90b151d5acbf4751e2c790e7d8328e82c20de518132d6290ff3c23d2601f21c1558e +a1a035dc9b936587a16665ea25646d0bb2322f81960d9b6468c3234c9137f7c2b1e4f0b9dbe59e290a418007b0e7a138 +81c4904c08f7bb2ac7b6d4ac4577f10dd98c318f35aac92fc31bab05eceb80a0556a7fc82614b8d95357af8a9c85a829 +8c40e44e5e8e65f61e0a01f79057e1cb29966cc5074de790ea9c60454b25d7ea2b04c3e5decb9f27f02a7f3d3cb7014f +ad8709e357094076eb1eb601539b7bcc37247a25fbc6ada5f74bb88b1b371917c2a733522190f076c44e9b8e2ae127fb +92d43cd82c943fd71b8700977244436c696df808c34d4633f0624700a3445f3ecc15b426c850f9fb60b9aa4708f2c7c0 +b2cb8080697d1524a6dcb640b25e7255ae2e560613dbd27beaa8c5fc5c8d2524b7e6edd6db7ad0bb8a4e2e2735d4a6f7 +971ca6393d9e312bfb5c33955f0325f34946d341ff7077151f0bcafd2e6cbd23e2ad62979454f107edc6a756a443e888 +b6a563f42866afcee0df6c6c2961c800c851aa962d04543541a3cedeb3a6a2a608c1d8391cf405428cd40254e59138f3 +986bd17bad9a8596f372a0185f7f9e0fb8de587cd078ae40f3cd1048305ba00954aff886b18d0d04640b718ea1f0d5a3 +ae32dbccfb7be8e9165f4e663b26f57c407f96750e0f3a5e8e27a7c0ca36bc89e925f64ddd116263be90ace4a27872c4 +83725445ec8916c7c2dd46899241a03cf23568ac63ae2d34de3bce6d2db0bc1cfd00055d850b644a059fb26c62ed3585 +a83f7e61c05b1c6797a36ad5ded01bf857a838147f088d33eb19a5f7652b88e55734e8e884d1d1103a50d4393dfcd7a8 +aa010b4ec76260d88855347df9eaf036911d5d178302063d6fd7ecad009e353162177f92240fe5a239acd1704d188a9d +a88f4ba3cf4aff68ec1e3ded24622d4f1b9812350f6670d2909ea59928eb1d2e8d66935634d218aeac6d1a0fc6cae893 +b819112b310b8372be40b2752c6f08426ef154b53ef2814ae7d67d58586d7023ffa29d6427a044a3b288e0c779866791 +b5d1e728de5daf68e63b0bb1dee5275edae203e53614edeeeefff0f2f7ac4281191a33b7811de83b7f68111361ef42e1 +953fb3ddc6f78045e53eaacfd83c5c769d32608b29391e05612e4e75725e54e82ad4960fbef96da8b2f35ba862968a3e +936471136fb2c1b3bb986a5207a225a8bf3b206a1a9db54dc3029e408e78c95bfb7539b67006d269c09df6354d7254ac +ac353364b413cae799b13d7dc6fa09c322b47e60b9333e06499155e22d913929b92a45a0ad04ba90b29358f7b792d864 +a0177419ead02ba3f0755a32eee3fd23ec81a13c01eab462f3b0af1e2dba42f81b47b2c8b1a90d8cec5a0afa371b7f11 +b009eeb5db80d4244c130e6e3280af120917bb6fcebac73255c09f3f0c9da3b2aa718cd92d3d40e6b50737dbd23461aa +b8a43426c3746c1a5445535338c6a10b65474b684a2c81cd2f4b8ebecc91a57e2e0687df4a40add015cd12e351bbb3eb +94ff3698a6ac6e7df222675a00279c0ea42925dc6b748e3e74a62ea5d1e3fd70d5ab2d0c20b83704d389dd3a6063cf1a +90e4142e7ce15266144153e21b9893d3e14b3b4d980e5c87ce615ecd27efac87d86fa90354307857f75d7ebaeffe79ef +a5fd82c3f509ec9a36d72ba204a16f905e1e329f75cfd18aaa14fb00a212d21f3fac17e1a8e3bc5691ab0d07f8ec3cd0 +962e6bfd75ea554f304a5fee1123e5bf2e048ccd3b401716b34c52740384579188ac98bc0d91269fc814de23f4b2dd34 +b50b4e45c180badf9cd842cd769f78f963e077a9a4c016098dc19b18210580ad271ae1ba86de7760dd2e1f299c13f6a0 +84cf08858d08eca6acc86158ffda3fbe920d1d5c04ac6f1fc677760e46e66599df697397373959acf319c31e47db115c +a697a38ba21caa66b7739ed0e74fe762a3da02144b67971fcad28c1132d7b83e0ac062cc71479f99e2219086d7d23374 +ad1f6d01dd7f0de814fe5fbb6f08c1190ff37f4a50754d7b6291fc547c0820506ea629aabacf749fec9c1bbfda22d2d0 +b11fd7f8c120d8a370a223a1adc053a31bef7454b5522b848dec82de5482308fc68fdaf479875b7a4bc3fc94e1ea30eb +93ecf90ebfc190f30086bcaeee18cda972073a8469cf42a3b19f8c1ec5419dff2d6a5cc8ef412ccd9725b0f0a5f38f88 +911f25aaa5260b56b3009fa5e1346a29f13a085cf8a61b36b2d851791f7bcf8456840eccbfc23797b63ecd312e2d5e12 +a52f17a8b2db66c98291020b1db44ab23827e1790e418e078d1316185df6aa9f78292f43a12cd47131bd4b521d134060 +9646fca10bf7401e91d9a49753c72f3ecb142f5ed13aba2c510a6c5ccb8d07b8e8d1581fc81321ad5e3996b6d81b5538 +aa1da4a5665b91b62dda7f71bb19c8e3f6f49cc079d94fcd07b3604a74547e8334efa5a202822d0078158056bbda2822 +a2432ae5feeaf38252c28aa491e92a68b47d5b4c6f44c1b3d7f3abc2f10b588f64a23c3357e742a0f5e4f216e7ca5827 +83c7b47735cd0ef80658a387f34f259940096ebb9464c67919b278db4109fea294d09ea01a371b79b332cff6777c116d +a740a2959e86e413c62d6bdd1bc27efe9596ee363c2460535eab89ba1715e808b658bd9581b894b5d5997132b0c9c85c +b76947237fa9d71c3bece0b4f7119d7f94d2162d0ced52f2eac4de92b41da5b72ad332db9f31ebb2df1c02f400a76481 +a20e1f2b7e9cc1443226d2b1a29696f627c83836116d64d2a5559d08b67e7e4efa9a849f5bb93a0dadb62450f5a9eaab +b44bff680fba52443a5b3bd25f69c5640006d544fca1d3dc11482ee8e03b4463aae59d1ec9d200aa6711ce72350580fb +a9490f5643bacec7e5adcda849ab3e7ff1f89026bf7597980b13a09887376f243158d0035e9d24fdee7cb6500e53ef29 +96081010b82c04ad0bfc3605df622db27c10a91494685ef2e6e1839c218b91cbb56e043e9a25c7b18c5ddee7c6769517 +a9522d59bcf887cbbbc130d8de3ff29a86df5d9343a918f5e52c65a28e4c33f6106ac4b48ecd849a33d39eeb2319d85b +aa5e0cea1a1db2283783788b4d77c09829563b75c503c154fdaa2247c9149918edac7737ef58c079e02dca7d8397b0eb +8c03f064e777d0c07c4f04c713a86bf581cc85155afe40e9065ead15139b47a50ead5c87ac032f01b142d63ff849758a +a34d672bf33def02ee7a63e6d6519676c052fa65ca91ed0fe5fdd785c231ba7af19f1e990fc33f5d1d17e75f6af270be +8680443393e8ac45a0b07c30a82ac18e67dcc8f20254bd5ede7bf99fc03e6123f2fcd64c0ca62f69d240f23acd777482 +a4e00ab43d8ae5b13a6190f8ef5395ec17fbac4aa7dfa25b33e81b7e7bf63a4c28910b3a7dc9204dbc4168b08575a75e +8249259066ee5672b422c1889ab5ed620bddd1297f70b4197c40bb736afba05d513b91d3a82ee030336c311d952cd60c +a0651d8cf34fa971bde1ec037158a229e8e9ad4b5ca6c4a41adedb6d306a7772634f703dcfac36f9daf17289f33c23fb +b02ff6e8abff19969e265395ceaf465f43e7f1c3c9cfc91f1748042d9c352b284e49515a58078c877a37ff6915ee8bf4 +927fb7351ac28254458a1a2ea7388e1fbd831fbc2feedb230818f73cc8c505b7ff61e150898ce1567fcb0d2c40881c7b +a9d3861f72090bc61382a81286bb71af93cdeefab9a83b3c59537ad21810104e0e054859eeafa13be10f8027b6fc33b8 +a523306656730b1a31b9a370c45224b08baf45773d62952a0bf7d6c4684898ae78914cfafbd3e21406407cc39e12afdc +947a090e7703a3ea303a4a09b3ab6b6d3fda72912c9f42cc37627557028b4667f5398a6d64b9281fa2efbe16f6c61ed6 +b41d24d40c10239c85d5b9bf1a3886d514a7a06b31ca982ea983e37162293350b12428eabc9f6a460473ad811e61ba40 +b0bb9805724f4ca860e687985c0dc6b8f9017fe71147e5383cfbbbdcb2a42c93c7062ba42acdead9d992b6f48fc1d5ac +aec775aa97a78851893d3c5c209a91267f1daf4205bfb719c44a9ed2614d71854b95bb523cd04a7f818a4a70aa27d8fc +b53e52e32ca90b38987610585ad5b77ecd584bd22c55af7d7c9edf5fbcae9c9241b55200b51eaed0fbdb6f7be356368f +a2c5ac7822c2529f0201717b4922fb30fb037540ab222c97f0cdac341d09ccb1415e7908288fabef60177c0643ed21bf +92162fda0cbd1dafbed9419ae0837e470451403231ee086b49a21d20de2e3eed7ce64382153272b02cf099106688af70 +8452d5df66682396718a76f219a9333a3559231e5f7f109a1f25c1970eb7c3408a5e32a479357f148af63b7a1d352451 +831ea95d4feb520994bc4904017a557797e7ad455a431d94de03b873a57b24b127fcc9ff5b97c255c6c8d8e18c5c7e12 +93d451d5e0885ccdbb113a267c31701e7c3d9e823d735dc9dfd6cfdcd82767012dc71396af53d3bedd2e0d9210acf57f +a2126f75a768dcc7ebddf2452aebf20ad790c844442b78e4027c0b511a054c27efb987550fcab877c46f2c7be4883ae0 +aa4d2dcba2ccfc11a002639c30af6beb35e33745ecbab0627cf0f200fdae580e42d5a8569a9c971044405dfdafed4887 +ab13616069ef71d308e8bf6724e13737dc98b06a8f2d2631284429787d25d43c04b584793256ed358234e7cd9ad37d1f +9115ee0edc9f96a10edcafeb9771c74321106e7f74e48652df96e7ca5592a2f448659939291ff613dd41f42170b600ad +97b10a37243dc897ccc143da8c27e53ccc31f68220bffd344835729942bb5905ae16f71ccaed29ca189432d1c2cc09b1 +875cf9c71ae29c3bde8cdcb9af5c7aca468fbb9243718f2b946e49314221a664959140c1ebc8622e4ed0ba81526302fd +86b193afbb7ff135ce5fc7eb0ee838a22e04806ceec7e02b3fb010e938fff733fc8e3a1d4b6cba970852d6307018b738 +b3403a94f1483edce5d688e5ed4ab67933430ede39cd57e2cddb4b469479018757d37dd2687f7182b202967da12a6c16 +83edfa0a6f77974c4047b03d7930e10251e939624afa2dcafbd35a9523c6bf684e1bb7915fc2e5b3ded3e6dc78daacf2 +88ff3375fe33942e6d534f76ed0f1dfa35ae1d62c97c84e85f884da76092a83ecd08454096c83c3c67fac4cd966673d7 +af0726a2a92ee12a9411db66333c347e1a634c0ab8709cc0eab5043a2f4afac08a7ae3a15ce37f5042548c6764ae4cf6 +81cfa33bb702e2f26169a006af0af0dcaa849cec2faf0f4784a06aa3c232d85a85b8123d49a1555cca7498d65e0317e4 +910a16526176b6e01eb8fb2033ffbb8c9b48be6e65f4c52c582909681805b3d9e1c28e3b421be9b9829b32175b8d4d80 +93d23befa411ca1adbdba726f762f2403e1cc740e44c9af3e895962e4047c2782ca7f2f9878512c37afd5a5a0abbd259 +82fcf316027fedfe235905588b7651b41e703836f96cb7ac313b23b4e6c134bff39cd10b3bddb7458d418d2b9b3c471b +8febc47c5752c513c4e5573428ad0bb40e15a5e12dbfa4c1ef29453f0588f0b75c3591075fef698e5abcf4d50c818a27 +83dab521d58b976dcea1576a8e2808dfaea9fa3e545902d0e0ce184d02dca8245d549134a238ab757950ad8bc11f56eb +898cfb9bf83c1c424eca817e8d0b99f5e482865070167adab0ecf04f3deeb3c71363b9f155c67b84d5e286c28238bef8 +b845e388cc1a8e8b72a24d48219ac4fd7868ee5e30960f7074b27dada842aa206889122acfce9e28512038547b428225 +b1ce4720e07e6eecc2a652f9edbad6bd5d787fbaff2a72a5ca33fa5a054dd3b4d5952563bc6db6d1ce1757a578bba480 +8db6990dd10741cf5de36e47726d76a12ebe2235fdcb8957ab26dba9466e6707d4a795d4e12ec7400d961bd564bdee7e +a3ca7afd20e16c2a45f73fc36357763847ed0be11cb05bfd9722f92c7ba3fa708cf10d4e0ae726c3eccae23cc55fd2be +8701b085c45b36f3afb589207bbf245ef4c5c82aa967ecd0c334daa1f5a54093c5e0fcacd09be540801920f49766aa0f +84e3736727ba76191d9a6a2a3796f55bb3c3a8bbb6e41f58e892ea282c90530b53ab5490bbf1a066723399bb132160fb +87c02a01917333c7b8866f6b717b1e727b279894108f70574d1b6e9e8dc978eda8778342baf3c6464d6e0dd507163e76 +b8da532dac81fafaed759e99c3ae011d75f3fda67a8c420c3b9747281fe32e31ac3c81e539940286440704c2c3e3b53e +a0cc63c3bef75a5c02942977a68a88cd3d103d829b6c0f070f64206da7e3638f10f42452788092de8fbbc626ce17b0d4 +b5c9317b3f6b1d7ee6871506c0430cdf73e28b02c001ba6ca11061c7e121c91152d2b80c4f80e1d8f51ff5653bc0db5b +b798fb572da977dd3ef2dce64042b012a470d6bd2cb61a16267abe2b8399f74540d7c70462a6b2278d73567447e31994 +b868eda58739effda68c834745cd2cf66a09f0f215607b65685bb5ca3eba71150f43a6e47b81a0c19fb58eeae3da56e8 +9041c93a7e8f2c34812fd6e9744b154e898e1ef69db72bf36242c71e2c251f3db7e86cbd802da603a92cd0b06b62ea63 +a834d648e974230582fc17b3a449f4f65b3297038a3a5401e975b9b60ff79b2006a33e1486d3428106580276993311e1 +a3ce874da6ade9f0f854d7ae7651fc3ff63cec748a847527539fe0d67e6c99eaa3011065a4627c2192af7f9569f7ab57 +ae78ad16de150cc0400d3b6b424c608cd2b2d01a7a38ea9c4e504d8463c0af09613774dbefdd5198415b29904e0fbb63 +b966db5a961067e743212d564595ef534e71dcd79b690a5a2c642d787059fc7959b9039b650372461a1f52910f7e857b +8069904f360af3edfd6cabd9b7f2adf5b61bd7feb0e9a040dc15c2a9d20052c3e5e0158f3065ec3200d19b91db603b71 +9600917dbcd80a47f81c02c3aafecfcef77f031bf612a0f1a8bdef09de9656f4bb0f8e3e95f72ece1c22bd2824f145b6 +834a0767b7b6199496c1faee0e3580c233cc0763e71eebc5d7c112a5a5e5bd95c0cf76a32ea5bb1b74f3cf00fbd2cfb4 +99469a893579ed5da7d34ec228854c4666c58115d3cae86d4fc2d03d38f10d8c5dc8fb693763a96ab6be2045cc8d518b +a52cc0aecda6594de57d8ca13b146e77212cc55854929c03f2a8a6cdfa46296791c336aebcc2610d98612d5b4c0452df +97864434d55aa8a7aad0415d36f9558ce6e6c00452923db68a1e738232d0cb2d47e3b0b8f340c709112838adeaee4695 +a4a7f2c45db3661b6af7ec759f9455ba043b0de6fd4787e3372cba215b9f7c641d5d817a0576e7aa28a46349d2fe0ae6 +864e857652d95e1d168c1b9c294777fc9251a4d5b4b00a346b1f1c9c898af9a9b5ec0ac1f3a66f18a370b721dbd77b23 +ab8eac458fa8e7eb5539da3964ccd297a216448c3af4e4af0dcfed0ce29e877a85e29b9601dc7508a060b97a05f37e15 +a6fd0782c5629c824fcd89ac80e81d95b97d8374c82010a1c69f30cef16ffc0f19e5da2d0648d2a36a636071cb4b69a7 +ad35a75fd8832643989d51d94ee6462d729e15f6444ffdf340dfb222af5d2b6b52e5df86082dbc7728fde7c1f28ac6b4 +8e06831cc8a0c34245732ea610ea6aae6d02950299aa071a1b3df43b474e5baee815648784718b63acfd02a6655e8ea7 +994ac097f913a4ce2a65236339fe523888ee43494499c5abf4ac3bce3e4b090f45d9abd750f4142a9f8f800a0115488c +a3e6a8e5e924f3a4f93e43f3f5aafb8b5831ce8169cddde7296c319d8964a0b6322a0aa69e1da1778fcc24b7de9d8b93 +81a9bd04f4c6e75517de4b5e2713f746bd7f3f78a81a2d95adc87ba0e266d1f5e89c9cfb04b5159c1ff813f7968a27a4 +b24de8f3a5b480981c6f29607b257ded665ecd8db73e2a69a32fcf44e926fdc7e6610598e10081cf270d2f879414b1ab +adc1b3f8ed1e7d5a26b0959ffe5afc19e235028b94cb7f364f6e57b6bf7f04742986f923fae9bf3802d163d4d0ebc519 +a9fa5092b6dd0b4e1a338a06900b790abbc25e2f867b9fb319fdcdfb58600315a45a49584c614f0f9f8b844aa59dd785 +b29c06b92b14215e7ef4120562893351ae8bf97cc5c3d64f4ecd0eb365b0e464cf27beec3f3ddac17ed5e725706b6343 +adc0d532ba4c1c033da92ba31aa83c64054de79508d06ee335dcab5cabae204a05e427f6f8c2a556870a8230b4115fd0 +9737150d439e6db2471d51e006891d9687593af4e38ee8e38bfa626abcefa768ca22d39133f865d0a25b8bbf7443d7db +a10d1e6a760f54d26c923c773b963534e5c2c0826c0a7462db2ea2c34d82890f9c58f0150db00aa2679aa0fdb1afcb08 +816947dc6c08ee779e9c2229d73dbfd42c2b3b6749b98ec76dbad017f4b4d4f77b5916600b576691978287208c025d6f +a2dc52b6056219d999f07b11869c254e8b3977113fd9ba1a7f322377a5d20e16c2adf46efb7d8149e94989b3f063334a +8153900aae9cf48ebc7438b75c16f5478960ef9170e251708f0c2457967b7b31521c889b5fe843d2694a07c0e804fa48 +a9e9d8d66c8774972cc1686809ce1fa5f0e16997ef2178b49bcd8654541b5b6e234cb55188f071477ba1cebcf770da45 +b1fa775f9b2a9b05b4b1f0d6ad5635c7d7f4d3af8abaa01e28d32b62684f9921197ba040777711836bc78429bf339977 +b1afbbd522b30e1ae2adf9a22993ab28b72a86a3d68d67b1833115e513632db075d047e21dfe442d6facc7b0a1b856bf +8779b7d22f42845a06ae31ac434e0044f5f9b4e704847fb93943e118e642a8b21265505ad9d6e418405d0cb529e00691 +ab2c6cef1c4e7c410e9e8deb74c84bedeb3c454ae98e3bc228eb13f6b7081b57977b3e849ba66346250e37c86842c10c +908d6c781d7d96aa2048c83e865896c720a66fdec7b06ab4b172192fe82f9ff6167815ffb66549d72bfb540bb35c36c6 +b790440f205ece489e2703d5d1d01ba8921dd237c8814afb5cb521515ed4c3b0a6df45fd4bd65ba63592c2fe1d008df3 +aec346251f9c78336b388c4e9069a1c6c3afbbb6bfaffdad050a9e70e92fb3cae3609067b4903552936f904c804b0ea6 +a0e528cc2cb84b04cc91b4084e53ead4188682a6050b3857c34280899c8233aa8c1a9c6fa4fd6a7087acf1b36d67734a +aa8d7632be3e4340712a1461a0ad0ae90ba6d76e2916511c263f484c6c426939fa93ffbb702cd0341eea404d6ddffebb +a4ea871d8a1d4b925d890aefb9897847599b92e15ce14886b27ce5c879daa9edead26e02ccc33fcf37f40ff0783d4d9e +ab63e4dc0dbdaf2ada03b3733aafe17e719d028b30dc9a7e5783c80933a39935dbe1ef0320bb03f9564cafdf7a4b029b +8219761bbaa39b96b835f9c2b4cec0bf53801f8e4f4a4498d19638be2fa0a193b2c1fbf94e26c1058d90a9ac145a7a12 +a609ee5561828b0f634640c68a98da47cb872b714df7302ef6b24d253211e770acd0aa888802cd378e7fa036d829cd36 +90793ff0736f3c80b5e0c5098b56cda8b0b2bca5032bb153d7b3aa3def277f2fc6cea60ac03edc82e3a9d06aff7d1c56 +8760085283a479d15a72429971a0a5b885609fd61787a40adb3d3d7c139b97497aa6bcb11b08979e2354f1bc4dbf7a0d +b168ede8b9a528c60666057f746530fc52327546872dd03c8903f827d02c8313e58c38791fb46e154d4247ea4b859473 +842c1149ca212736ebe7b6b2cb9a7c3b81ae893393c20a2f1a8c8bfef16d0a473ff865a1c130d90cc3626045f9088100 +b41d0e2c7d55108a8526aa0b951a5c8d7e3734e22fe0a6a2dd25361a5d6dea45c4ab4a71440b582a2f9337940238fe20 +8380bd49677e61123506dd482cdf76a8f1877ea54ed023d1deabfc05846103cfd213de2aef331cdf1baf69cfc6767be9 +a026f92030666b723d937f507e5a40e3f3cfd414ad4b2712db0a7a245a31a46002504974ed8ba9d8e714f37353926a4e +b492e9e9917b29eb04cde0b012df15cbd04f3963d120b63c55dc4369e04f5ac7682b2c7dff8c03410936c26ca73ad34c +81fd9271b4ee36be0ba8f560d191e1b6616dd53c56d1d8deac8c1be7bc67bbc53d434cf70d04e7fa9de3e63415389693 +835c3711abe85683d2344a3ee5f70e68342fd1aec025ad248efe66aab3e3d5790fad2f45bae0d7a53a80998fde45f0aa +b46599be80b8f7dbad0b17808dd5ca91d787929c0bef96fbbcf6c767727d07ed6785bad164d733ecb015eb6c8469a16d +b36bf5c17271d39f5ccb3d82a5e002957207a0cdf9ae7108a4946e6f3ed21a5d353fa940b6fe949c39422b452339bae9 +a12f5444e602d6fb8be51a08b8bc4ec105dfd759d2afe98d51ff4edd673c92e4fc91ff32417ae8070e12169004f8aad3 +892ce3ca0a2961a01f7f0149b8a98fdc0f8871c2d85e76daf7c8aed2a18624b978a4d0a84213f81f9d2a81f7ca4826d0 +b1e6229ebd5b3d85e62d0474d1fed34564f1b5b9c5856fae36164dd0eff378d67d6717dda77536379006fb462bced9da +ac852921dcb81e54e1e315fd6226219932f7b785c2ceb2035710e814899784d7001101f1515d68e3fb74cdbb4baf9e26 +989a42d851123d708a213f3a02cfc926df15af058ec9b5a9df968fe16decbd781b5e65a4c17fbfedd2ac17126084700f +b1d0fc2f7c948e466445f307da7b64b3070057c79c07c7ebbbe6f8ed300a642b3567aed2e5f28988ac566ba62e0d2a79 +83057263b41775bc29f1d59868a05b0f76d3bdf8a13c1014496feb4c0ee379bfd0d4079785252f51fbeb641e47a89b69 +ac9e6a208aa9c557155cf82b389bb4227db5ac4b22a0c7c8d1c3d98946df8b82b0c49d093ba55c8255e024a6d67c14b4 +8294a11cd3f5111b1f8bd135be23b4de337ac45711db9566ebf6e162cd58e7859b1309eba8149b0f0a43e07f62a92411 +8c15f3388b196603c05adec195c1d2cc589e3466da3169e9afd37157fa55cd34bfafbfc5ff10ac0e04aa6a0d0b2ce3db +b8faf8ba89c3115576ab6b340f6cc09edfea8f7331f5a5e8003960c584e839fcecf401113dfbb9a5c11a13721b35c263 +955c63b1166514c02847402d0e92dccfe3c0dee3bc70d2375669afb061594c85651e6569f471a6969759e5f373277da4 +963bd4f9ae7361d6936d209592a07d9a22cc9ef330cf0c5cb845cb4085d76e114aee66d7599bf5b9f11c6b1c05dade8d +85509b3c97e06e0db113b8b40022c8989a305cec39acab36ba3a73a4b4719573e5bdb82dc4795699c26d983465cd61b0 +b870cfd7f691f88db8d1dfbe809b7b402eabd3b3299606b7dfdb7ef49415411f01d2a7e4f7ebd919ac82c7094f628166 +a5533e7b58a6a9e5c25589134f501584163551247d36f50666eeb0a0745cf33e65bb8f7a9c2dc7fe7cb392414f1ece4a +b93d1ade01ff5678fcd5b5b4f06a32b706213748076cae3a375e20a97231133ec37c1c3202cbc4896b66c3410210f446 +86ed3a58000a46fe2c37d4de515430a57d8f54ab4300294685534372fed1d68e192dd43d43ea190accf3dc9b22e1548b +a8c7d8dc30057bb8ad66b9cfda5e223334407730aeb0f51705922c18e7a07d960c470d463d1781899203e1b1ed1df484 +8d86821d006e957e8544f95a98b110c89941bcc6985562e7a97285f5826b35b690963b2c141ff3f389d92ee18ec76d24 +a4e1108cd3cf01810e74dbbf94340487011b80013b9bfdc04f019188c0d4d077a54b71a3f97a036601aad42a268531e8 +a822cd61db07f64bea00de226102f5fc0adf8fa9f05a6c7478b0ff93e48f6cc3191302d22e1f369b571877d5eb96139c +b1ad4094d0bb4c325dfe072b17711962247dd7ff7e4bce4612e80a6f3c1bde04880ba1682f60d5f1451318afd4d3ba60 +88e7beb0cfd7361288ea27f6b2cb18870e621152ff47994440c18d45284d21bad80d9806ed7d9d392a5cd791d5150ce2 +aad3724a176cf4476595cdfb9e2c3261c37052324c0b5373a30b6cbeb481bccd303720840c49a84ddca916d470eb6929 +a57983370d159e7078a273746fb22468000a6448b1a31d277272e35c6f548f97928e9015f1daf577511bd9cfee165237 +a54136e9db381cdd6dfb3fff8bdec427d4dc1072f914f6fecfec13d7b8f95bb3b5f30ad7677288c008ce134edfb039a7 +a25dfc4019f165db552f769f9c8e94fa7dbbf5c54a9b7cde76629cc08808c1039ecbd916560c2b6307696dd9db87d030 +a917d25328b0754d70f36e795fe928e71ae77e93166c5e4788716c1ef431115c966f2aad0ce016f4bacc2649f7466647 +842ce5e4ad7d8d4b8c58430e97ff40a9fce1f1c65ecba75fed2e215e101d1b2d7ab32c18df38dab722c329ab724e8866 +a8eb2ed2986ff937a26a72699eb3b87ef88119179719ff1335f53094c690020123f27e44fc6b09f7a3874bf739b97629 +96753c1f9c226f626122dad6981e9810a3cf3bbee15cfc88e617cfd42753e34593610861be147a7b8966bcdec55bba8d +94119d31606098f5b129931b51b4b42c4e3513a128b9bfb03cfeee78b77b9909b1c2fcf0a292e49d63bc4e5fe823dfef +a869654f5880d9c21a0af1ff4cfa926e03ec1f2d80fe5524605e04f484e09dc80d6769249f31fd378ff3926ab4cebc69 +b2a539bdd8de4499c5f35cd8824974c2abb1933b3f50d0175dd044563ca829eaa0fc47bdac97eafa98434d1cd05d7c5d +85f53b2bfcde1986ce7279f3a2f5f841f87d75af5d197c897f261d4874bc6868c575ecf7556a32b7b33f7b2795454591 +964f087ed02228b30f401d8aea35c1a7f76698e4075e1bb343398be74c716884e9ca1a31b81566e1ff7513cf76a2f0cd +a1c9d9c9bfbc9c4e281a2953d5991e7b22ff1a32ddaace9e8d9a42e080efb802b853d3276973b5189a5745943c9b4389 +b0c45a9852663a427d7f50c608a6419fbd00f90e8452757a45269d25c0386ec29942f48a34aafc0187ef6020e581d290 +aa3ca7b01862d5d2aea714fa06724b7dda7062b6608605cb712588b2c49fc3c7d89a8799e6e7c31e7a9ef28b1ad4d1f7 +88f5e98ae8c5ae7add42f6d358a35667e590aa80e1869593cbf597d7ee466efa35b429f1836ba2199d8280fe7f60ce3a +8a3bff472e8008f7e50362acc1a0b53c09ac60430942544532722e938470376f0672662261992146765b7c75a380c318 +b9847be7f7aee7532282c279dde928698a892a183ca3047ceda521e9e0a50d96fd3ce59f8e58f31af49508ade6d4ba51 +98065dc23ea3df6d9f8459e81887d88d5752b7e7ba6050ec5c3f0dce93e463e0bf12be3c94ec74c16e2f7ba62e447845 +994aff677b97ee790894dbdb21b1f9210734e008cee2aa2200c8f2579ea650b872f39776a13a8c31e95cc817091bae1c +b292811674e18912ebe79df1af4a132b04ab702c125c039e0213f735f658fafd36c38e5bbd7cad35842576431f5f3630 +96520d750ec10bb10f75019f8f0e4a93ecbc6b678a710d76cd10aa27a6642ad1461bd58fc2aab8e0391b3f788339ed29 +80d478da7fe246ad0e81a00141229e9d91ffb7fd1b29975c8ec358ed5e864e481bf01b927a9ba002c5ec4aa226d0cb57 +ae58049d93a11ae845dc5be2505e95657f83b95d83ff3591a3c565d587157be795ff4481f42d59eda95e6d523444e199 +85f1f5ad988b9f8a7e24b6d6a22b9de9fb3fe408f95711389c444d7ba2243987225b04318aa97a4cde2cb4c30c05508f +922092d0cb828e764ce62f86cbc55c04dce07233cff041888fae48cfe93818780b4aec9b4ff4718275bb2bfa6bd9e9ba +a85ba97125feff0590a05fb78f19a7338639ad1748802918af4d59307bc994536c0ad638b97b9acd26a08b6b4370dfbf +8c46fcaa8d13266d650bd9366180e5ebbfa002c339e4424a030de19ed922e2daa9a353ae54921a42299607ae53feb075 +b8549832230eb1ec6ee3c33c078deb47f556a0907d2a85fde7720391c82d2ed63dd753cf544a6a0a46eed4b8d1ecd9b8 +b7b96f24504c7f8fbed9c1c654a2550feeee068407b809c43f1082c9558c8665806d911d5d244308169d8a531373bf56 +81c483fd9d9ad7af7869d617ac592e7e951e39738da041d8c4110637689108eb29c8acadfc85366c70885cdf77b353c3 +acf33bcfd9080dfdba828727fe36803327a94e8a3ee5b6e445274f0e8267ad3c943994a8dd6d09b8072912b57e1e25b8 +b3475e7456ff96861bc11068198d51b69b899f5ff13022694b501d3adc8bac58a16204b12011d61e880c8459f4badbbb +8ceb9562026aa96d6e786ec2e5cd49200b5b424349a2214cd3ff5c8f1c2bf1b9872480428f5428e45cc61106cbfbd953 +af56f7e482c24a1367fd798201a20c464848ece431f2d8a31a6ef4f9bdbaa50991e748dcb4ef0c08fdac0ef8ddda3b80 +896dae8b12549909d512fd5c02a2f72dde4086aef6c8007ddb26bb04dff51a707ae94ff87e45191fc10339967fa28958 +8ed1c606840e07a2ac6ff16ac6e81ed3e1c90872ababfe68d56ed2dc50d9294579b9c3546dc63292874299a3162d59f9 +b4d7a5c0836e419a46942281ce77d0aade8e39eb1bf1190dd274ca5070898a1c02ad9d165855629d6e1c96df1a6bd5f3 +aebad8939ac117deb28b789d9846c2c80359dc260920ac8408dbae0b6228dbf496dac0023a3b4302bb9a53e8ada18e61 +812d07c74a8650dc3f318c9b2dbf265f181041fb432fee989cedabd44b933dc6590e36c71dcf9dbe7b4bbf74ea0d7c50 +87b131dd3489889e090839c392231e0ee198acac65bb2e9e63e7d6da322391d1685cfc8ba60699308054c4b0fd89c90c +8b12110ece0b99b2e653b4bc840a12bce5b85abf6fb953a2b23483b15b732a0068824f25fcaa100900e742886c7b4a0d +8765fc9b526a98512e5264c877bdca567e32fdcde95cdbcf4f4c88ce8501e1c7fab755f80b87b9b32d86d18856f1d005 +ac806a32a14019337dfdb5f781ecba5cdea8fb69b23e0e57a0f885e0082a9c330ba808621a48e24316604f6c6c550991 +a711970fa40cf067c73e3edee9a111bf00cd927112205e9d36a21897529be9a051be45c336d6b56725dca3aeea0aed15 +908adbc17fc18821f217d46c25656de811d4473779a41eacd70d2a0d7dd3010de4268a562378814e619e13ac594bb0c3 +894251b79be5ae763f44853f6999289b3a9abda64d52797c6c7d6d31ff2a79e9b3906da72f9ebb95b61d6b29479e076f +aadcf11ea15bcb6d979c3ea320cff8dfcc23c5118ed075f35e77f71459b2141253060e3a90839adbcd3d040ad3bdc5e2 +b4e55d7d2eeaaffb0267448ecce0b75166e4805dc0e261eb5634d4a3f3c08964a597302fd8f6b45ec48178619291dadc +a8e2a02c93d6bec7f42f9265269660b4b404940c3e3de9515b4d826ea7e71f18c6f90a71ce3fbe452d0713de73cb391e +8e2467accfe207cb1ba37d60662920f95338ee212927edb706228c25345734217740159310edf17687f58b333754cb65 +90376b88f653381b3bab673c48c2b84fa82a091e18f710a732fef836e0d39043fcd5527aa97a3a385c0a77cf53746993 +b16530e289198c235ab680f86851bcc177f0c16a58483d83a89213077b06d6840600b03834b6b7af0e22b1914f72de43 +8c4fc3854f938ef1c2b5df065e4e75e9f299798afae8205706439491bdf9784c756134922e77af007e349a790afa52b7 +a68aaec4341d29b92b35322f89b1ae3612e7b440c89a86135a07c261dc5799217a651460c92113d099b486817226d8cd +a653f965feefd2df24156478f0cf3755274ca395afb79e8c72d3b6e1d1f5ba7f3e4f9a4c5ee85355de6f3c81935ff579 +aaf6c8d2717b57f6b14e06c742a11a3bc736bfc0327ca4b8a005b6e924f06871141d231737698a9a59286e44f244a168 +8de32e3c104b4278e27aac695d224f134001c3619f15186466c57c0c46f67e2efe537501d0d9f52f4cdbc724a170b92d +8e9b5858b6d4ffe811f6498bd80e454f0d6b345d4729c946626c7cdc196c803a349a14515296aadb7258bb7a5b37e930 +82fc711043aaf1d7a9c712d00eafd816a710f82eb10818ba6af09f591447f36814dbff6e6a1cb2b5c7f16c73930dbbca +b2f0205327fc8ff687f751e7b97788732afaef4fcf51bb17fd7579ed07501915790b70fc36624371fe4fb87a0179d850 +add87d5b1288d30f3449d3ccfa11cba4dc7756d85cee1cb6171b493680a625a01f273d0bb8e6332d0410250036b3acdd +a411f75ef7dd8de8062331ea40929db989e4d65ae8f33d3fa6cc19c98fa8a8ec2b7c7534a5c5eee9e5051626a6a2e47c +89d40a647781e7f2e8ab3a0f7dc7133669944c0cf627376433687a2ea15c137be26f582a6b07ff94b266ac0910009f7c +b2b5f808c26b40ed507922ed119b0fb95e0d6d8b084bbbba58ca456b4354d03110c99989b93207998334ea5d1b70fe49 +8c8db028671969a1e80e595283ce5e678ee955d785043bb5fd39fdb68a00e4c15b462600a7ab1f41486b6883e725894e +958087ce0c75fe77b71770c2f645ef3360c1a9c98637693b988c5f6ce731f72b24ab8b734e8eb6258ee8b23914451f0d +aad6c00df131c1eec6c556bae642e6dcc031e70f63eee18682f711c7b2fcd9afbf1f18cf8a4af562759130add67bd4a3 +b6d23c567291f019cd9008e727704e7e6679b274feb29abba0d92e036f349b1f0fa8c5271ec7384e8d70a2c3977b1f8a +a942c770e903d4150b5684e4b94bb72d0e171df2c7cae6f46e002c41c6b04d774ac6e2753ba8dccdbba3ad1e297a9ae5 +aa542d1849390f86d797408ed7f6a31504aa65d583481a00e475028af20f8b69248a87a8ffab1dace0377db77fe5f9b2 +a1ed3f9564a97f7cabe7c67e018eaeaa42db73a2f3d2332041ca9a7bea57436d848784d6dc402862c22a47f0692b1286 +925c757750c91db8b1b3c220fcbdd80742b4a060abfb0a402071d215c780ef6b420132ec5a43043b9fd7a06bf1b323db +94e575daa7fa0bbb35b4386f510fc3877c9df57bcf15349c5923f30ad6a8df95372835cc078216b41a7192921c1e8973 +9346a41174865d9ab31c7fb9a5329f322bfce06002386d3f5a2e2193de9bfff12bd0bd93307928f7b85e1097b2aaddff +a6e54c9324baa1bff7e9bf39c94fdd308ec6f210aad937112ec727565f8a6141375c04196831873bf506294854f6a20e +98d47b662504f400f1a0e14e24b43829490d022ade02a56288aaf148d466b45d89b5fc146cef67c9ba548cd37ad5e354 +ab690dd59a69904b6b3a4d5a42d17ea4898d9b00c6753aec216d5d4ea564f9a1642697df44d5a62f2c2ab19aaabf1532 +8d0aa8d3c5ec944af49beb99e403cc0d6d1adc6003b960075358a4ff1cbfa02a83d6cb4d848d9e83b34882446a330883 +af9334b7300780c752f32eaa68f3dcecd07dc50d265083f37f9800b02c2595ba24dab89f5fc27c1ecfdbf5291b4d77bc +81c4a6aaf7d4ccee9925c512dae5da6d916a6dd59f7a4cc79d216a91201b4d300114a309e3ddb3291bb95f85bec2a8ea +8c804e810c0785789de26e12b1beff56a163769733be7a31f34f81093782d6410293768a166c9191ef8636fc8724a31e +a91222b48de238f6dfe79c84080cee618611bd0bdca15cfe44474829e42481f8511a82589e69964e19f8cba04e3f5f3f +b26a8885aa594b0c8ad4a1711d80bcf687df996442075dd1497db1b446d16c74e28bc6f0e92b2ecea9c3e15c9c7e828a +85940f45d324ad1d335bd1d7d6f81758f52213e63d5770d9fe0c0c9507d5550795e538b6a2dd463f73d789b5ce377aed +931a277c78082f416880620df3aeb6d0bff2103d19679dd092ea981f5323e438c50a0d094908034ff8a2cb47b1a44108 +88dd85e4e2aa349a757b98661fc00d4538ec1d3f53daf44b16ffcf7f943dd4f2bba5b8ba3b05c529251dfeed73f6f1e9 +b7fd7182cd33639710b8216c54a11bb02e199bbc54fe33492a809dbe17771a685d6238ea3ebcfc75e3b0d4ea5369bc9f +85d77194d910f8cdad7330e1bca9087529a40fece17492f1d17cc4790833891b6d01d24f036b6422175c732b438faeb5 +9845265892d672d9517fbd22f88be4f225711b4abafa8327cc059f000656e4737188506051565d97912a0c19c3d063c0 +90a81987aa841c7f640c298b816643a0ae00cd3609c3a31d0b01245283cc785d9bb27763131b31a4f21aeda4e50073e8 +8b1256eb41a600bda8a06ac08b98a220ebfd52f89a0e4fdce32425db7a0481e9b7873ba3b7a24ad9fb782ee217dfdbf6 +870548998deed85c59507cec7e69cc001c279bb2a99c45a4d030a35c107e69feb76afecb9e435e67965051d6d7a88220 +b1504d194a0dd8df48d431ce991f89d7a0f72f573d21bd5bb46474c5005e43820877a44e62db555f194427ac8a4b9168 +a00d7423ec2cf0c9e9da07f3dae092d09e1ff4be852e07e531aa54d62ad937bfb52c8bf44683ac3a70f6dfc125575da1 +8019625ad3d218018803aacc2efcedba3a41c24aca8c5aab2005556e58fdf2ed614831277df7937aa594e97a2fc65e7d +8595596284f3add0155ecfee3fc0b66a6b6fc7923d82ca8302952e2ed906d119a1c053aed1123b51f73e1d30d93aba57 +a8ba033f5e7d06177e9ae2d99c40ed4e99e14e1c1b61795997f62e21ed8af1531c4720f23d6a39b0f75c6cd91c58c700 +a94f4167c0f6ae214bae75dd92c63299dd954b00b0d8b0416b8af929fe5aec6a259e44f83a183412d7ba4eb3a49728c0 +a73ee3c3a0fd2a369e0a279c3e214fb662d0378eea3c95cfb91412d7213a1f05958bd0de8f2a4f80f9f80d7eef943b41 +8ef6f3e241f6a761c9ab412629a49648c08b70b837c2cd8bea620bc93056ec73754e3e11f0df50f8e9fa67a9867501a9 +80b473ac4ba8cb82b4ae684206cde124d10fcf619f55a6c90d035981e1b08b9e141b4e5fa9a9af0b7f0c281b355dd593 +a566e2be0b41f01978dfffbb32f442b5e6706f5b9901110e645cf390f6a82869e3ca16887ffa35782a004d251d29c26e +a74e01eefa03546d00afdd24bf17015eee95d36de28c03c9b055e062cd5e8d8f20473c6d7ad21c94f9058fc5e84f9628 +acefc74de146911275dfd19bbe43d72729e89e96da04aff58e5fcb90962856c0b24eb13f43e30329f5477a1b65ae9400 +b5f113ef36e75de6d6d44130f38e460ad3ffc65cb9a5606828c4f7617981fecf76f5e862d7626ccb117aa757cc3c3e52 +96d3aeb1d3a66b136244062b891fc7f93ce745b776478d361a375ae57bdba9b4fcb257becbae228c1a3aff4a1c4fb5e2 +ab26c4a110877e5495b674569a32025dad599637b5dafedcfe32f205dfa68cd46f3ddf4f132a8e5765883b5c83214a07 +922a7a738066692193af32ccbab74edef067668ce3253e18a3275afcd5a6df7168deb2f5175c5fb413dc08fdaef63b17 +a47542f8e4a3a35ef6049280d1a9442c920887d5f1a1483149e143ca412318495a36decb804f81c9f5a7672a14965a4c +8fde57991e72a2aebd3376b4d9fdd795943ba3833431e52b136683567e6ee2cc1c1847dc49dc9534983060c54bf22f7e +addb041f01a99e7238ab2f9f2f94579861d0470b93b91cfb29f3a2e4c82386c868b2cfb6f3778b8a9cf908788acafe58 +a8c4e1df726431c43703739776e2cc51f5ebac57051244991baf53582538120133a44ca603d0722a4b5193e1be3c5ec0 +846379125968d1154376c5dc63100bdcd99b9403d182e3566fe48d79099099f51523cd81d21f0d1dcd622b715bdd851a +b828bf0d936d275abb40e3d73ef57fcd7ce97e9af35e194ae61463317bac6c1b0c3e4b40afe08a1061037bb7149108fc +abd07c71754973e698fa26c5019afd9551548f8369e2249b9902513f19a097057ee7065a1d88912e8f52e6e0fbfa6d82 +a9e36b6fcc9a3cc98e76d5751c76c50e1f92b7670f8076ab6ca8a30de4ec14c34669e049fd39bd293cde8789b1ca67f0 +8c060835496a04c7b51790790035862b20547e62fa8bb4e8857fb36891ec6309520af5c0f45d5ea46e3d228747d710a4 +8cc472ec62b8dce244373f40a821db585628989b6a7c4d394edffbc6346c8be455f4528d528fff41f91f2c875bd9fc0f +b4a75571f84f93451f15b3a86479063d7324d2789b6d2f2f4f8af68c66fac32743dc09b51df29608d62aaba78f6904af +916484984743b5ac16d40d0544faf9184819d92f779254b7fb892eb68cefbe59e75be8a6336a585e120f6ccae0a1eeac +b906ae585a73119764024e9eb87d92e53ee0c673474fec43fec4d344a3bbf471ce3976d25e37d197604689bbc944f1ab +8552708487305f16f95db3e01fbbfb969398f5b6d116844cbb000c9befd03f15c767584bf9541a42141949a4dc787a3a +a6025a2773f78c247f78c0d895ade8a6baa76e5499085f6175935d98a05fc41c1359f7843e0c6c323f1be256c45f45e6 +96dac695dd9288aeb6e32dce50e51ddf1fbd41de6146e3605c7a81f2253b17babf2bfda4f5a9d0c28352b9746c0dfa2c +a215b21f8eb2290f9d308278f2859a999eb3a31f4888f84a65f9ed05e1151c17777f91054d4d0de759ac5c3547d91929 +8fd7c9a279e9b619acf927d501b35dc551979731a89eab91d38b2356c0d73569baddacb9d1096d20a75c917ecaedadd6 +b985e8baa5195e2f1ea1091122d55aa321178d597f87b732b23eccb12b891638be1a992305a1ffcf5233af34339fa02c +ae1a9604b7f569aa48d2daa1889e76d3d103065fc8c3deb9ae127a6d94145695cab3bef640fa781612e8082c6d616c47 +a8fc67f9069f753360349eb874fa4dcadb2ec48d97c61abe568faee5f370ec3c87786c7faf0f73fc0ae7181a36eb89ca +a506d13acc3a9f80509fac936aef848cd30698631fff6130ed6217512ed9527d075f653cf6ef91f68e48a24c903eeb3a +a415093755cc012863043bf586b970bafdd87653ad14d1929672e04949bae4a753d16aa3eb5bd1afe3df3691b80f240f +ace3b792a1960580348b6fae8513149242378a18382741bbc2fb2f785cb8bf87550da4b5e0df2955970ab3a31f99f5d7 +a47d7fa7522664c8f9c404c18102f6f13a1db33ba8b0a56faa31a78a3decba3168c68f410115c5d9f240b3dc046dc9b4 +a9c930db3ea948cd2dd6ea9d0f9a465a5018bbaf6e9958013f151f89a3040cc03ae0b8eaf74b0ff96b4e7a6cd8aa5b4f +88abd235e3e760166cdedff4be82cf6ba02d68f51c6d53b1de326769f1f635215890f9a4c35b06dd16a9b93f30f3a471 +8f8d7b2fcdb70bfedde1ffd7f0b94108f0fa432f6ae81097988521dd2c4da928c10c5da3c7f33f11bd5331f2da8ec219 +b7abdbd48cece30d8f795a58a94913d76842cb006892485a9382a0502826538ca4ff951cc1ef4493e45de8571360d20d +b3e7b125f350c52695f7c5ec4a30916ea6c11744f1151a18ea0510e6cf6ed6f6dba4beaa4ca56988d306bd80ec360056 +9a004423c95e1f1714f98fb97ab798d6ab16cb5f6d6cad860635585d4d4b43ffcda63d8e931351189275e5a2cef28c2f +a8eab6ef917cacdc9b1932eb312309e1f85298d63e55ed9c89ab79da99d3eb60f1643d16be920e82d9285f60c7f7cab3 +934df955485113d10c4dde476ec14a98771145aadf3c8b61af26b09b9948757fa1abcc945ac91466a18c18c2fdce40d0 +99ed9146561597cff8add2196ff3a0f161dd5302685ceb846afca6efb5225f642e8f4a0970eecb01cdf18694fa697095 +b37062dd12a81267bbbf89bc9d6e30784c0e11e713cc49c6c96440f800f2a6a2a7e7f6c7f6c9eed4bc3c8890f2787342 +83a3d70055b6044e0207b3ece4da849755ab5798317b36b20c3555a392c27982f811e1c5007697554eeedc737b37f3ef +a85392c07ff8658935fbc52acec7221cd916c5fde8537a8444eefd507220e76f600350ae8f5dc3353911087b88b91045 +b1ea23558ad805dde9cc1eade995cd8e7f46d9afa230908b5fbaaa09f48547f49c2bd277bff8ab176f1c240beedd2b09 +8a16a48b9105d94700e8e5706b8d8a1ed14cffda5558a596974ea3191c5c3449da6e7efe2059e7baf4530a15f175ce16 +ac5fa54381fc565842417558e131df26e9505027759416165035357816a7e1859a7c14c228c79b4e5ba2ef6758e12ad8 +8475e290c399cc9322c05264a516cf766bf5fdb6b9dec7283961da0b99012d499b244b33fc0eaf94b461ab777f2a9537 +a7922f3c70e6857652805af7d435646c66d94eec174be997c4fe973d8f019990c4f757eeb730b2cfdf8154e6e97f7d5b +b90deb797fba3150cf265a23ea6bd49a382855cd4efe171cbcb1664683a9f1687cfcadfdca4e39cd971ec13aa5cdc296 +91ca761dd9659007d2fe8970bbd336c19ed0d2845d0d8aaab397116affcc793de2da73d89e6625cf4dae5983cceffa56 +9121ae9b60323ab1301e97555bcc74ddba0f5b1e62bfe9eaa2c239e1d685c4a614d397b32a59febed4db9968db44f38a +8477b07da4bbfe9087975f30d2c2333fccfcd7149f90e0e6fabecee627eee3ea324df31cf6a680393f5dedf68a35c9de +946a9c0f02fa6bf9f9d4933e7fc691749f4ac2f82a9b880666b5185189d4f3432da9096d0ea4d6baacbc079e19c887ce +b24663332914ea519435874d4c42d11842ea84dd3dc55292d5b0f27f64587848d095bacaec235a37003bdb5185daa6f2 +b980f46f84ac21dea75b4650f9412f6123325842758589a9b47caa68545905061f03fcad23cc102e2ce8ffeb1ae634a8 +90e9ebb060182d3043ea4210a2d934858559522a19eab9f0ff81a367484a05ec7cce78ee6a91dfff96145869db6a4e80 +b04228a009c91847693eab29c9ea71d1d6ba07060bc2b0b3bb81c46a125baecb3e1412f6ce4305076a97d316d14e4665 +8d3268370dbf38d378c7228c7b54e91f90f43cbfddc0d8468de11a4312616ca6372619209b89114152b16f334f4d2780 +964a63ffae653e0249685e227d937937b079ec3da9c977dad2b2e052af5eb560ce7d175941f2ae0df90e3d0a20b77e75 +855604c2910be885b14b27896e16d8dc339236b975398c771d29ac74e4278a2305fcf85203050a8faffddf64ea19cf78 +8e0b1d61a4349411eec77cf3490555843187a25a93e1f45bf66ad3982b9cc141b07805f8cb252b0fcc125e0052a7c450 +a03bc9588f971a1257cd0cfd2ca406c76aaeb634001864b0e4dda91e009d3361b33fc39f34922835031a423a13619a82 +b703fa855c2c4e1641d2687717fe8c5061acab71cd2dab55cdb069a6865464c3080f7936ddfd320516b6791b36c64b8c +aad1cfa7295e463fc3d5374ea4b952020010d67a77c7a86fe2c351a5959cd50df6a0045ad588257567a99bfd0e9400b3 +97906fb82abf5c1d9be8f72add8e6f175a6a5a4300b40295cb5ec8527cc7ec700fa03a7a494122d9605d212457452e41 +a83366cf93ad9a07f617e4002a10b624270f60083559b045ab5a805aaa592ac37b90c1e8b5437158f3bd942cf33bb633 +a585168e157e111bfa329d0ed6651a96509b20b30f6bb0691c6a5875d134d4a284867ab52511cdc19e360d10638e58a1 +b17d480a0b39f2487b7f3878714658fda82f2147c5ecbccd4004eb92d267c4663b42c93bafb95ce24e2f2f0a9ea14b8f +9362297a1a3951d92db4fd8ea6b48c403d6d8d2f7e7b6310b9cf9b4e4ba9e84cfe1ae025830aab9466c32fd659144474 +b1a62fbadfd4ea4909d8d0714c1e3ee9f95237fde20720f88d5ad25c274a6792158b99966d7b93151f769c832b6a132b +8d9af736949a33fe929548abe72384281365385862821a584f5198eed63bc5388f89fc574cda35a9eaabed0d336b86b6 +90ee2235f4ec2c6089b5cb7b8a41c9bc39e4a57935022ef28bed490e2ab12680922af7395bda4f708809e2bfc62192c9 +91f3a123d420bca34d3d751119bbebc435630c6605fb59a8d80d16a4895972e56cfe4cf1998e0a527c18ee38c2796617 +a2c4fbb20e7fbaae103b86ca9d8dbc2828e6bf33d1d7ce153bd98e8880fe7ac62abbf7059194b1eee64f4526a36c63a9 +91a7f93310ac74f385f11509f4bea9a4d74f2ce91cf2024fee32a4a44d5e636a73339c6b4027ee4d014a24b90de41ecb +914a6d405fee0a15e99704efb93fd240105572335f418d95e1f2de9afeb97f5f4b80aaf20bd5bf150b9da9abc2b6d6a5 +9462cf2c7e57e224389269b9fdddc593b31e1b72ab5389346aa9759fad5d218039a4a5bc496f4bf7982481bc0086292a +b7596132d972e15dc24f2cd0cf55ee4a6cc3f5a0e66dff33021a95e5a742889e811afd1dc0cd465cee6336ad96f25162 +99409bba2548f4ece04751308f815ecee71222869d8548fa142788fb19df5366d093a5131e57560237471bbd5279bbe5 +8e7560988a844b5b844ad460b19c452a5a04346d8c51ca20d3b144a3670ecc60c064b2415c2eeebf140d6ae4ba5c5360 +8cd9e18d311e178e00eb81ca839cfaa8e64e50a197de8461f07135fca28c1d895dd9c2401b923a4175ff711853497317 +91ebf99c95e8f653402b3079ecbd533ed7cd3b6c857a710142354ce8330cebdee7cf0fd0400417883b66055bec9d0552 +a9d0cf8cc6bbdc44426dcb716df667826426b4559056d73738bf3eaa6df373403861b6bbd6fa0454b1d2730e3b0015c4 +928320b452ef21d2443dee360110550f531d7a4275b2cb227814150f3e9e360e05a884d6e3bc4415f202120ea5ac333e +b9551f2b2e7bb984618f2e7467e33b5b5303b8707f503f2e696e49c2990ea760c31e0944d52257c7a38b553a67cf621c +b2ec34126fe61345e5c6361fe55b8fb3218cdcc9103bba5b200252d50b758153cd549226b7aabedd265906401e755190 +a8cf814926082a96a921d471036a9919a58e68d02ee671c215ea304759cd92a7c2c9ccebdd5e9ec5572164ad2abb22ad +8c0563c28c261bbe9a1ec4986f8b277324bf05b4fe5e2b79a862168e646bbea50ce7c4622b2aa7ca899c1a728c226d24 +b558cdc334ea894d3a13347ea9e30f78a0a20621903d6c009c54feceba3ba81d2445a43572e088ae691f65489702e963 +a62ba0b20f46c367cfd409beb300e39f1a6cd5be95e63457b6ad3cb66374aed754fd037b8e4215d651a7d8e1a442f762 +8543e2c6135df471bd7a5c09f1313674c7f6847cb88f15eabf40b2bc9535d0ec606725b97103334a0c162a20d9f5bb53 +8c0367d7058d63b425450f8ee9252e64234c0c2e61878c7c2d4b17bab22a72f40c75ac3bf8b64f264c00d9c5963af041 +acb7207445993d563f1b6e7b179bbd6e87044399f80e6d15980acf7aaccb9d85071fecb22250afb3aba850712fbda240 +b93725e66184bb03f0ab4078c737a7fb2b10294a3a09995958de3dcf5316b476ce9b5cd8d180017196d9482abdfcab88 +afcb52bb7b8f45a945299da6fc6a877ba9f69f7f23d5f94b5f5d9a04c3cf3089333bbd50fc305e3907825003da73b9f6 +961de781cb238cef52d43bc0dc7d8e3a75bca4c27ab37a2e9353137a9aa9403444a5841b595adeca75a3de5485ab97f6 +9408c828d3ed6df40cc167d72ca9882a9c9cf8e765d6f9125e02e0d66ee0ac94f449803afb50bf1b92176feae92473d6 +a85480591e7e033b9087fd0efe5cf3c88c10a75de4a5d7da4443df1cc1fa1aa59b6cde3ce7453fcabe555495e49ef6f7 +a2611bd82344bc5d70d7e6cf3f0d25866b9f709ac4bf6f75d1006da2a11e2cd07a4c0ac71505e5062a04f71db7a3063b +ac466aaa96febb5b810ba350c7a874797ce4bd6c9585f6b9d114d646894a67c9af9526ade4f7ec834d3a69e18ab643af +b73fc98a79fe77cdbc524c76a09cb9f2d5f8b0a5508846bed1ba5ea9ae3bb62120e01d3b8fb544d90ac9ae0c3d4ccefe +aed333c3403adc899a870082f70aadc770c9f880dc057f05a46d7400be9d893354121a0a31e5475898f437bf722eefcf +97f02133c72187178a8c48db26031f0b2c0317a6648d2be5f7450f00c37391cec935bea46b8144ec9fea5327ee959f27 +940b582b41f1d0f09f0c5f51bab471e4eb143e91b1e96dde83e94650421d51f9c9baec10cc802fb83cd63b56d0b907c0 +b1286a55a74a88a75da47671994916be428be1ca3f42783e497d6478eaa6aca69d50a421b210e9ed3283d578b651b8cf +97cd4e87e21c71d11f1df1c0b6518c00e1610661be4b13cdbdbb026d60fc3f4a2b8549326a648b3fdecb7de8f6aa9fb7 +8f36bbcccee986c35328633bf6ee8f70b5dbf42d0f677c0f4e009d2289976e512af6af91a6ddcd87dc0df93bc4ecd02d +9253ad44ad182e67ab574d718733a69c05cd5bcc43e6292ef0519a9430460aa6a233fe26269da7298ea88cf406e733c0 +b616b5ea74db0dcf8f10a2db79df6ec3566c06410f68a933eff150194608c591b2b175908d4b4ccaef1018b0fefc5693 +80a712ba89394381cbb83fedcaae914cc4f21ab024b8da8a7bbad7762a22f82940451427b1a3f5d84c246d5ba0c7ccc7 +a806909a5517a970879143ad789c6cb6256b82553b649f6865cdafbbc050b1f86528241b3cb600e784186e1a672b588f +b6ae801d1f0e4adf3ce57659d7c61f94abd3c8d1635ad28133a79eff0586fc48bdc195615335449e9bfee39e8a955eb2 +b8a000561211844bef72adf3413f3b438a8789fcddf6676402ca6a1c2c63b9deed322030de2ae3a0aeb3cedbb89406c3 +8bc3615b28e33fc24a7c989f8b4f719c914c4c65b35ad3d4cf15e2196e37c62e42ca34e8b1275e0f32589b969bdfc21b +b2f9637f370a79e7591e5056dac004f56b375f33645ae9f5a192cc6b7b6b3d8a1105cc00f10d8bc8ef250ecc2ac63c39 +b51899978b9c5b737999fee1935a5b0944261e7005bea411b5903d2c16ea045a3b0bcd69395b6733752caed43bc4e343 +873c71a01009dddb9885c48658f83aa6320e74bc152e09de8b631c763c2b4e2e8cbac921418a0d9085ff5c53a2b52d39 +96470f48efd7d2ac2daea8753ef097c09c6fc128a54cc7ef758ff07e32c0b0ac7d122f97b53e88a29cc26874dfee5e0d +8dd2decbd3504b7961d65edb8d51b96377f4edd2e0d2cd8a4d98333f373c79a8d7ca8f8408718d0e7b5e48255857c339 +b536ae387bdd0f6e40850c71fcaecb1051b2c8f7bf5cf92c6bda030de72a03e9212d00390c53a72a08e9fb2bff1249c0 +b1566076f59064e3545adef74fd1acadc1bee0ae23543c30caf9e1ad1fc20ebe84ee25004c612525b26857253f5345b7 +afd180e25444cb720342923b8897d38a6537bc33a0ca1fc9c6e4d524b280193618f19e2bcfbd07606b78b734fe6114ed +89b2a6c8811e5a6d07aa74c79dd854bdfc292cc104b525bc37e4c7c1f9485e19d759c8e27cd7cd73c46346f56ce3b189 +8234196e196898b2501b79d0dc016f6df3d5878952cdb8a93735e4ce2ecf77d07924c701e084533a20f0c50a7d1ee376 +adea7ce2efc77711f50138691ef1a2b946aaba08e7e3b21378708dd5a10bae933ed121e71834b43b14e2ea30a7b306e8 +a566d406a35fae703b3d1ea1791d9207116002e5ee008d01e053a1ea4fe5af2feb63605b011ae6a14414028aa054b861 +b83bbb063682386456719179b6f6bbc8cf6f791229600b7d402167737492f99437b45886695b26a28731e952e56f1ee1 +a8f5fffc2c335d3ad5c7593e81f0862351413cc348392afa86d50921dabb929a5a1de20d604666af9e17a13bbc30bc3b +8d5dcdc1335f01847f6ef650ff64b26e7c4cecb934a7bbce11254e8ced9fa9e4fc87eec55248f69bf499180101c63f5a +83fec30b8bc62f9fc28301a03ef18158d6364738f1c42de311bbfba2e62b25d4c9ea9d6097698b24c84fff956a6748b9 +96394fbe0c2d03cdaa56e13326aeb62344238ad3043ee2fb4f18ebf0a6f7f090f410032a2d15bfbeca9449202d59f2a0 +94880f5928fe71a797362a37d05849d23e118742697f75bc87173a777e7b9d4383b8796a8a2bbee27fb781f363301dfe +af229535896ab86fdf6d2ae676a0dbf44f868f6c7f17bd9a65567631c7aa2e29758f41de050ca5311bd1528bcc811532 +8d4fa4968575b483b3ac16345e7f1ea3f81e8dad72c945a48b7b982054fe1030584be2f89b2f53af84d2490cda551b84 +8052aeb115e4d242078c8726d376a13156cc832705243f14adaa3ef3889e1f2fcdfd46e087acab6fa85a74afde5f5eef +a1349c8a22788a1937a837fceecfaada9e93a63e582a09c56b53da52c9db1600254dc85f63f5eadfa30b89b31dcbdb30 +a10178cdb263ff1a5e0cc034b6deaa160d00c3c3fe1fd1ff0c55fdf1ecb83d771070c10930f88832b75fef39a10024ea +938b17e4405934ea5ef29c2187d6787c5ff5d8c9a02665efb453117d462dbc50ef2c202cbc884305cd807a70b5cc177b +84f01f0da6b58c71788616be71fb3c259ceea7f8bd131a5661c5c03d0205feaff6dac2915919347b0559c381477b3d89 +98787f0a2fac2b04bb7aa247ac77236bbe690aae64203e553be328a2c3bffb772e7a0244e585d27558cc64b089a5ee11 +a14501d8b6b3a84b13b9006d521667e8d168f642ebf154c4e90ec8c75d11985fd0c9d86fc2efa6c7077dafecfdf0ab13 +8215dee75eed04de83a3e910129bee8c48ce01cf1317ea477ff35c09a6f9e9771a8b05aa79e6b0f3e71b9874695e7a2a +85763c3072c7400a2c5668ef5cc53e6f4b8dff474146028a8be370ca9d8af9bf9ee10cd7d23d33eb6d6e257dd3af38d6 +91bf62245c5a59d514d39bfb74db7f72ca7160c1c5d5be3844fff37e53e99d451e18a6747c65e33f98f48a55f38962c6 +8c68817c6a6ea348d9aedce99929371c440fbad72718c2d239ffcaebb26ecc8a4e8c38c2819d945fdb7f02ffda70a5e0 +a96ce2745866a22267a49faa7ea00ebf009ea8d0b0ca2c233c62759b9d5514306b5822dd2eee0124c9e28380e2f97aa4 +8b18d5757c73843dcd55f0f0dc894bcd17e0ecf4c9fd901eacd38480844a15b4ce5e9598ccee039f9d93185137630cdb +a5b45c403b6735aaae14389bcee23ca10571f5437f1f5ab0c2b4e573dfd3341c638fff2cc780166af96b118d47ff2299 +ac849a0ccd354dd46bf55ea837d509b4ae3eefcbd5b8eb2582d301fd56c27b89950c6eefdd4e98e608ef4a6b75251311 +89f13ac14bb064e9c6b49a482831ecea6344faec490bd18bb44028b83a0f22e21145861558029bd172ba7c5247c2cba7 +aa57b057a2ac32c101e442c33831630c81b2e061a542e3e1d6897b2b7ca8a7241ef717a548b3f751d60d89be384ba5da +8a43db4e12682b98230364f25c75b49002f5002bd72a1674cf2a9d53197b5ef1b95e48429af98af503b0d5c3e0e017b2 +a10cd7b8e1574d78c4e917cf833d3d845b878e8e8b60312e6a994bd4f391a5e8c38dcd774087b93c9241238f43f80937 +8b61ccb949088286216cd628811df1a362a7f5c333654ce823e63ebd04b069d5b0f627fb6c96d54c7b853de8aab05472 +887b902020ad45f70f2d5bcfa7324fcbe7be09fd2b1bd40f9ae43a89d487986e89867aee0945ea6a0fe8dfd051ffec56 +822fcd260a7876cad31f54987053aab06108de336878b91b7a15d35013d6d4d6de2d4b30397bb6f1d5c1a7b48e9d1ced +80b89ff95d725858b50e84d825ea99fb6a8866f10b91a5d364671ccbb89cb292bada9537c30dbde56b989c8bdc355baa +b53cab156006c3a1766a57dd8013f4563a2e8250995dbeda99c5286a447618e8ac33ebf25704b9245266e009a0712dc5 +b6e2da9c1156e68c15861a05cd572976b21773e60fc5f2f58c93f3e19c73ad6c2ee3239e6cb4654040c8e15df75a505d +8b7e187d473a0bd0b493adcdb91ca07c9310fd915dec46c2c9f36a5144eb7425dd35dfa50feb0e9ef747caed9f199944 +9743ec3917e953e0a420406b53f4daa433adf4ad686207e9f296e7c83d1ffdbf81191b920ba635c85416e580178c16ff +98d1476fd4504a347c5261012298ca69c8593fec91919d37ddfdf84155b6f1c600cd8dbb92b93f3262da16cf40a0b3c6 +94f50d52982a3c81ac47a7b3032dad505b4e556804f8606d63d821f2c1a4830917614630d943642ba375b30409546385 +b5c0eb5f4cf3f719be1a9ad0103349269e8b798dbffe1b5b132370b9de1188a6d71dcbc3635dfdb4b888400f790b6ea4 +b47fb45ec73392598866d27994c2feb0b0f3d7fc54303a2090757a64b6426d183ae41af16794ced349ede98b9b3fd48c +b5f45fd0aee6194dd207e11881694191e7538b830bfe10a9666493ae8b971d65bc72214a4d483de17c2530d24687d666 +a50c149ea189387740d717290064a776e2af277deafcf5f0115bbbdc73c0840d630965a4e0214b738d1cb0d75737e822 +b941afc772043928c62e5dbe5aa563fa29882bff9b5811673f72286ac04fddf9a9ed0f9faf348268fa593a57bc00ba6b +839051a7838937270bdf2f8990fd9aa7d72bfc86cffe0b057aa8eca7393abf16b70d71a6470d877f8ec6771efa5a8f26 +835bc9d049418ab24dd1cbf76ed5811381e2f0b04035f15943327771f574f723b07c2b61a67a6f9ddc1a6a20b01f990d +8935cf5634d6ae7b21c797a7d56675e50f9d50240cb2461056632420f7f466fdcd944a777437dcb3342841ad4c3834bf +b5698fe3da1f9d1e176c9919fddd0d4d7376106774aa23a7a699f631566318d59b74ae8c033eba04d06f8cdcb4edbbed +ad11421ba75d74c600e220f4bce2ca7eacb28e082b993b4368d91218e7b96029acfbdf15a2ab0b8133b7c8027b3c785b +886ef813644599051dafdaa65363795cf34a3009933c469bd66a676fdd47fc0d590c401cc2686d1ba61fce0f693426d4 +8858fdf3e98e36d644257ab6076f7956f2e7eacc8530ec1da7f3e9001036cba7a0855fb5011925cdc95a69600de58b2d +b59eca7085a2f6dfeaa6a414b5216ff0160fbea28c0e2ad4f4ffd3d388e1cc2c23a32dbe517648221b75a92500af85e3 +abec62d259bcd65b31892badad4ac8d2088366d9591cd0dab408a9b70ad517db39c2ef5df52348ba4334dce06a4e3ba5 +a9acfe8f5a310779509621ed2946166ffb6168e68ecf6d5a3b2f6008df1728c8fceb811636c50d2e419b642a848a9ca9 +9929bb1a3537362848fac3f1bcb7cfb503dac0a0b1bebbfd6ddf14c9a73731e2248cbaf0fbb16c7d9c40cc6737c3a555 +981d06c7431e6f4654e32f1c5b27e7be89e7c38d59c4e2a872a0f0934cb852c6aeff2d2eaee8302131795590b8913f5e +a6ba9dd43354320f65fd5cdd5446cfa40080bcf3ef4a083a76ad4e6a609b0b088bcf26c4957bfab829dca6064410ca5f +9367ef28def311c79adfd87e617651fcc41ad8caf047d73ce9a1f327e8871e9b35d5b203fd0c0138e32e2ef91e20ba62 +855d1bb508a9036f42116c8bbb830c576189798baee27c7c3477ef1b1fc5d7b0c2c7203457f1eb48d4b029dd6f646be2 +8539a5d0528d3d601083e162b34cb33b5bf6736b4feeeab4941f10eea127c56b7e0b8d57f34b72f8f674d89c10bf302c +a3b71a9a9ac2dfcd681bfd8f6a5d9abf5df6950821705bdfb19db25f80d9b8a89fac7a922541cc681325679c629743d2 +8e95929dfd4e5b56e5a8882aad6b7e783337e39055a228b36022646a13a853d574603de5fed12b6c1f2585621ead7afd +8b05c885575d6894cb67ba737db5915639a6f281bf249480df444ff9f02724e28ed7371ee7ec26d50d25f3966010f763 +90f1a45de0cc0641181d54ee86630b5d182d24e7c30c2615803f16de90ec7c982a00b21f250ccebc2e94ef53a13e77e6 +90f0e97a132092e51a4521c2ecaaa47e4e4f319e67a3cdbd00ed85c2f10dfb69c339bc9498e2abbffcd54b1fdc509a20 +a9995234520cab9d1bdec1897b0b67571b718d5021c0fcf913140206b50ab515273b5f8a77e88fe96f718c80dd9be048 +aebc6495d54d0e45a3c74388891dbcfab767f574fed0581566415af872dc5b3bd5d808c44f6e1fbdde7aa9ffd260b035 +ae757f8f4b1000a623a7d8e337a50c3681544520683207e09d05e08a6f39384b7aaadf72018e88b401e4a7bb636f6483 +a626a28d5ce144cc0c6a30b90ec2c1412cbbc464ee96ac49035e5b3a37bb3e4ed74e8934c489b4563f2f7db1caf8b2ad +8c994e81dfd7a5c2f9d4425636611d5dd72d0b091a5862f8bec609d0cdd3c423eb95b0c999c48faa5dbb31e510c22b61 +a1c0e59e076b908de760d9becff24883c6eb9f968eac356e719c75cce481f2f7bcb1a41ed983a00c1a3b9369a7ff18f9 +8d7e199044fe2e552bc514668fe8171c3416515f7a5019f239c0384f0ade349e88df26cd30f6b67d02b83bf005d85de8 +80190f2255199be690fb502d02ed159aa568c390a684f7840512efc3d2a62f28a49d5d1928ad99a5f975ad81a245acd5 +889d84cefef33f5714e14d558f41d406072ba66b427bf27918b669c5be46261c3de0139610a2c2eadef8e6508e937bcb +a480a686d5085b854ccf9e261e7f1f2d40d978fc30b62b1a8fa9561127745529405820df21a680ee2258b8cefa5f0201 +ae6243400d416a8c13b80b6637726959ef07b8d9b6aff2bd3bb23aaaf97337c7a6b466c5db617bf2798e01d4ccc68e4d +85e0ff143657e465f3d934ee781de5cbd2bfd24f2fbbe6d65c698cdd93204a845f6ef1fa8941c2578463a06a8a418481 +8f4f8b45f1a9f6c2a711776db70f20149dd6d0e28d125906ba9893c5e74e31c195b0906f04c922c8b556ced7cd3d611d +877b852c33483b25c4cd8da74b6b589d8aa96e217c3c4d813466c77ef83af95a94a47364aa8421f0396ce631ad87d543 +852cb06bc4222ce125287a7a55a79ad0bf55596f26830dd6d79da3c60f80e3ba7b9a9b42b126dcb99d2cb9ce142783ef +810cd64c1dfce85d509eeb57a5c84efafe1d671454ef601a040de8d46fb33bc419577f6a6c404e28ffdfe315ffec558a +b60ff8bc804d101a32079b8ed52285fdbb47fd60c3c15cef17cfe7f6b0567de6b50128b9dbc49a1d9811b62b22c99143 +a9df7068b26a6a58f7a499e67b17d34f2a2e8e5029c6e51e2b4c0d19324fb5cd9734c4c4d5034e1bfc274cd0c74a82d0 +ad93c50802ded1e21217a58b874c074ea52322492d589820691572084d8edaede8c2ce8021c6df8c0060f395f3c25ee8 +a17b98e090f7ef5800477132b436c1fccc1802f34956711bfc176e36890c7df95a108e03f34659142434cbd8aee9dccd +acb14aea5575c293dc0a2b58c5350390801d57e9bcda876d87c56565043ddde1a544a88b48ad0d8ec3d41f690aef801e +88b8e26cbc83faa053fa247e26c95d1bbb77955b336e1b0e41d080633248238de8adc9b98688c98fdfc67e7286bc5be4 +899f69823cf1b2204c8da91bb4f943c04d943137b08b1c46e160919e3378bd22a666a079a66e63d81c05336c742efdd2 +8d7ffbc0b47a32408c9e88676ac4f87683cf37c37d214163ca630aec2d3cc014d88caff35022ff3b6d036eb8343d52a3 +b7760f27db0704a6742855998a0c31333bb34d60ddebc95588e25b72445ae2030427aab088ec023f94563118980f3b74 +ad06ecc0f3745861c266bf93f00b30d41ed89d41e99ab63fedd795c970d3ad40560e57ab7333883a72e5575a059df39c +8687d28b1cbc8aa34a0e5dbdb540a517da9bda36160daaa7801fce99754f5d16eda3bc8e1df6b0722cfb49e177e9bcb6 +a38332c3ebbd7f734c8e6ab23ae9756f47afbf7d1786fe45daebc8d7d005d6d8fd22f5dbd0fa8741e1bfb2014d3f9df7 +b86f84426dee88188be9c5cc10a41599e53b7733ba6f2402392b0ea985effc7525756ca1b7b92041ae323337618b238f +958731a6f1881f652d340832728bc7fadd1acebd8daebd772b5acea634e9f7b7254b76d38a7065ea1b2cdea83b18a54f +adb90bff1f0d7d45b8ba28b536c0e0f7f4dc4b9a0354692ecf29539631d7a57d308db3e438e0f907810234c490b42153 +a5188c775ad76617d3bb6e7f1f3b2449f48b7bb7a84035c316284396529564a227e3b9762a89c7114fa47b3ca7ba418a +a3826ef63c98793a5c8c5d5159e2e00cc85fb5e5124f06421b165de68c9495e93c2f23cd446adf6e6528967aa3ed3909 +80eab97de89f3824ace5565b540b229adcc6ef9d2940e90de185af309234cd8aa4ae9c7ce1b409b3898c8fd10c8c2896 +8824f5acd4c2330c459fdb9ece9313263a8b20419f50f8d49958dc21754c21a77bcf7fbf3e0041f78d8fb667a3342188 +95091cf06911a997a09b643326c2fadbbe302555ab2521db806a762a5f4492636507ca71d7a093840236ac3c096614f7 +a392c81a546196d7e78b61f3ceaadfb2771d09fe43f862c0af65f5e55ce490a0293b9ab754cb5ab03ff642a9a8213a23 +afd76cce1dfa2c9e4af4f840376674f090af37d8c6541824963373f97b9dd1f405c50b2ff56165e1d4dde760e590738a +8fc4f513d3b40c10872603e1c29a4b2cf4c99320962644ce89f69ffb57f844344e1d472b2d43559119bdfb5a2c21749a +9951ca8e13b9a2b4a789e851c04c4f030470772da62f101074ef304612e9653b43b37d2c081b5d0a09196b3a167f5871 +b4f16fc2a113403ab5fc1b6a9afddec77be7406413b70ee126f0e84796168a572940550d61e443e5635591d4b6c46ca9 +8d71452cf39e7345c7298d514b9638a5cbe78af7652f0286d42632c5c6d7953ed284551fb40c77569a7721413cdbf79c +953625b58d52a308cb00ad87c44a3fd936786ada44000d45bb609ea9db6b156a0d0f9475e13ee5e053eaded19a09990a +a0983a3baa278ad5f5de734eb1b65a04f668408994e396fb0b054991ad2e56e27ac522b04fe37c9583b754e344f795b3 +8eaa454257f77a6754b2c1c5ff0036fa5b03e214576fabc657902c737fcbf298b1795b43c5006e18894f951f5f7cd203 +90183fdeae2ce2a295a567fa61b997b1f975d1be7b03d0101728cd707bb2a7111c222588ab22e573518fa1ef03719f54 +8abec7f31f6b897a1d497368a42733a6bd14ffbb8b21d3e49fc4cd3c802da70e8886827c1aea0b18d1b44635f81ec461 +a6d1e6fd24b0878ff264b725662e489451c590b2aadaf357d64210a3701fe763f529826fa6e0555267c1f5ecc2c52c05 +8fe6d2a4ea0d91702cb2a8a1d802f5598f26d892f1a929ff056d2b928821e4b172c1c1c0505aa245813fe67074cf9834 +82a026a408003583036f16268113ca6067ce13e89c6e9af0a760f4b2481851c62fadeeef0d361f51dcd9fa5674ec5750 +a489a574b862d4056091ef630e089c163c16c2f104d95eb79a27ae1e898b26d6c1adc23edc1490f73bb545d3a6e3b348 +939d85148547fc7b9894497841bd4430bc670bb670f0efeac424b529a9aebf2c02ac18a9d1402a12e4e590d623de09f0 +a3ab52cf911a2ba7fb0cd242d7778ec0d4fa382960c9bd5b476bb1cd44ff1430a3871bbbcea0a0db2630c39ee639fd1e +b7629509d8c3a3b88b31f1af137a25c38f536284f11a5bbbe0d05b86a86bc92ebbf70f17c256dc8b0d48374e1985e6f3 +8a8647ff33e0747dd6c6ceddcf7938a542656174a08a31b08337ea49b08d814e75f8363fb51676a2cd2746569e3bc14e +a7a7f8d94d32b7cee00b3ff272d644b8dca86b8da38c726f632c2bcdfa0afb13fd0a9a5685ddaeb6073df4d9cfa3d878 +b7136eea8d05bfee2265b0e9addb4bdf060270894de30d593627891584b9446b363973de334b6105e0495cf8cb98e8f7 +a9fcd33ea59315ad7611a3e87e8d1fd6730c8cbeeaebd254e4d59ed7d92c97670303a2d22e881ab16c58779331837529 +965fd41741a0d898c2f2048945b2aefc49c735228c25deaf17fed82c4d52cf3f8e93b3fb8825ade632dc4940311b1542 +b9f400a2c7ca7da8b36470ee5d26c672b529b98e6582012cbfc2a3c24b72e73f5633de4265c417c0d47c474155a603c6 +85f333b0b1630a688a385f48bf0175cd13ecdd92fa5499494f4ad5aea0ef1b9d180fad8f936018538d842630ff72884c +8da95a735a1a98ed8e563099bd87d13a237dd7ec6880cfac56c6416b001e983a56f3d72dda7f68684bb33e4f64cadd30 +a29b66a2095e1acce751f6aec8dfeae1e5b24187dfedb5d1635ca8deae19b580ef09329a18b3385ebb117cd71671f4dd +b001deeeaf5eaf99ac558c60677b667b9f3d57cf43a2c4d57fd74b125a6da72ea6c9dc81b110655e0df01ca7b8a7a7ed +912e11dfff77c778969836d5029747b494dd81d9f965f8be2c9db9e8b08f53858eface81862c3ee6a9aa10993d0d23f3 +ac166a00e9793cf86753aa002ca274cb6f62328869fe920f5632a69a5d30d8d3ce3f0c5487cb354165763ca41d83495a +b74df519ae1a8faeff2ccd29892886b327c7434360ab5c5355752667069a77d466a48cb57b1950d10b6c47c88b2a8538 +8751679aeffa39da55f2c2a668f7b26fb8258f70c5454b13e2483e3ad452f3ac7cc4fa075783e72b4a121cd69936c176 +ae0cc16848b8bf8fffbb44047d6f1d32b52b19d3551d443a39fb25976a89d1a5d2909a4fc42ee81a98ad09d896bd90a9 +a0c8acd6a2f0d4ab0e0a680fa4a67b076bbbf42b9ec512eb04be05fb2625f6d2ed7b4349eebe61eb9f7bd4f85e9de7fa +85c629ce0deeb75c18a3b1b4e14577b5666cf25453a89d27f1029a2984133a2b8e7766597e2ff9ee26a65649b816b650 +938dbb477840d3ed27f903d09fd9959f6fec443fbc93324bc28300dd29e602bd3861fd29508da0dfdbb0fff7f09c5a6c +a7c76cd4a42ab7904d036fe6637471d9836ad15d0d26a07b1803b7fb8988b8c9edf522e0d337a1852131d0f658565ae7 +838a30260cf341ae0cd7a9df84cbc36354c6bc7b8f50c95d154453c9e8ec5435d5f9b23de2a5d91b55adde3dbdb755b9 +8f870b1f798c0516b679273c583c266c2020b8dea7e68be4b0628b85059d49e5a680709c3d6caabe767a0f03975c4626 +89bad0b6499d671b362ae898fee34ad285aa8c77d33ca1d66e8f85b5d637bbd7ae2145caae7d9f47e94c25e9d16b8c4f +af963d3dd3d983864c54b0ed1429c52b466383f07a1504215bbf998c071a099a3a1deb08d94b54630ac76d1d40cfc3da +b5686de207c3d60d4dcfe6a109c0b2f343ed1eb785941301b827b8c07a8f1311e481a56a4baab88edb3ddc4dace6a66a +95e5978739a3e875e76d927f7c68bdf7ab20966db9fa8859f46a837760dfe529afa9a371a184dfb89d2962c95d5fcf3b +96d2855e20c37ed7bd7f736e11cfba5f61bb78a68303a7ced418c4c29a889a4798c5680be721a46d548d63525637e6b0 +b134bceb776cd5866e911f8e96016704c9a3caeadcabd7c0f37204497d789bc949e41b93e4c2d597e4c924853f1b21e3 +a1949ff397013acde0303e5d64432bf6dd7f01caa03c5fc38e7c8ae705b9d5c2646b4b02d013004e5eb58e344703260c +8036a5f79d8aeb6df4810974cf8dbd0ac778906d2f82b969ac9dcfbe7ece832a7e8aad08a4dc520f7abeb24b1610ae84 +982b6b0af8602a992c389232b525d4239edc3ae6ceea77d7729d1fffc829664dd647ff91c4cb9c7f7c25cea507f03167 +b34c7d24fa56ab6acdb8af5b4fa694a1985a1741cc53a2b0c5833611e8ed6fb3b663a4d9a126bb4a1a469f2072199d66 +8166366fec4ee2b3eda097dc200cdfa0533a742dfbe7082dfa14c1c1ecafc9d9fa71f518476634f29d06430869bd5e02 +86c0251ac00b8200618c8b7ce696d1e88c587f91e38580b2d6ae48a3ef904e0ba1b20b7f432719ca40e7995f2281a696 +afd89f3bc7843a1e45ac961e49c1971114c5238d9e21647804b1852b8f476a89c12d1edfb97fff71445e879d6bfd3b70 +911d8bec4d4c3e73a2c35469b2167569f59705404425bd95440408fb788e122f96e9b1bd695f35c6b090f10135b20cd3 +b3f6350ff7afaa0660f9dddd9559db7f164e89351a743fc695d987c88f89fc29136e3c5eb81963edabf2b6f2057120be +a371229680d1468777862e9c0e864156f9cd7c12ce7313a8de67b7bd34e3d1b6fa45ce891a81f8316f4afcbdecf3b6ca +a6a9a875ef9efe8ba72523e645b5773aa62c4fb41efd23da3fa38105472308b8d293be766342ee0a2f00758825bd3b6a +a840d495a184f4499b944ee08f07193a1e1bb8ab21f8ce7aa51d03bd8643f2bc2616c17b68d3fe7c0fb364136926a166 +b55200ae7d6ebb0b04b748051c5907293184b126cf8a1c2f357e024f1a63220b573e2875df83d9b5e0c6e2ace9300c40 +b1e0870f2e3719f42a48256ee58cc27f613308680f2d3645c0f6db0187042dddcfed0cb545423a1a0b851b3a16146d70 +b43a22ff3f838ad43786dc120b7f89a399ed432c7d3aa4e2062ad4152021b6fa01d41b7698da596d6452570c49a62062 +88b1dc50873564560affaa277b1c9d955aebdcdd4117dab1973306893b0e3f090899210102e7e1eef6f7cdf2f4e0e5db +9223c6246aa320b1b36eb1e28b5f9ccc2977e847850964f9762c7559da9546e508503050e5566ccb67262d570162b7a3 +aeeed21b932752709f43dc0c2c7d27d20263b96a54175dd675677a40a093f02bba80e2e65afe3eb22732a7617bf4ff9d +b47cae580ae84f4e4303db8f684f559382f075ef6e95698b9a629e92b67bf004f64e7cf47e401768fa170c4259efbda1 +849821e1ead81fe2dc49cd59f2bba305578c4ea0e8f4b8ae8fc275a1c4a6192f8819d5b6d7da786c94dfc16aacf3e236 +8c60d9a8baefc72a3d3f9dd2e24cca40fb5ce36b19d075122391d9b371c904a0a15d2196c0f2ac9da3acf188d15b0fe8 +946edfe168bbe5ddb0fa6c2890bb227d8418bfbebe2bafab84909825484f799407b610d8aab6a900c5ff9eb796cdc4bf +ae7bf8ae71de5d7ea644d9541e49da1ec31eca6ff4c3fbec5480d30e07ef2c2046cc0a486af7b3615a6a908846341e99 +b4d31a6f578463c9a5ccde0ea526c95b1981eb79468665395c0e550829abfdfa86689699d57830856e324092a423f231 +93415ad3a732417cca9771b056ed42db7ce50879aca7c6f71883ad297eaf5a37fd4641d44a0b7e28b90c168834141340 +98960617a413a3ba86d8257a7386355a69258943aa71834166bd624ea93b0af06178e86538e237f88fd039eacf7cb04a +881335200a487545e38d5b1ffda3080caf5729e1b980603bcdf9ea652cea7848335b83aeeaa321d3476ae4a8d9073582 +b39e84c14666d51895b7a8341fd8319f9e0a58b2a50fc3d7925cce3037f7c75367b5fb5bf25ff4720c9992cab7b8b9f4 +8ea4bab42ee3f0772d6bd24dff3643d8b61147b46ada374414d8d35c0c340e458e449d31023d96e66decf9c58e30cc34 +a5198f6759a045b6a4ba28e4bc3bb638fad44c5a139064327580e285adf38ea82a7570acebf925e81a39d9025f3a6f2e +80267097e2d27c1b19ecf95d184dcff822d34e03326b9fc139a4f8b75b3f80777bb97a9dd284d9b755f14dd401d63c0e +946f346220bd3b6f733e94b61a1ad0b44e45c356fa6036dde5882d93b5613c98e23b20e91eddc6b3c5acea38085705af +a5f559e110cad99bbcae2d9362434aee7db0f3b6d72311291649dbda3f84c10e9760b66b988db3d30067bf18ae2e5238 +8433b38e5c7b293ef532f8c70cef1ed9be7f31f60d5b532e65df7d2885203be78b7ad78ab3011bc54cd9f64c789bf837 +a5a4c0a9b0e0b6bb912cf6ecd30738b0acc0146d77442449b486c3f32d7e60244f643a5cf9cc6da2de5408d0c5f17691 +a81feb329fb51b72464bddcfcf4e02149d995b548d88c64ba143144ce16b652c9913c8ee948ee837596ec97cc43d8cc9 +88e5a7e93a738d61330425bc21ade88d33d7160d124bf174eb3e12a00283654431036977c4f1a47a1bbbf2ef8449ac89 +ac75ad7c099383069e662bfd3624b92b64b5838246902e167fc31b9411efda89b2c6bbd1d61b9eb7d304faacf438d70b +8583bcd1c7cb9bb4bb6bcff803b0a991912b8403a63c0d997761ff77295ccc357d0292318601a8c61329ab28fed7bb83 +a1f9aa0523f1dff00023a44a6c3a9e4e123be0f6722a1c6682ac3c6047efe9e62f4773daf4767e854e1fcbf8ee7339e2 +85f65ebcf5c7e574174b7c4c4166a9a5368e7986b8c0ef846c2e13b75dea7311a87483503149ebfb3cb839b3ef35c82d +abc55eeb72699031a367b9675a2b91a8434e1f01467660903ced43a0b2a11a85ebdf48f95c13ff67e4e2958065a50ff3 +a4ff77c9b86939a15647499b9412417b984bfb051e5bf27b35392a258a5dac297bbdbcf753a4be6729ffb16be924a2ff +af0d41c15b5172efa801cc85ed101b76844dcd06712d0d21160893235a2dbedd15d187a9b31cf0d0ca6c14de6ab2b707 +92661339199f18e5dd9a210783c1d173a26dfa315bd99a33d6f04bf506c871a2b47745c1909faa209d5e6c5c645124a4 +b35813dafb52df709dfa47982bfb44e1bf704f9f46085b2a0e92511dff90e5597110f614f8915830821fc5ed69ae0083 +934a05aa713fa276a4d47f1a28ef06591e5a9a69293c1651c223174df0af4927fc9cd43d374d89c1b4f7c8dc91abe44b +8f83a0ef05202c0b7170ac96f880135e2256fdf8964dae5aed5dd0f6452a6d8e123321e8c182b3aa6f1f8ab767caa735 +b92db10c21c321cf1349fd34129d7180e5088daf2bbe570de6427299aab68992c011c2e2939a44247396f5427c1d914a +95ce1892d1ce25ef2bc88a23880055a4d829a3b31f3806635fd49bec32cca4e965b129b6dd3e90f7e3a2eb293ffc548d +970cf816ee7501ade36b0b59f87c7e352957f67f1f75bbacd8ed52893f9fc40572c76f49c23db44866af7e34a63cd3f9 +a2fcd08581d3569fff699fd7ed1ede5f98f2b95956ecdf975a29af053d9f4f42600b3616ad6161e958c3ce60139c20a4 +b032688b6cc8a7e63dcb82694f71f087b1ee74c4d5fa27323b1ead3ba21722d7fc49eda765725b5553db5260005049c3 +b0b79e4329f1ad25ef6a603390baf889757cab5af10bfa6953a61f89aaace0442b9ef08e57ba778f1e97bf22f16f0ace +a2e6ac06f8973266cd0df447f82cec16614df65174c756e07f513e2c19aa82c10d8670047860960cfba3c5e4c42768c8 +811e66df0f3721a1ae0293549a0e3cd789f93fb6be2cab8e16015a6d52482af9057b1b75e9456322a5a9e87235e024cd +8744a80b3d9e37da4c50c536007981a4958d7e531cb93916dbf985cdc22f4ff482a5cc4fe50915c049d2de66530f1881 +b20b6e8c7be654c23c8ca440be2c37cf9cc9f4e81feedfd0cd7c56f37eda8f295fe5d415e9bac93d5f0a237edd8bc465 +b33fd84377f31f7819150d464b5eb3ef66e06cb8712665cf0587d61e1b1c121d11cc647f3753bbc18604941c77edbc1f +83acb8a3ec5f477b6d44cd49f9e091bc2bf7c9dfee876cde12075a7db9262314cb66ad2e7557114e0c19373e31c6eff1 +acfe4172327832ee207eb07da9cd37da3b009c776f7a8290529f0249f58da213254baddc7c3074fbaa1d226ba1e52b7c +81911b4dea863424b9d77a981987732382702e0294d8c8e1ec48e89678ecb0e64836b45205a120885fa8f8a3a4b9d4b0 +b11f61b1302579a11077bb2f1f0db371ab943573b261be288dc76172eee8a5102b992a5b526092d160ffd20aac2d4856 +ab491f7f1e002a44944c02537f365e525ebb6d5614bba8e5e8e8bd12064c702a1759571ddbeee592a0ba8b73cfce8810 +89211da3d92aed6b111de001b8b5a9231a1c2d09fb1cd2618ec457b635a6c8590fe119acca42fce76dce791c35b889c7 +a5f076c8f7164bcab8af59021ef97a0afa93d0877e52241c3ff5a9a9f81227a55c119ed6a84d34b196e94ec851ca5ca0 +80d91417d0d6c1adb5a3708165da1d54a83caaff482a4f65abf3fb335cbbc738c74ed19a8c451ca98befdf9b2d8b5f90 +aecba33a67f66401614eec5fa945e763da284edb9dc713bad4ac03972630781a09a3e2a291aac0605a9560c5f3444de5 +8a0aa1320bf5217a049b02ad02a4f892bfd6a3f5b48f472041d12f3aaab8dd197307f144f9de5f9e762c6b4971a121b4 +a4120a569e446fe4129f998e51f09c1cc7b29dc2b353d6f6f05daad1a4ef99acfcbaa4950a58aacf7ee1b3fde0af33d0 +aff71370d58b145758a5f24cf3c0c6667d22a1f950b8137c369fa845a5265cd645b422f24fa95e1cd7db1d68686120b6 +a839f075a8a702809a51fbc94595eab4f269a2e7a027aa1f4fc472e77f586138bf5aa4e5570a560e139eb6cda4cca161 +9484f1caa3e35cda0e3d36e43aff3dd8cf45a5a51fc34aafa3a63ed3543047ba9d6af2a9bc7c201c028499e6b4c41b28 +84ddb374c5c9170903bb3e1054fad071b0a147a9ca2ebe2fdb491ebb2431d53b398872a39cc385f973e38579d8e60158 +acaad8babaeaeb52c5b5a16ae689fa5ae15846f2d1f3596a52371bd8681819603822ee8d32ab8cda1bd5290d601e483f +946b69ca5361b60c3dc31db13669b05e5c0452f3c80e7e185f9667a36f351e9ed83bcb5c6dd2439ecd4490e3a87d260a +99f457221ac40df86f9b4bef0bf8812720b2f7218273a0aab08c4d4d4fb18a0fb0ef6ba9bf7fa53c116cc6f16742e44f +8bc0e812d8b718dbe48ead74a6bc7bac68897d01d097422be04110a25589bacd50d336d2c8b70d0dfde6c1b8bc372dc3 +895d118dae2fb35a4b0de22be0d000ec0f0f317b9494db7c12f10d7db81b6f3eaf6d6f3fdfe952f86ec4143d7469368d +893bf3d7e579e800526bc317438a69590d33759931830daf965cec721baa793ea335e9624a86b84b8fed5effc3e2bbac +a112d30dda88c749ca15d6dc65bcbc7fe838b2d25329d44410a9a96db195c7ce6a6921196a61ba7c9d40efdb101a164d +b88b5340af052fc3b8e1a8cf7532206801e79d878f1fb02b32ac4f8e91b64e0ec9252d808b87c4579de15886a20aaef1 +865f76475bb5da18c6a078c720c7b718e55d310876c98017c30ac31882ae347258b508ec34001918324250241d2df5b7 +b6d8a15913eb1714061d5cacbd0bb05edd83ecdb848a89b864e7411598e9f7814d0c039ebe4735437c8370d2ff183751 +a95fedce8351ae9c24d7fa06ebc5cd4e3aef87afaf04a7150e561a6a7f2347bdcec1e56b82d6e5f597fe7124f6cc503b +8526004ca0c802b073d50b0902ea69975949e7567b2e59ca2cf420bc53d91951d26096f2abb07a2955a51506e86488dd +99ccecaab68b6e5adadb9c848cb577de7e7ff4afc48d3b6b73bc0872730245b8a1c68cebf467074af6756d6226f4f4a7 +b5497d5c0cd79b7e6022e295642e1f2161254379eb78ef45e47f02c84ef5a3f6b6297718e4fac8093bf017287e456917 +b6943f30012b2093c351413c2b1b648afc14a5c4c0c338179d497e908451d2779919fe806181452ed386c1e8f8e8c25c +afdb56ce89bcd3247876c918cad68aad8da65d03c7c73ccbee0c4c39f3ad615aab87ffa0db5b3b63b4cc915d0b66deb7 +a44659d7be2f11d4d4949571d7bf84a6f27f874d3281edc34ef1098d321a4dcad9a42632b39633f8f9d20a39f54a2464 +a3e489b4db5832280dd58c62120262471b6fb4355c2ad307bd17c5c246b3f1e1b00f925930f5f5f6987de234fcbb7d16 +87a4e3a190340ed4949597703083d338e9c17263ba8a39b67100589f0dddbc420d9557f9522c17c71ae04b76876f8db0 +a35a3978e928eaac8c182a0a613c611ae7b4827c5e999f938eed06921c0294befdc21d02e68d035a2fc8d03c82641126 +a6898d90265dcf0fb215629f04b07c7918e022667583efe0bfe02f258b446954876c6ca9e369ffe1bb079e2314ebda32 +922fc52e648b6b2b6768c079c67ab425da72907a46add801715f8a2537280869d7071d527b833aa63ef562ce059a392b +8acbb7c4297196d8d1c131040c34cc7064656a148c2110b19c672abb094b1d084fafe967f7122ba9dd1523a4eaec3b42 +82dbf2cdd581fe3b81b156792228eae2485710e6c21dd5fd14614dc341bb0afbebbc0f32340eda9f094b630afcfc17e8 +907a095dca885da219e4558e9251ec765cf616e995c61546bc010963bf26f2d8adbd9b2ef61f2036e1740a627c20fbed +a7a83f849691d04640137989a2d0c90a7ed42a42b0ad328435d7e1fba557a27a58eec9170ab3d0099ec97da0c950765a +b7d435a801c2a5652cb479027f2c172eafa3df8ca0d896bbb9d49a42c42660fb382a8439bfed09ddf7e0214cb6066761 +8bc6b5e79af5512589f90de8e69bc858277055cf7243f592cc4edd193f03f71d16c9300097ddafb79752c63f135c884c +913264fca800467bee58a429e1f245ef303f5dbeea90f0ce6bb3c7ae6d1bd0f99ea75d3d309634684d2178642c81b5d8 +83ba558f9c23b785a123027c52924a1d7334c853a6165d4f5afd093b0b41951a36860ba0a20fa68f73d7db9df0e3ef38 +875b2df7cb54ecdf7ba31181b9dc7dbe02761ab8ffb61757d42a735c8e20d44bad5b904e76dcec6bb44883fdb9f4ad84 +af3dc5d2dd29565de8f4c700d5f1ab71dadb4351f06e9ee2eb5ee7a9b5da827d0c6726c6dc780748a26aa3b4d10e6c2d +a113ff09296b25f550f6d0d3f37dd4517b14cf6d5517293bd3068aa3aea765a8640fcd4bf0ba96db5c00167267fbd574 +a138c5cca485b9180ef091c9e327982bea203c165cb83564f416c36e813bea1ef1f6345f57c8a591df360541b7b758f5 +85793441e917ed520d41dda6e762269fb9f9702e5ef83cee3e90652d324536bf4233425cd05b54a383609076ab84ea13 +b422ac9de53d329e6321a8544c264d63cffc37965d627d7e180a999c3332644e21fedf10cd2f43cf6ba4fc542db91155 +a85d31d4bfa583a493681e57bfccca677ec5b85870a53de37f7be7833b573f8c8dcf029cea4ae548d83048030d77d56d +ab8a0702a371db496715a4ee8fcb6d430641b0f666d7fe3ef80c09df0bf570293cec1aa1675381c6bbd9ecc1f7cdccf9 +b308ef2b87438d35957191294782e9f5014a3394fadad3e2ccaf6ebf20fd889a36dbb8ddb3634baa8e2e131618aa4e70 +919e972e5b67cd65f377e937d67c27b4dd6fd42cfe394a34a70e8c253a1922f62ff36b9dcc7fbbc29b0960ad6a7fde88 +a0e4d4be28301af38a910971c8391ef3ec822ce35757226a7fd96955cd79afa14accba484ef4e7073e46b4b240a5863f +9422f6d424c1736b4b9bb9762aa62944085e8662c4460319dac4877b1e705aa5cd8b6b3a91268363ec3857c185685f4b +b7cf9f2053119d284a37df4e4489b632594df64e5dc846652ee26b4715e352e6333118b125021481138e4ec3e9f9987b +aea983e81c823472df8652654be8a60a8bf40147d599f87e323397f06bf88c98e9c6db0f28414f6ea4091f3eb0f6a96d +aa20bf03cd8b6ffda09fe0ef693fc0aaa3bb372603e786700e52063a4f7ee742771c41cf5e67e6248f99b7fc73f68dbf +8748a4978198071d7d5ddc08f8c8f0675d895dc19df0889e70bd86d44c469c719b93f6526c7e7e916c7bfeb9a1379aaf +b8fcd863d55dab2f7b1c93844306e00056ba17338ddfa3f02689a0b58b30239beb687b64c79b8420ecea8d0d082d9ffa +abb1a35952dc8a74dd1cdbc8ae7294c6bfd1910edab6f05c879e9ed06c636a949fe0017ec67f8f6f73effcb5817cccae +8bef43422b1c59e354b7f46c08a8eb78e26c4d01c236a4fe781cefb7465293a4444f2bdc68c6a221cd585a2494d9a1d7 +93527258940feff61befa18fcd6626fcff019d34a3ac8c6886599cbef75b15c15d689e8c1bd2177cc93c4c1792dee8d7 +b7f114eea99c8278841180ec8886ad2bab1826554a1657b9eeb17aa815f31b59c3931913ddec40aa9923bc92f8975635 +91a96446158b194a0a6ada2e37c8a45f3017c34034f757245f6f3b98c65d39d084e74d2a9dc271e5918faa53990ec63f +aea4ada0a853753db03f9790e20bab80d106f9b09e950f09aeaba5d869f0173bed673b866a96d6b0dd8123a539caac9a +b8e3e98ff0d3e512441e008a4a6783233045a4639e0c215c81984846b43ff98de99d7925cf717b1ca644f6229b6d16a2 +8987ef81a75213894e11e0310e8ba60fe06e2b264cc61655e5b51bf41cc8c3d6c10696642ea3517770f93be360207621 +8d4eff7335252f74af4a619c78625fd245df640f2086338dbb6c26b059f83fe70f3e81f5b6c12d62c0f784e572d56865 +a56f6389b0bac338f20c615d7d11e16045a76cbea23ced0a9d9067f538421c378200bfd4523b7c96094ab67f47f98d42 +83f5ab0727fd6ce8b3370ce3fac1f3a9c1930ea7ebbd16be61cc26f34aa1291ba4b5f16729d7d4f5924eaa4a1e31a04e +8cc62366874bf8751067a526ea32927584cef41174e2ec5a53079ee557067bc282f372b831cb2547c5e21a2f178c91b4 +b609e141006dc8d8649457efc03f8710d49abb34bc26a33ed4e173e51b85d7acdf18d74aed161b074f679d88f5aa2bf3 +873c7aa784c17b678443320950e494250baff8766db42619b9fc7ec4c3afa4eee290cd1f822b925d5b9e55c9cdd1af2f +859ba787f052d3665481c3dd58159ec8c238d918fb6d2787ebe275ef9acd377cb7aaa03a69820c78247bf51afee3d5bf +8eb1e6d2b0f51a3275b4a8be96957cb2d518b32c815dc0dfd5f75340c7dee73e5edc45db7c7d375c4ffaf8c59767d0c1 +85f3876ff5edbb826a9592e68db3dcc975725bfdda4fcac197758a8b27e4f493e6c531b1342ba0f5a75f965273720345 +8a1272f2678d4ba57e76c8758818965e6849971e8296b60ff85a522feeaaa3d23d3696c040d8bdaf1b380db392e988aa +85002b31ce31be7cc8757141a59a7cf9228b83144993d325b2241f5bfac09a02aca0c336307257f1a978c0bbf79fa4fe +b96bd26a6bbbc705c640285fd561943ef659fca73f25e8bf28cfcd21195752b40359d0edca0adc252d6e1784da267197 +936cfe367b83a798ab495b220f19cfe2e5bde1b879c8a130f84516ac07e3e3addcc791dc0e83a69c3afc225bed008542 +b1302f36190e204efd9b1d720bfaec162fcbba1b30400669dbcdd6e302c8c28f8b58b8bbde10f4512467dd78ed70d5e0 +8291b49f56259c8d6b4fd71525725dd1f35b87858606fc3fe7e048ac48b8a23ba3f0b1907b7c0d0c5ef6fa76cddc23f0 +97aca69d8e88ed8d468d538f863e624f6aed86424c6b7a861e3f45c8bf47c03e7b15d35e01f7add0a4157af171d9360c +b590d896e6b6f2e4dcffebfa67fc087fa518a9c8cb0834a5668cabe44e5c2b6f248f309b9cd74779030e172dba5d9e29 +97e7099bff654bcb37b051a3e8a5a7672d6ab7e93747a97b062fc7ae00c95deef51f5ced2966499217147058e00da4be +83435b739426f1b57f54ebad423939a68ad3d520db8ca5b7e28d1142ebfb4df93f418b180a6c226c0ca28fa0651163a0 +946c9144d982837c4dbc0b59544bdbc9f57e7c9ef0c82a7ad8cfddea78dedc379dbc97af54ba3ac751d844842a2990a4 +90ba1eff9c25adba8c3e6ef5b0d46c13de304632fec0646ee3a7bee69da2bc29e162dd3fb98a37ed1184ae5da359cf0a +b17b7a5c0a48eb9784efb5ff8499230b45efeb801cf68e13fe16d0d308511af5aa60e3b9a5610f96d7c2242ae57d455b +9991245e5617c4ea71575e5b2efe444f09cbbed13b130da08f8e9809d62512e8298a88d41f6aa3dbf3bcbc90654ceb18 +a1190c4cbccf2898a7fe025afd03f8652973a11cef59775fb47d69a6b4dcb9a5a0c554070421a5e10a75e43b63d37b79 +857c0a5f291eb35a76be11543a8c3d798187bd0717e2cdee50d390b66322d0d9529520fd3377136cdc93cfee99b6403f +944d11e5f9a3493c67786df94f129352d892fbdc43e98206b8dbf83cce240f65305e1768b38e5576048a31dca5c18f31 +818f361c5dae709e067a82b81beffbd9674de8df2bc1bfc3a27ddf326260e124e46b1e36697fb8de539b7736db093e9e +b07f5b737735a0d628e7ac2d335080b769bdb3acea38ad121e247a6e4307916ba1d029da5d341f079ea61eeaf7d8554e +a69e338803f3ee0fbbddc7ee481a13f6b64d25d71bae0d76f4b5145b54923cf1616c77ba0fd9ca37a3ae47208f490423 +acaee66b94e226622e28a144f93f6b1b442b9c79d7a8a1740c4d53044d0675a661e7453509b9e716e469fe11ce45ee31 +9402ca799d2e1cce0317ed49453ee0b2669b05e68ff101b89306db215c3941b3786ad3402d00369cb1dee020b56d3142 +849440c539fc0df3c8d06e23e271e6faa50234d5c057b8561e9376415f4396e548351cc677b0abeafe4f51b855a3dc83 +865b99587eb3dbc17e412647673f22b2e89185d1df1ec8ea04515585ad2edfb731be458123118dcd7b41b475026477b9 +9390618833b5adbaf24bd38cf9fc6f25104717f314259bb4da5c7a1f6963ecdc04d07bed391d8cd765c3d53567b2b6b1 +95383e8b1d0a629cec238b5ae2bda236a027f4e3b5f99ceace05f1d5a781ec1e7a43058f44ef0a5aee6b0db5697a0d89 +91739b8946d90db3a5244f7485295cc58143ba0449c9e539df1ba3c166ecf85ff914c9941192963c32d35033ae2f0980 +b5d88848d856d882db5947b9182025f0abf2bc4335b650fa0a48a578e2c87f32cc86d42d3b665ee2eab46d072bf1eccd +91f4c754549f5a53b1902ef84274ce9acf0bfd2e824e62eb127d67e3214ce05fc2430c05ea51e94dc6e8978f5d076bab +91fff8c75f8ad86afe78ec301de05e4ca71421d731419a17c747a9a0bf81129422c9499e4749107b168d1695dc90292f +99fbd7bede9cc1e2974c2a21c70788960c2dbf45a89552da8d73bb1d398b8399590707f2f4ba4b43cb356e703eb01b5e +80a51cd83e3d748c07b9ac82de1a697b09031e3edc7bf585f06cd0ffa8ea319517fcc2b735614b656677b54b4910814e +886b27de1f93311d1a31b6d698aa28b54fbd800decd8e25243d89e352ee38cb252d5648b5134a3e1ed021bae46e9da48 +976e70c94db905f83b4ef72188d840874bf005814c0c772f3832aa65b1f21927403125eea7a07b6d3305b1a781b36ab7 +b4adb9d1c49eb31462583580e3ffa625bea4f8b2a7d4927e4ff925c1759d4b3c1e43283d635b54fb0eabfbe1f4c12992 +b66b466bd48485ebeedd47e749d86cbaa3deffbbee2e69cfaa5e9f3bd28b143d7c1c0255a7a1393a2cc1490b2c485571 +8bded5bc0794513947ddb00ff6b780c5cc63a74e2a0b0284153c346a31c82e1eff07c073939da39e6f87a06c14ff1a80 +aceea8c6f799589f6b7070abf69fec724e6679514e60f1eaf9a52c37e9cebb72abcc833a81d8da1a4f5194c1a7eeff63 +89a9f76d053379687fd221ebcaf02c15c2c241bb673ef5298e32640a115d9e0f2331c3e185572cd65946dd6c5bd42412 +a57b6f1e3fdd92eadc6220760f22d0685a82cada1c7a1bda96d36e48e2852f74f3a83c757dd8857e0aee59e978da4919 +9106cf0891bb39ce87433c5f06a5c97a071d08ad44a7cbcd6918c0729c66bb317fbbee8aa45591cee332ad1234c7257d +96c18cca4a0f0299e0027ff697798085f9f698a7237052c5f191b1dba914e5a015ae356b80c17f0fdd31d08c5a939ebb +a892103c93df126c024825c07d8769bdac5f1d26ea9509ee26530dc594384b2a5095cc34e0b41ab3db0392a29792c9e8 +b7c2dbc95edb6fc25802ea051803b7bea682f87a99f8a9fdcc3091c81d914b9493dfb18a8894c964805298a6c22b07f2 +8e40948927d560a6840d7fb99802989ce72b43693e9dc7ed9dcda4bca7daedf75271cf656bcc22b3f999a550faad8648 +b354de1c6f0603df3ed9036c610281e55b51a48950ee3ce57a00b4692232de7ca57d19722700e15cbe67a91fcec2f786 +adf987b90737b933436d8036c1d3f0c9104f26c540052e22e703964f72739ac1261e4289b8f27dec47281a0f3f51378a +8ed5248e9c836fffa7c924178db593e1aaeb54bcf2e93c1983c1f3899cad538deeb2b836430fddc9b2f283e0797ea11e +907e5410e3bd5d7f55340e2f497bd1ca10bfcb4abed2c66a3cdf94dc40bbd7c43ac98754e0b4b223ea4c61eebf2f27f5 +8e81b441ea0397db28840fb4b3c3bfe6d8e31418816f7bda36f9c1cfe4556daee30c43639d90a2dc9b02a3d65e5f4ab2 +897085c477f5030f9fed06e181b05953a8cd2001d959dd6139738d40f1d673b2c7120b5348f678547acfdc90ffc9fcc6 +b0bf2784c4b3808a04be5a00a0593035ce162b3886e1500247b48365eac8ec3d27c7e5e6372e030c779c75fb79772d0d +af3fe6c75f2a1241ac885d5091ff3882cf01695d957d882e940f0c31f7a5b5e269c1a2bae7336e9a7cda2b1d23c03bd1 +a6d94e065f85736d77080a4f775885ccb0dd5efdbe747e4595280bca0ebe12450257c1beadcbec77566ef57508c5d4df +a5c50fe56b5532bf391da639a2f2b6cbb2634fc6637416fea7c29a522dea024d4adaaa29b6d472b4d2cc3e3b85c72e2a +afc35f5a03b245a6286318ef489db05d397bbd16c17b4e92eeb56509f875246c0176c01804139eb67dc4247c2a36ff9e +99ba14ab5a9612c078f9bbaa0e68fd1d52ecceb2ed19bd9abf8f98dd4ed1f9c4fa6e4d41bcef69be2ff020b291749ca8 +8018cdd3d96f331b4c470a4c3904bed44cadecbeec2544ca10e4352cf4ae1a856cf55f6383d666bf997ad3e16816006e +a9964790c318bb07b8fe61d230dd2161dd3160e186004647a925cfec4c583b4e33530bf5d93d8a14338b090055085b05 +ab89d8401df722101c2785cb3ef833017f58376ee82cedd3e9405b2534f259bb76063434a247652c7615a6de5194de65 +a72c3d320a0d40936dee8edfb36703be633aefbb8f89530df04eb6aebe0305ef4f4b6709436f8036d417272a7e47e22a +b3457661ad62634cc25e2918921a97b0bf5c59ccc7063bc8eb53194783f07659f42f8978c589228af5b12696588d8b2f +926fa35cd3ed4c8ad78af6284b87ae53b2e25a1ff50398034142a2bbed5b989ba3181ff116838931742c0fbcd8b8a56c +ae57fe506626432f27ae4f8791421c2df9efd9aaabe4b840ccf65fc3d0dd2f83e19eb63ae87bfa6898d37b5da869ddb2 +99c0a26ac74211db77918156d7ae9bea6ecf48da3ce9e53829a9ad5ed41321227c94fbd7449ae2e44aae801811552b1b +abdd2635b61cb948e51b762a256cf9d159b9fcb39b2fb11ba2fed1cb53475a03fc6e024a6a824a67a689396119a36a7b +a5ca98b98da8bb8eb07b1e5e3c85a854db42addefacd141771a0c63a8e198421dccc55ef1d94662ca99a7d83b9173fc3 +a821bb5cf1eb3aeae6318c8d554e2ea3137d73bb29d2e4450c9a33f441355ea77bb0e0e0ce7c819abc3ed119110a3a92 +95cdfb19b3f7196c26d60586e2c1efaa93352a712f8c8ef6209f6f318cecd52d7bebdfbfee4be1f5903a1595f73bc985 +aef6e6a400106e217f9888afcef0a1e1299b59017e77dc5453317dec0c32ae96873608bef3f1b504a7e4f45b06edc9c6 +96399ad093299ba26dc09ae85dbec9a1801dea4a338dd5d578bcdcb91246db0059e54098ba8a56cbb24600a40095cf79 +ad8b018ac99857ad4b38bdf6d110bbef64029a4d9f08df85a278c6ddc362a5f64e1f3a919f798ccb2f85a7f4ca1260b4 +b211f3b5dd91941d119c4fe05e2b4c7bb0ce0a8d7ef05932a96e850f549a78cd20cded0b3adb3f9f8b7058889ae2cb4e +ab780dd363671765c9c9ab0f4e7096aacf5894e042b75f40a92df8eb272a6229078cd6eadcc500eead3650860aa82177 +a4d96b16ab3abe77ead9b4477c81957e66a028f95557e390352743da53d1a7ba0c81d928a7ea8bc03b9900135ac36a6a +b4d4e028099bf0f28ac32141cd8de4ee7c3d62d4f519fad6abbb4ba39592750812220a4167d1da4c4f46df965f7cf43d +aa929c5f0bd8cb44a861bfb3d18340a58c61d82afa642447b71b1470a7b99fe3d5796bdd016b121838cb3594f5a92967 +a038e66f0a28aba19d7079643788db3eed8e412fb9ab4c0f6cacf438af4657cc386a7c22ae97ccc8c33f19a572d6431c +89c1ff879faa80428910e00b632d31c0cebb0c67e8f5ded333d41f918032282fb59fbcbe26d3156592f9692213667560 +8d899072c9d30e27065d73c79ce3130a09b6a4a4c7d9c4e4488fda4d52ad72bd5f1fd80f3a8936ef79cf362a60817453 +8ffb84a897df9031f9a8e7af06855180562f7ca796489b51bb7cca8d0ca1d9766a4de197a3eb7e298b1dfb39bc6e9778 +836ebd0b37e7ef4ff7b4fc5af157b75fa07a2244045c3852702eaafa119ca1260c654a872f1b3708b65671a2ece66ad2 +9292dfd6d5bfc95f043f4eb9855c10cbcf90fbd03e7a256c163749b23a307b46a331bdbd202236dca0e8ea29e24906de +8bc37eaa720e293e32b7986061d2ffcbd654d8143e661aabe5602adc832ab535cffbe12a7b571d423675636a74b956e4 +887455f368515340eb6f9b535f16a1cf3e22f0ceda2ead08c5caefccef4087e9f4b5d61c5b110ff3e28e4ab2ad9e97c5 +a6e5ec36e7712056fec00de15b8696952b17891e48ebe2fa90c6f782c7d927b430917b36b4a25b3d8466da3ca2a4985d +895cae36ba786104ec45740c5dc4f2416b2adce6e806815e3994e98d9e1be372eaec50094fbb7089015684874631ab7e +9687444fe6250c246b1711a8f73992f15c3cac801e79c54ffd5e243ad539fdd98727043e4f62d36daf866750de1ba926 +b17f75044c8e9ce311bb421a5427006b6fa1428706d04613bd31328f4549decd133e62f4b1917016e36eb02ea316a0ca +8538a84d2f9079dd272a7383ff03b7674f50b9c220e0399c794a2bcb825d643d0fc8095d972d5186b6f0fe9db0f7084f +af07b37644cc216e7083bac1c4e6095fa898f3417699df172c1f6e55d6c13c11f5279edd4c7714d65360b5e4c3c6731e +87eed8fe7486c0794884c344c07d3964f8fc065aebb0bb3426506ab879b2e0dfaefa5cece213ec16c7b20e6f946c0bd2 +8a4bf42f141d8bc47c9702779d692a72752510ef38e290d36f529f545a2295082a936c8420f59d74b200a8fff55167c4 +a7170e5e00a504a3b37cb19facf399c227497a0b1e9c8a161d541cb553eb8211449c6ac26fe79a7ff7b1c17f33591d74 +a9a2cc7232f07ef9f6d451680648f6b4985ecab5db0125787ac37280e4c07c8210bab254d0b758fd5e8c6bcf2ee2b9ff +8908d82ebfa78a3de5c56e052d9b5d442af67a510e88a76ba89e4919ae1620c5d15655f663810cfc0ee56c256a420737 +a9d47f3d14047ca86c5db9b71f99568768eaa8a6eb327981203fdb594bdb0a8df2a4a307f22dcea19d74801f4648ea89 +a7c287e0e202ebfc5be261c1279af71f7a2096614ee6526cd8b70e38bb5b0b7aca21a17140d0eddea2f2b849c251656a +97807451e61557d122f638c3f736ab4dab603538396dca0fcdf99f434a6e1f9def0521816b819b1c57ecdfa93bd077eb +a8486d60742446396c9d8bc0d4bed868171de4127e9a5a227f24cbf4efbbe5689bbd38f2105498706a6179340b00aed5 +a03b97c2a543dfefa1deb316db9316191ab14e3dd58255ce1027b4e65060d02fb5cb0d6ac1a2bf45bfeac72537b26429 +a7d25060f6861873410c296a4959a058174e9a1681ac41770788191df67fc1391545dab09de06b56cd73a811b676aa1b +96bb9c9aa85d205e085434d44f5021d8bbafc52cd2727b44e2a66094a4e5467b6294d24146b54c0d964c711e74a258d4 +b07b17f11267e577191e920fa5966880f85ff7089ac59d5d550e46f3a5cdadd94f438a547cd1ec66f20a447e421f96c6 +964e33e1571c97088fe7c8ca3430db60a8119f743a47aa0827e6e2fb9bae5ff3bf6cecd17b11dd34628546b6eb938372 +82a0513a05870b96509a559164e6ff26988ea8a2227ac6da9adc96fe793485a9eb6bdcab09afac7be4aef9a5ae358199 +b1185bc679623e7a37a873d90a2a6393fb5ccc86e74ba4ba6f71277df3623cde632feae4414d6429db6b4babde16dee0 +b3d77504b7032b5593a674d3c0cd2efbf56b2b44ed7fe8669f752828045e4e68202a37bf441f674b9c134886d4cee1df +95ab31749ff1f7b3f165ce45af943c6ed1f1071448c37009643a5f0281875695c16c28fc8d8011a71a108a2d8758e57d +b234dee9c56c582084af6546d1853f58e158549b28670b6783b4b5d7d52f00e805e73044a8b8bd44f3d5e10816c57ecc +86da5d2343f652715c1df58a4581e4010cf4cbe27a8c72bb92e322152000d14e44cc36e37ff6a55db890b29096c599b9 +8b7be904c50f36453eff8c6267edcb4086a2f4803777d4414c5c70c45b97541753def16833e691d6b68d9ef19a15cb23 +b1f4e81b2cdb08bd73404a4095255fa5d28bcd1992a5fd7e5d929cfd5f35645793462805a092ec621946aaf5607ef471 +a7f2ca8dacb03825ef537669baff512baf1ea39a1a0333f6af93505f37ed2e4bbd56cb9c3b246810feee7bacdf4c2759 +996d0c6c0530c44c1599ffdf7042c42698e5e9efee4feb92f2674431bbddf8cf26d109f5d54208071079dfa801e01052 +b99647e7d428f3baa450841f10e2dc704ce8125634cc5e7e72a8aa149bf1b6035adce8979a116a97c58c93e5774f72b7 +95960a7f95ad47b4a917920f1a82fbbecd17a4050e443f7f85b325929c1e1f803cf3d812d2cedeab724d11b135dde7a3 +8f9cd1efdf176b80e961c54090e114324616b2764a147a0d7538efe6b0c406ec09fd6f04a011ff40e0fa0b774dd98888 +b99431d2e946ac4be383b38a49b26e92139b17e6e0f0b0dc0481b59f1ff029fb73a0fc7e6fff3e28d7c3678d6479f5a3 +a888887a4241ce156bedf74f5e72bfa2c6d580a438e206932aefc020678d3d0eb7df4c9fe8142a7c27191837f46a6af6 +ab62224ea33b9a66722eb73cfd1434b85b63c121d92e3eebb1dff8b80dd861238acf2003f80f9341bfea6bde0bfcd38c +9115df3026971dd3efe7e33618449ff94e8fd8c165de0b08d4a9593a906bbed67ec3ed925b921752700f9e54cd00b983 +95de78c37e354decd2b80f8f5a817d153309a6a8e2f0c82a9586a32051a9af03e437a1fb03d1b147f0be489ef76b578b +a7b8a6e383de7739063f24772460e36209be9e1d367fe42153ffe1bccb788a699e1c8b27336435cd7bf85d51ba6bfdd6 +937a8af7ed18d1a55bf3bbe21e24363ae2cb4c8f000418047bf696501aaeec41f2ddf952fd80ef3373f61566faa276a9 +ab5e4931771aeb41c10fa1796d6002b06e512620e9d1c1649c282f296853c913f44e06e377a02f57192b8f09937282eb +893d88009754c84ec1c523a381d2a443cb6d3879e98a1965e41759420a088a7582e4d0456067b2f90d9d56af4ea94bba +91b2388a4146ebaaa977fec28ffbfb88ac2a1089a8a258f0451c4152877065f50402a9397ba045b896997208b46f3ebf +8ce0523192e4cc8348cd0c79354a4930137f6f08063de4a940ea66c0b31d5ea315ce9d9c5c2ec4fa6ee79d4df83840dd +b72f75c4ab77aca8df1a1b691b6ef1a3ff1c343dd9ed48212542e447d2ed3af3017c9ad6826991e9ef472348c21b72a4 +af0fa5a960f185326877daf735ad96c6bd8f8f99ab0ab22e0119c22a0939976ece5c6a878c40380497570dc397844dba +adf9f41393e1196e59b39499623da81be9f76df047ae2472ce5a45f83871bb2a0233e00233b52c5c2fa97a6870fbab0a +8d9fc3aecd8b9a9fca8951753eea8b3e6b9eb8819a31cca8c85a9606ce1bd3885edb4d8cdbc6f0c54449c12927285996 +901969c1d6cac2adcdc83818d91b41dc29ef39c3d84a6f68740b262657ec9bd7871e09b0a9b156b39fa62065c61dacb1 +9536a48ccd2c98f2dcbff3d81578bbb8f828bf94d8d846d985f575059cd7fb28dfa138b481d305a07b42fcb92bacfa11 +8d336654833833558e01b7213dc0217d7943544d36d25b46ecc1e31a2992439679205b5b3ab36a8410311109daa5aa00 +95113547163e969240701e7414bf38212140db073f90a65708c5970a6aaf3aba029590a94839618fc3f7dd4f23306734 +a959d77a159b07b0d3d41a107c24a39f7514f8ce24efa046cfcf6ace852a1d948747f59c80eb06277dce1a2ba2ec8ea9 +8d2cb52dd7f5c56ef479c0937b83b8519fa49eb19b13ea2ec67266a7b3d227fb8d0c2454c4618d63da1c8e5d4171ac7b +9941698c5078936d2c402d7db6756cc60c542682977f7e0497906a45df6b8d0ffe540f09a023c9593188ba1b8ce6dfcb +9631d9b7ec0fc2de8051c0a7b68c831ba5271c17644b815e8428e81bad056abb51b9ca2424d41819e09125baf7aaf2d4 +a0f3d27b29a63f9626e1925eec38047c92c9ab3f72504bf1d45700a612682ad4bf4a4de41d2432e27b745b1613ff22f9 +80e3701acfd01fc5b16ecfa0c6c6fd4c50fe60643c77de513f0ad7a1a2201e49479aa59056fd6c331e44292f820a6a2c +a758c81743ab68b8895db3d75030c5dd4b2ccc9f4a26e69eb54635378a2abfc21cba6ca431afb3f00be66cffba6ab616 +a397acb2e119d667f1ab5f13796fd611e1813f98f554112c4c478956c6a0ebaceef3afae7ee71f279277df19e8e4543a +a95df7d52b535044a7c3cf3b95a03bafd4466bdb905f9b5f5290a6e5c2ac0f0e295136da2625df6161ab49abcdacb40f +8639fc0c48211135909d9e999459568dbdbbc7439933bab43d503e07e796a1f008930e8a8450e8346ab110ec558bcbb9 +a837bcc0524614af9e7b677532fabfb48a50d8bec662578ba22f72462caabda93c35750eed6d77b936636bf165c6f14e +97d51535c469c867666e0e0d9ed8c2472aa27916370e6c3de7d6b2351a022e2a5330de6d23c112880b0dc5a4e90f2438 +aadb093c06bd86bd450e3eb5aa20f542d450f9f62b4510e196f2659f2e3667b0fe026517c33e268af75a9c1b2bc45619 +860cef2e0310d1a49a9dd6bc18d1ca3841ed1121d96a4f51008799b6e99eb65f48838cd1e0c134f7358a3346332f3c73 +b11c4f9e7ef56db46636474a91d6416bcb4954e34b93abf509f8c3f790b98f04bd0853104ec4a1ff5401a66f27475fce +87cb52e90a96c5ee581dc8ab241e2fd5df976fe57cc08d9ffda3925a04398e7cffaf5a74c90a7319927f27c8a1f3cef5 +b03831449f658a418a27fd91da32024fdf2b904baf1ba3b17bbf9400eaddc16c3d09ad62cc18a92b780c10b0543c9013 +94e228af11cb38532e7256fa4a293a39ffa8f3920ed1c5ad6f39ce532e789bb262b354273af062add4ca04841f99d3aa +99eb3aeb61ec15f3719145cf80501f1336f357cc79fca6981ea14320faed1d04ebe0dbce91d710d25c4e4dc5b6461ebf +920a3c4b0d0fbe379a675e8938047ea3ec8d47b94430399b69dd4f46315ee44bd62089c9a25e7fa5a13a989612fe3d09 +b6414a9a9650100a4c0960c129fa67e765fe42489e50868dd94e315e68d5471e11bfbc86faffb90670e0bec6f4542869 +94b85e0b06580a85d45e57dae1cfd9d967d35bdfcd84169ef48b333c9321f2902278c2594c2e51fecd8dbcd221951e29 +b2c0a0dd75e04a85def2a886ee1fda51f530e33b56f3c2cf61d1605d40217aa549eef3361d05975d565519c6079cc2ac +abb0ea261116c3f395360d5ac731a7514a3c290f29346dc82bacb024d5455d61c442fefe99cc94dddcae47e30c0e031f +a32d95ae590baa7956497eddf4c56bff5dfdc08c5817168196c794516610fcc4dbcd82cf9061716d880e151b455b01e0 +8bd589fb6e3041f3ef9b8c50d29aed1a39e90719681f61b75a27489256a73c78c50c09dd9d994c83f0e75dfe40b4de84 +82d01cdaf949d2c7f4db7bfadbf47e80ff9d9374c91512b5a77762488308e013689416c684528a1b16423c6b48406baf +b23e20deb7e1bbbc328cbe6e11874d6bdbb675704a55af1039b630a2866b53d4b48419db834a89b31ebed2cfc41278dd +a371559d29262abd4b13df5a6a5c23adab5a483f9a33a8d043163fcb659263322ee94f872f55b67447b0a488f88672d6 +85b33ddf4a6472cacc0ed9b5ec75ed54b3157e73a2d88986c9afa8cb542e662a74797a9a4fec9111c67e5a81c54c82b3 +af1248bc47a6426c69011694f369dc0ec445f1810b3914a2ff7b830b69c7e4eaa4bafec8b10ed00b5372b0c78655a59b +94b261ed52d5637fd4c81187000bd0e5c5398ce25797b91c61b30d7b18d614ab9a2ca83d66a51faf4c3f98714e5b0ea5 +953d4571c1b83279f6c5958727aaf9285d8b8cbdbfbaff51527b4a8cfdd73d3439ba862cdb0e2356e74987ff66d2c4d9 +b765dae55d0651aca3b3eaef4ca477f0b0fda8d25c89dccd53a5573dd0c4be7faaadaa4e90029cdd7c09a76d4ce51b91 +b6d7b7c41556c85c3894d0d350510b512a0e22089d3d1dd240ad14c2c2b0ce1f003388100f3154ad80ec50892a033294 +a64561dc4b42289c2edf121f934bc6a6e283d7dce128a703f9a9555e0df7dda2825525dbd3679cd6ba7716de230a3142 +a46c574721e8be4a3b10d41c71057270cca42eec94ca2268ee4ab5426c7ce894efa9fa525623252a6a1b97bcf855a0a5 +a66d37f1999c9c6e071d2a961074c3d9fdcf9c94bf3e6c6ed82693095538dd445f45496e4c83b5333b9c8e0e64233adc +ab13814b227a0043e7d1ff6365360e292aca65d39602d8e0a574d22d25d99ccb94417c9b73095632ff302e3d9a09d067 +b2c445b69cff70d913143b722440d2564a05558d418c8ef847483b5196d7e581c094bae1dbb91c4499501cfa2c027759 +87cbde089962d5f093324b71e2976edbe6ad54fb8834dd6e73da9585b8935fca1c597b4d525949699fdfa79686721616 +a2c7e60966acb09c56cf9ad5bdcc820dcabf21ef7784970d10353048cf3b7df7790a40395561d1064e03109eaac0df98 +8ea7b8af208678178553946b2ee9e68c0e751b34f3652409a5e66c40d3aee3a40ba6ffe2175ce16c6a81b78ecc597d02 +960234239e1e3ea262e53d256ad41b2fe73f506b3d130732d0ee48819eb8a9c85bb5106a304874d8625afae682c34015 +858459694c4e8fdafa6cdaee1184e1305ca6e102222b99b8e283dd9bb3ebf80e55d6c4d8831a072b813c8eceb8124d95 +a30a8ce0f44aeb5590dc618c81c7cac441470ce79fd7881a8f2ea4ca5f9d848ebde762fcaee985cbd3d5990367403351 +a83867643672248b07d3705813b56489453e7bc546cdba570468152d9a1bd04f0656034e7d03736ea156fc97c88dc37f +a7bb52e0fc58b940dc47ea4d0a583012ee41fad285aba1a60a6c54fa32cfe819146888c5d63222c93f90de15745efb2b +8627bcc853bdeaad37f1d0f7d6b30ada9b481ccdf79b618803673de8a142e8a4ce3e7e16caed1170a7332119bcdc10a9 +8903d9dc3716b59e8e99e469bd9fde6f4bca857ce24f3a23db817012f1ea415c2b4656c7aeca31d810582bb3e1c08cc6 +875169863a325b16f892ad8a7385be94d35e398408138bd0a8468923c05123d53dba4ce0e572ea48fcdadd9bd9faa47a +b255b98d46d6cc44235e6ce794cc0c1d3bd074c51d58436a7796ce6dc0ae69f4edaa3771b35d3b8a2a9acd2f6736fab3 +9740c4d0ee40e79715a70890efda3455633ce3a715cbfc26a53e314ebbe61937b0346b4859df5b72eb20bcba96983870 +a44ce22ab5ddc23953b02ec187a0f419db134522306a9078e1e13d5bf45d536450d48016a5e1885a346997003d024db0 +90af81c08afdccd83a33f21d0dc0305898347f8bd77cc29385b9de9d2408434857044aec3b74cb72585338c122e83bb4 +80e162a7656c9ae38efa91ae93e5bd6cb903f921f9f50874694b9a9e0e2d2595411963d0e3f0c2d536b86f83b6e4d6ef +8b49fa6babe47291f9d290df35e94e83be1946784b9c7867efd8bc97a12be453013939667164b24aeb53d8950288a442 +a1df6435d718915df3da6dda61da1532a86e196dc7632703508679630f5f14d4cb44ce89eff489d7ff3fe599cc193940 +afd44c143dbb94c71acc2a309c9c88b8847ef45d98479fccce9920db9b268e8e36f8db9f02ff4ee3cff01e548f719627 +b2cf33d65d205e944b691292c2d9b0b124c9de546076dd80630742989f1ffd07102813c64d69ba2a902a928a08bce801 +b9f295e9f9eca432b2d5c77d6316186027caca40a6d6713f41356497a507b6e8716fb471faf973aaa4e856983183c269 +b3bd50c4b034473edce4b9be1171376a522899cb0c1a1ae7dc22dd2b52d20537cf4129797235084648ac4a3afc1fa854 +8ef37683d7ca37c950ba4df72564888bedaf681931d942d0ea88ead5cc90f4cbef07985a3c55686a225f76f7d90e137d +82107855b330bc9d644129cebecf2efbfab90f81792c3928279f110250e727ce12790fd5117501c895057fa76a484fc0 +816a5474c3b545fb0b58d3118cc3088a6d83aad790dbf93025ad8b94a2659cceba4fa6a6b994cb66603cc9aef683a5e3 +8f633f9b31f3bb9b0b01ea1a8830f897ecd79c28f257a6417af6a5f64e6c78b66c586cf8d26586830bd007fb6279cd35 +acb69d55a732b51693d4b11f7d14d21258d3a3af0936385a7ce61e9d7028a8fe0dd902bda09b33fb728bc8a1bc542035 +8d099582ac1f46768c17bf5a39c13015cfe145958d7fc6ddfd2876ad3b1a55a383fbe940e797db2b2b3dc8a232f545dc +97a4dd488b70bf772348ececaca4cf87bc2875d3846f29fe6ef01190c5b030219b9e4f8137d49ea0cc50ca418024c488 +b4d81148f93fa8ec0656bbfb5f9d96bbf5879fa533004a960faac9fd9f0fe541481935fdf1f9b5dd08dff38469ef81c5 +8e9b2ae4fc57b817f9465610a77966caaff013229018f6c90fa695bd734cb713b78a345b2e9254b1aff87df58c1cd512 +99eb7126e347c636e9a906e6bfdc7c8ca0c1d08580c08e6609889a5d515848c7ca0f32ab3a90c0e346f976a7883611f7 +8ca87944aa3e398492b268bda0d97917f598bc0b28584aa629dfec1c3f5729d2874db422727d82219880577267641baa +88ab0e290dc9a6878d6b4e98891ff6bfc090e8f621d966493fcbe1336cc6848fcbb958d15abcfa77091d337da4e70e74 +8956a2e1dc3ec5eb21f4f93a5e8f0600a06e409bb5ec54e062a1290dff9ce339b53fbbfc4d42b4eed21accea07b724d6 +8d22220da9dc477af2bddb85c7073c742c4d43b7afee4761eba9346cadbcd522106ed8294281a7ef2e69883c28da0685 +90dafd9a96db7e1d6bde424245305c94251d5d07e682198ae129cd77bd2907a86d34722cbde06683cc2ca67cebe54033 +b5202e62cf8ea8e145b12394bd52fd09bda9145a5f78285b52fda4628c4e2ccfc2c208ecde4951bd0a59ac03fa8bc202 +8959856793ba4acf680fb36438c9722da74d835a9fe25a08cf9e32d7800c890a8299c7d350141d2e6b9feceb2ebb636f +ab0aa23c1cd2d095825a3456861871d298043b615ae03fcd9283f388f0deef3cc76899e7fde15899e3edf362b4b4657f +9603b333cc48fe39bea8d9824cfee6ac6c4e21668c162c196ecd1ff08ef4052ace96a785c36b8f7906fdcb6bc8802ddd +93bfecbc3c7cc03c563240e109850a74948f9fa078eb903b322368cda0b50888663a17953579578ba060b14dbf053024 +b01f843b808cf7939a474de155a45462e159eb5044f00c6d77e0f7ec812720a3153209e971a971ccbf5ebee76ec4074f +b009e0567c3c75ed767247d06fa39049a4d95df3392d35a9808cb114accf934e78f765cd18a2290efef016f1918c7aeb +ad35631df8331da3a12f059813dfa343d831225a392f9c7e641c7d23a6c1ad8df8e021201c9f6afb27c1575948d6bf68 +a89c2a631d84128471c8ef3d24b6c35c97b4b9b5dad905c1a092fb9396ae0370e215a82308e13e90e7bb6ebcc455eb2a +b59c7f5fbfeb02f8f69e6cedef7ff104982551f842c890a14834f5e834b32de1148cf4b414a11809d53dd3f002b15d6a +aa6f267305b55fede2f3547bc751ba844ce189d0b4852022712b0aee474de54a257d4abcd95efe7854e33a912c774eba +afddd668f30cce70904577f49071432c49386ec27389f30a8223b5273b37e6de9db243aceb461a7dc8f1f231517463a9 +b902a09da9157b3efa1d98f644371904397019d0c84915880628a646a3ad464a9d130fdc651315098179e11da643ad2e +b05f31957364b016c6f299ae4c62eede54cab8ea3871d49534828c8bdc6adbc6a04a708df268f50107d81d1384d983ae +b4c3f7284802e614ddf1f51640f29e7139aae891467d5f62778310372071793e56fbd770837b97d501191edd0da06572 +b4eddb7c3775fb14fac7f63bb73b3cde0efa2f9a3b70e6a65d200765f6c4b466d3d76fcd4d329baee88e2aba183b8e69 +a83e7dbae5a279f0cfd1c94e9849c58a3d4cecc6d6d44bb9b17508576ca347fca52c2c81371d946b11a09d4ed76ec846 +8018ea17e2381c0233867670f9e04c8a47ace1207fdcf72dce61b6c280ba42d0a65f4b4e0b1070cc19c7bb00734974d9 +af90b541dfed22e181ff3ef4cf11f5e385fd215c1e99d988e4d247bc9dcee9f04f2182b961797c0bcc5f2aaa05c901a9 +a37046e44cf35944e8b66df80c985b8a1aa7004a2fd0b81ac251638977d2ff1465f23f93ac0ce56296f88fdc591bbdd7 +a735bd94d3be9d41fcd764ec0d8d7e732c9fc5038463f7728fd9d59321277e2c73a45990223bd571dab831545d46e7aa +94b32dcb86f5d7e83d70a5b48fe42c50f419be2f848f2d3d32ee78bf4181ab18077a7666eedb08607eece4de90f51a46 +a7f0804cafbf513293485afc1b53117f0cbfaea10919e96d9e4eb06f0c96535e87065d93f3def1bbc42044dbb00eb523 +aaaad1166d7f19f08583dd713275a71a856ab89312f84ca8078957664924bb31994b5c9a1210d0c41b085be4058ed52e +a1757aac9f64f953e68e680985a8d97c5aac8688b7d90f4db860166dd3d6119e8fca7d700a9530a2b9ba3932c5e74e33 +98cada5db4a1430c272bfc1065fb685872e664ed200d84060ee9f797d0a00864f23943e0fb84ba122a961996a73dfb14 +a5e609f716dc7729d1247f40f9368a2e4a15067e1dd6a231fece85eeefb7e7d4a5ac8918fb376debd79d95088750b2ca +b5365eb8caab8b1118619a626ff18ce6b2e717763f04f6fa8158cdca530c5779204efa440d088083f1a3685454aa0555 +a6e01b8da5f008b3d09e51a5375d3c87c1da82dff337a212223e4d0cdb2d02576d59f4eef0652d6b5f2fc806d8c8149c +ae310f613d81477d413d19084f117248ad756572c22a85b9e4c86b432e6c602c4a6db5edf2976e11f7353743d679e82a +a1f219c0b8e8bb8a9df2c6c030acbb9bbfa17ba3db0366f547da925a6abb74e1d7eb852bd5a34bae6ac61d033c37e9dc +a2087fa121c0cdd5ea495e911b4bc0e29f1d5c725aadfb497d84434d2291c350cdaa3dc8c85285f65a7d91b163789b7a +929c63c266da73d726435fa89d47041cfe39d4efa0edce7fc6eca43638740fbc82532fd44d24c7e7dd3a208536025027 +91c1051dcc5f52ad89720a368dddd2621f470e184e746f5985908ba34e1d3e8078a32e47ab7132be780bea5277afecb0 +ae089b90ba99894d5a21016b1ea0b72a6e303d87e59fb0223f12e4bb92262e4d7e64bfdbdb71055d23344bc76e7794b2 +8b69aa29a6970f9e66243494223bad07ac8f7a12845f60c19b1963e55a337171a67bdc27622153016fce9828473a3056 +95ca6b08680f951f6f05fd0d180d5805d25caf7e5bda21c218c1344e661d0c723a4dfc2493642be153793c1b3b2caaa4 +a4789dc0f2a07c794dab7708510d3c893d82ddbd1d7e7e4bbbeca7684d9e6f4520fb019b923a06c7efab0735f94aa471 +93c4f57a3cf75085f5656b08040f4cd49c40f1aab6384a1def4c5c48a9fe4c03514f8e61aabe2cfa399ff1ccac06f869 +b6c37f92c76a96b852cd41445aa46a9c371836dd40176cc92d06666f767695d2284a2780fdfd5efc34cf6b18bcfb5430 +9113e4575e4b363479daa7203be662c13d7de2debcda1c142137228aeead2c1c9bc2d06d93a226302fa63cc75b7353ec +b70addeb5b842ac78c70272137f6a1cef6b1d3a551d3dd906d9a0e023c8f49f9b6a13029010f3309d0b4c8623a329faf +b976a5132b7eb42d5b759c2d06f87927ef66ecd6c94b1a08e4c9e02a4ce7feca3ac91f9479daa1f18da3d4a168c2ba77 +8fdab795af64b16a7ddf3fad11ab7a85d10f4057cf7716784184960013baa54e7ba2050b0e036dc978ff8c9a25dc5832 +b2c982ad13be67d5cdc1b8fac555d4d1ec5d25f84e58b0553a9836f8f9e1c37582d69ad52c086a880a08b4efcccd552e +810661d9075ae6942735215f2ab46d60763412e1f6334e4e00564b6e5f479fc48cf37225512abbccf249c0ca225fc935 +a0c4bf00a20f19feff4004004f08231b4c6c86ac4ed57921eea28d7dea32034f3f4ab5b7ded7184f6c7ffbf5847232ad +b2bb5a9eea80bf067f3686a488529d9c2abd63fc9e1d4d921b1247ef86d40cd99e0a8b74f750e85c962af84e84e163a6 +887ee493c96d50f619ba190ce23acddc5f31913e7a8f1895e6339d03794ecefd29da5f177d1d25bc8df8337ae963fc7b +b7966fb07029d040f2228efa2cfcd04341e4666c4cf0b653e6e5708631aa2dd0e8c2ac1a62b50c5a1219a2737b82f4f7 +92234cfd6b07f210b82db868f585953aafbcbc9b07b02ded73ff57295104c6f44a16e2775ca7d7d8ee79babb20160626 +8d3cd7f09c6fd1072bc326ff329e19d856e552ac2a9f20274bc9752527cd3274142aa2e32b65f285fb84bc3adaaea3cc +8caed1cb90d8cd61e7f66edc132672172f4fa315e594273bb0a7f58a75c30647ec7d52eda0394c86e6477fbc352f4fe8 +ae192194b09e9e17f35d8537f947b56f905766c31224e41c632c11cd73764d22496827859c72f4c1ab5fd73e26175a5d +8b7be56aac76d053969e46882d80a254e89f55c5ab434883cbafc634a2c882375898074a57bc24be3c7b2c56401a7842 +98bc4a7a9b05ba19f6b85f3ee82b08bed0640fd7d24d4542eb7a7f7fde443e880bdb6f5499bd8cb64e1ddd7c5f529b19 +a5a41eaa5e9c1d52b00d64ab72bc9def6b9d41972d80703e9bfe080199d4e476e8833a51079c6b0155b78c3ab195a2a7 +a0823f6f66465fd9be3769c164183f8470c74e56af617f8afd99b742909d1a51f2e0f96a84397597afbd8eeaabb51996 +801da41d47207bdd280cc4c4c9753a0f0e9d655e09e0be5f89aeed4ce875a904f3da952464399bf8efc2398940d5fba2 +a719314085fd8c9beac4706c24875833d59a9a59b55bca5da339037c0a5fc03df46dbecb2b4efcfed67830942e3c4ea1 +a75dde0a56070bb7e9237b144ea79f578d413a1cbbd1821cee04f14f533638b24f46d88a7001e92831843b37ed7a709f +a6b4ef8847a4b980146e1849e1d8ab38695635e0394ca074589f900ce41fa1bb255938dc5f37027523bac6a291779bef +b26d84dfd0b7bd60bcfdbea667350462a93dca8ff5a53d6fc226214dcb765fada0f39e446a1a87f18e4e4f4a7133155f +ae7bd66cc0b72f14ac631ff329a5ca4958a80ba7597d6da049b4eb16ac3decde919ca5f6f9083e6e541b303fb336dc2f +a69306e6bfbbc10de0621cffb13c586e2fcfd1a80935e07c746c95651289aec99066126a6c33cb8eb93e87d843fc631f +a47e4815585865218d73c68ba47139568ea7ae23bfa863cb914a68454242dd79beaec760616b48eea74ceab6df2298dd +b2da3cfb07d0721cd226c9513e5f3ace98ed2bc0b198f6626b8d8582268e441fa839f5834f650e2db797655ca2afa013 +b615d0819554f1a301a704d3fc4742bd259d04ad75d50bccee3a949b6226655f7d623301703506253cca464208a56232 +85e06ed5797207f0e7ae85909e31776eb9dae8af2ec39cc7f6a42843d94ea1de8be2a3cdadfcbe779da59394d4ffeb45 +8c3529475b5fdbc636ee21d763f5ec11b8cb040a592116fb609f8e89ca9f032b4fa158dd6e9ceab9aceb28e067419544 +accddb9c341f32be82b6fa2ef258802c9ae77cd8085c16ec6a5a83db4ab88255231b73a0e100c75b7369a330bfc82e78 +93b8e4c6e7480948fa17444b59545a5b28538b8484a75ad6bc6044a1d2dbd76e7c44970757ca53188d951dc7347d6a37 +90111721d68b29209f4dc4cfb2f75ab31d15c55701922e50a5d786fb01707ab53fcec08567cd366362c898df2d6e0e93 +b60a349767df04bd15881c60be2e5cc5864d00075150d0be3ef8f6b778715bebca8be3be2aa9dbdc49f1a485aeb76cda +b8d5a967fdd3a9bcf89a774077db39ef72ca9316242f3e5f2a350202102d494b2952e4c22badecd56b72ba1eea25e64b +8499ebd860f31f44167183b29574447b37a7ee11efcc9e086d56e107b826b64646b1454f40f748ccac93883918c89a91 +99c35e529782db30f7ccab7f31c225858cf2393571690b229ece838ec421a628f678854a1ddbd83fa57103ccebd92c7f +99817660d8b00cbe03ec363bcdc5a77885586c9e8da9e01a862aca0fc69bf900c09b4e929171bc6681681eae10450541 +8055e130964c3c2ebd980d3dc327a40a416bcdbf29f480480a89a087677a1fb51c823b57392c1db72f4093597100b8d3 +877eaddef845215f8e6f9ed24060c87e3ab6b1b8fbb8037d1a57e6a1e8ed34d00e64abb98d4bf75edb5c9788cbdccbef +b5432bbff60aeae47f2438b68b123196dfb4a65cc875b8e080501a4a44f834b739e121bec58d39ac36f908881e4aa8ab +b3c3f859b7d03ff269228c0f9a023b12e1231c73aba71ad1e6d86700b92adc28dfa3757c052bbc0ba2a1d11b7fda4643 +ab8a29f7519a465f394ef4a5b3d4924d5419ca1489e4c89455b66a63ac430c8c9d121d9d2e2ed8aa1964e02cd4ebac8c +866ae1f5c2a6e159f2e9106221402d84c059f40d166fab355d970773189241cd5ee996540d7c6fc4faf6f7bcff967dce +973a63939e8f1142a82b95e699853c1e78d6e05536782b9bb178c799b884f1bc60177163a79a9d200b5ff4628beeb9e7 +a5fc84798d3e2d7632e91673e89e968f5a67b7c8bb557ea467650d6e05e7fe370e18d9f2bdd44c244978295cf312dc27 +b328fe036bcd0645b0e6a15e79d1dd8a4e2eda128401a4e0a213d9f92d07c88201416fc76193bb5b1fe4cb4203bab194 +99239606b3725695a570ae9b6fb0fb0a34ad2f468460031cfa87aa09a0d555ff606ff204be42c1596c4b3b9e124b8bd6 +af3432337ca9d6cce3574e23e5b7e4aa8eda11d306dc612918e970cc7e5c756836605a3391f090a630bac0e2c6c42e61 +8a545b3cb962ce5f494f2de3301de99286c4d551eaa93a9a1d6fef86647321834c95bf754c62ec6c77116a21494f380d +8f9b8ea4c25469c93556f1d91be583a5f0531ac828449b793ba03c0a841c9c73f251f49dd05cbb415f5d26e6f6802c99 +a87199e33628eeffd3aff114e81f53dd54fba61ba9a9a4d7efdbff64503f25bc418969ab76ef1cf9016dd344d556bb29 +a2fda05a566480602274d7ffcaefdd9e94171286e307581142974f57e1db1fa21c30be9e3c1ac4c9f2b167f92e7c7768 +a6235d6a23304b5c797efb2b476ed02cb0f93b6021a719ae5389eb1e1d032944ae4d69aec2f29fcd6cbc71a6d789a3ba +a7f4a73215f7e99e2182c6157dd0f22e71b288e696a8cff2450689a3998f540cfb82f16b143e90add01b386cb60d8a33 +922d8f9cd55423f5f6a60d26de2f8a396ac4070a6e2dc956e50c2a911906aa364d4718aea29c5b61c12603534e331e7e +96d7fdf5465f028fc28f21fbfe14c2db2061197baf26849e6a0989a4ea7d5e09ab49a15ba43a5377b9354d01e30ce860 +8f94c4255a0fc1bd0fa60e8178c17f2a8e927cac7941c5547d2f8f539e7c6ed0653cab07e9fb1f2c56cdd03bb876512a +95984c10a2917bfa6647ebce69bf5252d9e72d9d15921f79b2c6d7c15ee61342b4fb8a6d34838e07132b904f024ded04 +93e65e765a574277d3a4d1d08ca2f2ff46e9921a7806ca8ca3d8055f22d6507744a649db7c78117d9168a1cbdb3bbc61 +8d453b7364662dc6f36faf099aa7cbbe61151d79da7e432deba7c3ed8775cfe51eaf1ba7789779713829dde6828e189a +acffa3ee6c75160286090162df0a32a123afb1f9b21e17fd8b808c2c4d51a4270cab18fba06c91ef9d22e98a8dc26cdd +a5597cc458186efa1b3545a3926f6ecaaa6664784190e50eed1feac8de56631bee645c3bac1589fa9d0e85feb2be79d4 +87ba9a898df9dfa7dabc4ab7b28450e4daf6013340e329408d1a305de959415ab7315251bad40511f917dfc43974e5f0 +a598778cf01d6eef2c6aabc2678e1b5194ee8a284ebd18a2a51a3c28a64110d5117bcbf68869147934e600572a9e4c8a +84c69a4ad95861d48709f93ade5ac3800f811b177feb852ebcd056e35f5af5201f1d8a34ab318da8fe214812d0a7d964 +9638a237e4aed623d80980d91eda45e24ebf48c57a25e389c57bd5f62fa6ffa7ca3fb7ae9887faf46d3e1288af2c153b +800f975721a942a4b259d913f25404d5b7b4c5bf14d1d7e30eee106a49cb833b92058dab851a32ee41faf4ef9cb0dea4 +b9127a34a59fed9b5b56b6d912a29b0c7d3cb9581afc9bd174fc308b86fdb076f7d436f2abc8f61cef04c4e80cd47f59 +8004eda83f3263a1ccfc8617bc4f76305325c405160fb4f8efeff0662d605e98ba2510155c74840b6fe4323704e903c4 +aa857b771660d6799ff03ccad1ab8479e7f585a1624260418fc66dc3e2b8730cfa491d9e249505141103f9c52f935463 +98b21083942400f34cde9adbe1977dee45ba52743dc54d99404ad9da5d48691ddea4946f08470a2faad347e9535690c7 +a4b766b2faec600a6305d9b2f7317b46f425442da0dc407321fc5a63d4571c26336d2bccedf61097f0172ec90fb01f5f +b9736619578276f43583de1e4ed8632322ea8a351f3e1506c5977b5031d1c8ad0646fb464010e97c4ddb30499ddc3fb0 +973444ffaff75f84c17f9a4f294a13affd10e2bceed6b4b327e4a32c07595ff891b887a9f1af34d19766d8e6cb42bfd1 +b09ce4964278eff81a976fbc552488cb84fc4a102f004c87179cb912f49904d1e785ecaf5d184522a58e9035875440ef +b80c2aa3d0e52b4d8b02c0b706e54b70c3dbca80e5e5c6a354976721166ea0ca9f59c490b3e74272ef669179f53cb50d +8e52fa5096ff960c0d7da1aa4bce80e89527cdc3883eba0c21cb9a531088b9d027aa22e210d58cf7cbc82f1ec71eb44f +969f85db95f455b03114e4d3dc1f62a58996d19036513e56bee795d57bf4ed18da555722cd77a4f6e6c1a8e5efe2f5d7 +ab84b29b04a117e53caea394a9b452338364c45a0c4444e72c44132a71820b96a6754828e7c8b52282ad8dca612d7b6a +83e97e9ab3d9e453a139c9e856392f4cef3ec1c43bce0a879b49b27a0ce16f9c69063fd8e0debbe8fabafc0621bc200c +8c138ebdf3914a50be41be8aa8e2530088fb38af087fa5e873b58b4df8e8fd560e8090c7a337a5e36ef65566409ad8f3 +a56da9db2f053516a2141c1a8ed368ae278ab33a572122450249056857376d1dffc76d1b34daf89c86b6fe1ead812a0c +a3233ea249f07531f5bc6e94e08cea085fd2b2765636d75ff5851f224f41a63085510db26f3419b031eb6b5143735914 +b034bb6767ce818371c719b84066d3583087979ba405d8fbb2090b824633241e1c001b0cb0a7856b1af7a70e9a7b397e +8722803fe88877d14a4716e59b070dd2c5956bb66b7038f6b331b650e0c31230c8639c0d87ddc3c21efc005d74a4b5cc +8afe664cb202aacf3bd4810ebf820c2179c11c997f8c396692a93656aa249a0df01207c680157e851a30330a73e386b9 +a999e86319395351d2b73ff3820f49c6516285e459224f82174df57deb3c4d11822fd92cbbed4fc5a0a977d01d241b19 +9619408e1b58b6610d746b058d7b336d178e850065ba73906e08e748651e852f5e3aab17dcadcb47cc21ff61d1f02fcf +947cf9c2ed3417cd53ea498d3f8ae891efe1f1b5cd777e64cec05aba3d97526b8322b4558749f2d8a8f17836fb6e07aa +aec2fdae2009fda6852decb6f2ff24e4f8d8ca67c59f92f4b0cf7184be72602f23753ed781cf04495c3c72c5d1056ffe +8dba3d8c09df49fbfc9506f7a71579348c51c6024430121d1c181cad7c9f7e5e9313c1d151d46d4aa85fb0f68dd45573 +b6334cb2580ae33720ebf91bb616294532a1d1640568745dcda756a3a096786e004c6375728a9c2c0fb320441e7d297a +9429224c1205d5ecd115c052b701c84c390f4e3915275bb8ce6504e08c2e9b4dd67b764dd2ea99f317b4c714f345b6ff +abe421db293f0e425cfd1b806686bdfd8fdbac67a33f4490a2dc601e0ddbf69899aa9a119360dad75de78c8c688ca08b +95c78bffed9ae3fff0f12754e2bd66eb6a9b6d66a9b7faaeb7a1c112015347374c9fe6ce14bf588f8b06a78e9a98f44c +ac08f8b96b52c77d6b48999a32b337c5ad377adf197cda18dbdf6e2a50260b4ee23ca6b983f95e33f639363e11229ee4 +911a0e85815b3b9f3ba417da064f760e84af94712184faeb9957ddd2991dee71c3f17e82a1a8fbeec192b0d73f0ebce7 +aa640bd5cb9f050568a0ad37168f53b2f2b13a91e12b6980ca47ae40289cf14b5b89ddd0b4ca452ce9b1629da0ce4b5d +907486f31b4ecea0125c1827007ea0ecb1c55cadb638e65adc9810ca331e82bb2fd87e3064045f8d2c5d93dc6c2f5368 +8cbfaf4ce0bbbf89208c980ff8b7bc8f3cfef90f0fe910f463cb1c0f8e17cce18db120142d267045a00ba6b5368f0dd3 +9286f08f4e315df470d4759dec6c9f8eacef345fc0c0b533ad487bb6cfefa8c6c3821a22265c9e77d34170e0bc0d078b +94a3c088bc1a7301579a092b8ece2cefc9633671bc941904488115cd5cb01bd0e1d2deef7bdccb44553fd123201a7a53 +8f3d0114fbf85e4828f34abb6d6fddfa12789d7029d9f1bb5e28bc161c37509afdab16c32c90ec346bc6a64a0b75726f +a8ed2d774414e590ec49cb9a3a726fafd674e9595dd8a1678484f2897d6ea0eea1a2ee8525afac097b1f35e5f8b16077 +9878789ff33b11527355a317343f34f70c7c1aa9dc1eca16ca4a21e2e15960be8a050ec616ffb97c76d756ce4bce2e90 +854e47719dae1fe5673cacf583935122139cf71a1e7936cf23e4384fbf546d48e9a7f6b65c3b7bf60028e5aa1234ba85 +af74bdda2c6772fe9a02d1b95e437787effad834c91c8174720cc6e2ea1f1f6c32a9d73094fc494c0d03eef60b1a0f05 +80a3e22139029b8be32cb167d3bc9e62d16ca446a588b644e53b5846d9d8b7ab1ad921057d99179e41515df22470fb26 +86c393afd9bd3c7f42008bba5fe433ec66c790ebd7aa15d4aeaf9bb39a42af3cfaf8c677f3580932bbd7ada47f406c8c +90433c95c9bb86a2c2ddcf10adccb521532ebd93db9e072671a4220f00df014e20cd9ce70c4397567a439b24893808dc +95b2c170f08c51d187270ddc4f619300b5f079bbc89dbca0656eae23eecc6339bf27fa5bf5fd0f5565d4021105e967d2 +8e5eced897e2535199951d4cff8383be81703bca3818837333dd41a130aa8760156af60426ceadb436f5dea32af2814c +a254a460ebefbe91d6e32394e1c8f9075f3e7a2bb078430ac6922ab14d795b7f2df1397cb8062e667d809b506b0e28d4 +ac2062e8ca7b1c6afb68af0ebab31aebd56fc0a0f949ef4ea3e36baf148681619b7a908facf962441905782d26ecbdb5 +8b96af45b283b3d7ffeec0a7585fc6b077ea5fd9e208e18e9f8997221b303ab0ce3b5bafa516666591f412109ce71aa5 +afd73baada5a27e4fa3659f70083bf728d4dc5c882540638f85ea53bf2b1a45ddf50abc2458c79f91fb36d13998c7604 +a5d2fff226e80cb2e9f456099812293333d6be31dd1899546e3ad0cd72b2a8bcb45ec5986e20faa77c2564b93983210c +a8c9b8de303328fbdaccf60f4de439cf28f5360cf4104581dc2d126bc2e706f49b7281723487ff0eaf92b4cc684bc167 +a5d0d5849102bf1451f40e8261cb71fc57a49e032773cb6cd7b137f71ee32438d9e958077ffafce080a116ccc788a2d4 +80716596f502d1c727d5d2f1469ce35f15e2dbd048d2713aa4975ee757d09c38d20665326bd63303cfe7e820b6de393d +97baf29b20f3719323cc1d5de23eaa4899dc4f4e58f6c356ec4c3ad3896a89317c612d74e0d3ab623fe73370c5972e2f +b58bdc9aa5061bf6e5add99a7443d7a8c7ba8f6875b8667d1acbe96fc3ecafbdcc2b4010cb6970a3b849fff84660e588 +b6be68728776d30c8541d743b05a9affc191ad64918fdbd991d2ddd4b32b975c4d3377f9242defef3805c0bfb80fbac7 +b0cddace33333b8a358acad84b9c83382f0569d3854b4b34450fd6f757d63c5bdab090e330b0f86e578f22c934d09c36 +854bd205d6051b87f9914c8c2494075d7620e3d61421cc80f06b13cea64fd1e16c62c01f107a5987d10b8a95a8416ad9 +80351254a353132300ba73a3d23a966f4d10ce9bf6eae82aedb6cdc30d71f9d08a9dd73cb6441e02a7b2ad93ad43159c +937aae24fb1b636929453fc308f23326b74c810f5755d9a0290652c9c2932ad52cc272b1c83bd3d758ef7da257897eae +b84d51ef758058d5694ffeac6d8ce70cef8d680a7902f867269c33717f55dd2e57b25347841d3c0872ae5f0d64f64281 +a4b31bb7c878d5585193535b51f04135108134eff860f4eac941053155f053d8f85ff47f16268a986b2853480a6e75e6 +93543f0828835186a4af1c27bdf97b5dd72b6dfa91b4bf5e759ff5327eaf93b0cb55d9797149e465a6b842c02635ffe5 +afdac9e07652bf1668183664f1dd6818ef5109ee9b91827b3d7d5970f6a03e716adcc191e3e78b0c474442a18ad3fc65 +9314077b965aa2977636ae914d4a2d3ce192641a976ffa1624c116828668edbfbe5a09e3a81cb3eed0694566c62a9757 +b395ddcf5082de6e3536825a1c352802c557b3a5118b25c29f4c4e3565ecaaf4bdd543a3794d05156f91fc4ceadc0a11 +b71f774aad394c36609b8730e5be244aaebfff22e0e849acc7ee9d33bedc3ec2e787e0b8b2ffe535560fcd9e15a0897e +92e9409fa430f943a49bce3371b35ac2efb5bc09c88f70ff7120f5e7da3258a4387dfc45c8b127f2ef2668679aeb314e +8ef55bef7b71952f05e20864b10f62be45c46e2dca0ef880a092d11069b8a4aa05f2e0251726aca1d5933d7dea98f3f8 +aad3fba9e09fae885cdeef45dfafa901419f5156fb673818f92a4acc59d0e2e9870b025e711de590a63fd481164f3aa8 +b444d52af545dd3a2d3dd94e6613816b154afea0c42b96468aceb0c721395de89e53e81a25db857ca2e692dcb24ba971 +88b279fe173007e64fe58f2c4adba68a1f538dbd3d32d175aa0d026bbb05b72a0c9f5d02b8201a94adb75fe01f6aa8b2 +88494cea4260741c198640a079e584cabfea9fcfb8bcf2520c9becd2419cde469b79021e5578a00d0f7dbc25844d2683 +94f3cce58837c76584b26426b9abdb45f05fee34dd9e5914b6eae08e78b7262ed51c4317031dab1ad716f28b287f9fc2 +b8c7ed564f54df01c0fbd5a0c741beed8183ce0d7842dc3a862a1b335de518810077314aa9d6054bb939663362f496da +81c153320d85210394d48340619d5eb41304daea65e927266f0262c8a7598321aba82ad6c3f78e5104db2afd2823baca +ab6695a8d48a179e9cd32f205608359cf8f6a9aead016252a35b74287836aa395e76572f21a3839bec6a244aa49573e5 +920ed571539b3002a9cd358095b8360400e7304e9a0717cc8c85ab4a0514a8ad3b9bf5c30cb997647066f93a7e683da9 +a7ec7c194d1e5103bc976e072bf1732d9cb995984d9a8c70a8ee55ce23007f21b8549ad693f118aa974f693ed6da0291 +87a042d6e40c2951a68afc3ccf9646baf031286377f37f6ac47e37a0ec04d5ac69043757d7dff7959e7cd57742017a8d +b9f054dd8117dd41b6e5b9d3af32ee4a9eebef8e4a5c6daa9b99c30a9024eabeae850ab90dbdb188ca32fd31fd071445 +a8386da875799a84dc519af010eaf47cdbc4a511fe7e0808da844a95a3569ce94054efd32a4d3a371f6aba72c5993902 +8b3343a7cf4ffb261d5f2dbd217fb43590e00feac82510bdf73b34595b10ee51acae878a09efebc5a597465777ef4c05 +8312a5f1ea4f9e93578e0f50169286e97884a5ed17f1780275ab2b36f0a8aa1ab2e45c1de4c8bce87e99e3896af1fa45 +b461198cb7572ac04c484a9454954e157bdd4db457816698b7290f93a10268d75a7e1211e757c6190df6144bbb605d91 +9139764a099580d6f1d462c8bf7d339c537167be92c780e76acb6e638f94d3c54b40ed0892843f6532366861e85a515a +8bb70acb3c9e041b4fc20e92ba0f3f28f0d5c677bcb017af26f9171e07d28c3c0729bef72457231e3512f909455a13a2 +93301a18e5064c55fcfe8e860fab72da1b89a824ca77c8932023b7c79e4a51df93a89665d308a8d3aa145e46ebe6a0ad +ae3bca496fbd70ce44f916e2db875b2ce2e1ded84edd2cebc0503bdfdec40ec30e1d9afb4eb58c8fa23f7b44e71d88f8 +93cb3a918c95c5d973c0cb7621b66081ed81fba109b09a5e71e81ca01ec6a8bb5657410fdec453585309ef5bf10d6263 +95a50b9b85bb0fc8ff6d5f800d683f0f645e7c2404f7f63228a15b95ce85a1f8100e2e56c0acee19c36ed3346f190e87 +816cc4d9337461caca888809b746ab3713054f5b0eac823b795a1a9de9417c58e32a9f020fef807908fa530cbf35dee8 +a9c2890c2dd0d5d7aedc4cca7f92764086c50f92f0efd2642c59920d807086031bfe2d3ba574318db236c61a8f5f69c2 +ad0d5c8c80bddfe14bdaf507da96dc01dc9941aecc8ad3b64513d0a00d67c3f4b4659defb6839b8b18d8775e5344c107 +9047c9fad6ef452e0219e58e52c686b620e2eb769571021e3524bd7eac504f03b84834b16b849d42b3d75c601fd36bb7 +a04dd988fed91fb09cb747a3ac84efe639d7d355524cd7dee5477ecbcdec44d8ac1cec2c181755dcfdb77e9594fb3c5b +b0ea0c725debd1cec496ced9ce48f456f19af36e8b027094bf38fa37de9b9b2d10282363ea211a93a34a0a5387cace5d +b5fc46e2bb3e4653ea5e6884dcb3c14e401a6005685ee5a3983644b5b92300b7066289159923118df4332aac52045b8c +841fc5b26b23226e725e29802da86b35e4f5e3babc8b394f74e30fd5dec6d3840b19a9a096625ce79a4f1edae6369700 +8fd2bbbeea452451def3659bbe0ceb396120ebe8f81eee1ea848691614422c81d7c3e6a7a38032b4120b25c5ffa8f0c2 +9131ce3d25c3d418f50c0ab99e229d4190027ee162b8ba7c6670420ea821831dec1294ac00d66c50fac61c275a9e2c71 +99ec6eafe0eb869d128158cee97b984fb589e1af07699247946e4a85db772289dff3084d224a6f208005c342f32bbd73 +ac100fbbe7c2bf00cc56fcd5aa1f27181f82c150c53bbb1e15d2c18a51ed13dcfa7bccab85821b8ddddf493603e38809 +affd73a458d70c0d9d221e0c2da4348fed731f6b34c0b3e2d5711ba432e85a1ec92e40b83b246a9031b61f5bc824be47 +8ed30ed817816a817e9e07374ef1f94405a7e22dd0096aeaae54504382fc50e7d07b4f1186c1792fc25ea442cd7edc6b +a52370cfe99a35fa1405aeca9f922ad8d31905e41f390e514ea8d22ee66469637d6c2d4d3a7ee350d59af019ae5a10a4 +8d0b439741c57b82c8e4b994cf3956b5aeaee048b17e0a1edb98253a8d7256f436d8b2f36b7e12504132dbf91f3376b1 +8caac7e1a4486c35109cff63557a0f77d0e4ca94de0817e100678098a72b3787a1c5afc7244991cebcd1f468e18d91d4 +a729a8e64b7405db5ebfb478bb83b51741569331b88de80680e9e283cc8299ba0de07fcf252127750f507e273dc4c576 +a30545a050dad030db5583c768a6e593a7d832145b669ad6c01235813da749d38094a46ac3b965700230b8deacd91f82 +9207e059a9d696c46fa95bd0925983cd8e42aefd6b3fb9d5f05420a413cbc9e7c91213648554228f76f2dd757bde0492 +a83fa862ae3a8d98c1e854a8b17181c1025f4f445fbc3af265dc99e44bbd74cfa5cc25497fb63ee9a7e1f4a624c3202c +84cdfc490343b3f26b5ad9e1d4dcf2a2d373e05eb9e9c36b6b7b5de1ce29fda51383761a47dbd96deca593a441ccb28e +881a1aa0c60bb0284a58b0a44d3f9ca914d6d8fa1437315b9ad2a4351c4da3ee3e01068aa128284a8926787ea2a618d1 +aace78e497b32fbff4df81b1b2de69dbc650645e790953d543282cb8d004a59caf17d9d385673a146a9be70bf08a2279 +aa2da4760f1261615bffd1c3771c506965c17e6c8270c0f7c636d90428c0054e092247c3373eca2fb858211fdb17f143 +acb79f291b19e0aa8edb4c4476a172834009c57e0dcc544c7ce95084488c3ad0c63ffd51c2b48855e429b6e1a9555433 +814b58773a18d50a716c40317f8b80362b6c746a531776a9251c831d34fb63e9473197c899c0277838668babc4aa0ecb +b1f69522b0f7657d78bd1ee3020bcce3447116bf62c146d20684537d36cafb5a7a1531b86932b51a70e6d3ce0808a17e +8549712c251ef382f7abe5798534f8c8394aa8bcecdca9e7aa1a688dc19dc689dcd017a78b118f3bd585673514832fe4 +912a04463e3240e0293cfc5234842a88513ff930c47bd6b60f22d6bc2d8404e10270d46bf6900fee338d8ac873ebb771 +a327cb7c3fada842e5dd05c2eeedd6fcd8cf2bfb2f90c71c6a8819fb5783c97dd01bd2169018312d33078b2bc57e19f7 +b4794f71d3eceed331024a4cee246cc427a31859c257e0287f5a3507bfbd4d3486cb7781c5c9c5537af3488d389fe03e +82ffcb418d354ed01688e2e8373a8db07197a2de702272a9f589aed08468eab0c8f14e6d0b3146e2eb8908e40e8389c5 +910b73421298f1315257f19d0dfd47e79d7d2a98310fb293f704e387a4dc84909657f0f236b70b309910271b2f2b5d46 +a15466397302ea22f240eb7316e14d88376677b060c0b0ae9a1c936eb8c62af8530732fc2359cfd64a339a1c564f749b +a8091975a0d94cdc82fbaff8091d5230a70d6ea461532050abbdfee324c0743d14445cfe6efe6959c89a7c844feaa435 +a677d1af454c7b7731840326589a22c9e81efbbf2baf3fdeaf8ea3f263a522584fbca4405032c4cdf4a2a6109344dfc8 +894e6ffa897b6e0b37237e6587a42bbc7f2dd34fb09c2e8ac79e2b25b18180e158c6dc2dd26761dba0cfed1fb4eb4080 +928d31b87f4fe8fe599d2c9889b0ff837910427ba9132d2fba311685635458041321ae178a6331ed0c398efe9d7912f0 +afc1c4a31f0db24b53ee71946c3c1e1a0884bd46f66b063a238e6b65f4e8a675faa844e4270892035ef0dae1b1442aa0 +a294fcb23d87cf5b1e4237d478cac82ba570649d425b43b1e4feead6da1f031e3af0e4df115ca46689b9315268c92336 +85d12fd4a8fcfd0d61cbf09b22a9325f0b3f41fb5eb4285b327384c9056b05422d535f74d7dc804fb4bab8fb53d556bd +91b107d9b0ea65c48128e09072acd7c5949a02dd2a68a42ff1d63cf528666966f221005c2e5ca0a4f85df28459cdede6 +89aa5dc255c910f439732fcd4e21341707e8dd6689c67c60551a8b6685bd3547e3f47db4df9dfadd212405f644c4440b +8c307d6b827fa1adcf0843537f12121d68087d686e9cc283a3907b9f9f36b7b4d05625c33dab2b8e206c7f5aabd0c1e5 +843f48dadf8523d2b4b0db4e01f3c0ea721a54d821098b578fcaa6433e8557cadfea50d16e85133fa78f044a3e8c1e5b +9942eb8bd88a8afa9c0e3154b3c16554428309624169f66606bfb2814e8bac1c93825780cf68607f3e7cffe7bf9be737 +b7edb0c7637a5beb2332f2ae242ba4732837f9da0a83f00f9e9a77cf35516e6236eb013133ddc2f958ea09218fe260d3 +9655fe4910bc1e0208afbcf0ff977a2e23faded393671218fba0d9927a70d76514a0c45d473a97ecb00cf9031b9d527c +8434bc8b4c5839d9e4404ff17865ded8dd76af56ef2a24ea194c579d41b40ed3450c4e7d52219807db93e8e6f001f8da +b6c6d844860353dab49818bed2c80536dbc932425fdaa29915405324a6368277cf94d5f4ab45ea074072fc593318edff +b2887e04047660aa5c83aad3fa29b79c5555dd4d0628832c84ba7bf1f8619df4c9591fcde122c174de16ca7e5a95d5e3 +953ba5221360444b32911c8b24689078df3fbf58b53f3eec90923f53a22c0fc934db04dd9294e9ec724056076229cf42 +926917529157063e4aade647990577394c34075d1cb682da1acf600639d53a350b33df6a569d5ebb753687374b86b227 +b37894a918d6354dd28f850d723c1c5b839f2456e2a220f64ecadac88ae5c9e9cf9ab64b53aac7d77bf3c6dfa09632dc +b9d28148c2c15d50d1d13153071d1f6e83c7bb5cb5614adf3eb9edede6f707a36c0fa0eadb6a6135ead3c605dfb75bd1 +9738d73ea0b9154ed38da9e6bd3a741be789ea882d909af93e58aa097edf0df534849f3b1ba03099a61ceb6a11f34c4d +afabbecbbf73705851382902ec5f1da88b84a06b3abfb4df8d33df6a60993867f853d0d9bd324d49a808503615c7858a +a9e395ddd855b12c87ba8fdb0ea93c5bd045e4f6f57611b27a2ee1b8129efe111e484abc27cb256ed9dcace58975d311 +b501c2f3d8898934e45e456d36a8a5b0258aeea6ff7ac46f951f36da1ec01bd6d0914c4d83305eb517545f1f35e033cc +86f79688315241fe619b727b7f426dbd27bcc8f33aef043438c95c0751ada6f4cd0831b25ae3d53bcf61324d69ea01eb +83237e42fa773a4ccaa811489964f3fab100b9eea48c98bdef05fa119a61bde9efe7d0399369f87c775f4488120b4f2e +b89f437552cab77d0cd5f87aca52dd827fb6648c033351c00ab6d40ac0b1829b4fcdf8a7dad467d4408c691223987fbe +8e21061698cb1a233792976c2d8ab2eeb6e84925d59bb34434fff688be2b5b2973d737d9dda164bd407be852d48ef43f +b17a9e43aa4580f542e00c3212fbf974f1363f433c5502f034dfd5ed8c05ac88b901729d3b822bec391cca24cc9f5348 +aac6d6cda3e207006c042a4d0823770632fc677e312255b4aff5ad1598dc1022cab871234ad3aa40b61dc033a5b0930b +b25e69f17b36a30dada96a39bc75c0d5b79d63e5088da62be9fcbddfd1230d11654890caa8206711d59836d6abbc3e03 +af59fe667dd9e7e4a9863c994fc4212de4714d01149a2072e97197f311be1f39e7ad3d472e446dcc439786bf21359ede +957952988f8c777516527b63e0c717fc637d89b0fd590bcb8c72d0e8a40901598930c5b2506ff7fea371c73a1b12a9be +a46becd9b541fc37d0857811062ca1c42c96181c7d285291aa48dc2f6d115fcff5f3dfdf4490d8c619da9b5ce7878440 +87168fbd32c01a4e0be2b46fe58b74d6e6586e66bbb4a74ad94d5975ac09aa6fa48fd9d87f1919bd0d37b8ebe02c180c +895c4aa29de9601fc01298d54cfb62dd7b137e6f4f6c69b15dc3769778bfba5fc9cbd2fc57fd3fad78d6c5a3087f6576 +b9cf19416228230319265557285f8da5b3ca503de586180f68cf055407d1588ecec2e13fc38817064425134f1c92b4d5 +9302aaef005b22f7b41a0527b36d60801ff6e8aa26fe8be74685b5f3545f902012fcade71edca7aaa0560296dac5fca5 +a0ccda9883027f6b29da1aaa359d8f2890ce1063492c875d34ff6bf2e7efea917e7369d0a2b35716e5afd68278e1a93a +a086ac36beeba9c0e5921f5a8afea87167f59670e72f98e788f72f4546af1e1b581b29fbdd9a83f24f44bd3ec14aee91 +8be471bf799cab98edf179d0718c66bbc2507d3a4dac4b271c2799113ce65645082dc49b3a02a8c490e0ef69d7edbcb1 +8a7f5b50a18baf9e9121e952b65979bda5f1c32e779117e21238fb9e7f49e15008d5c878581ac9660f6f79c73358934a +b3520a194d42b45cbab66388bee79aad895a7c2503b8d65e6483867036497d3e2e905d4d51f76871d0114ec13280d82f +8e6ca8342ec64f6dbe6523dc6d87c48065cd044ea45fa74b05fff548539fd2868eb6dd038d38d19c09d81d5a96364053 +b126a0e8263a948ba8813bf5fb95d786ae7d1aa0069a63f3e847957822b5fe79a3a1afa0ce2318b9ba1025f229a92eb7 +8e4461d6708cac53441a3d23ac4b5ff2b9a835b05008c26d7d9c0562a29403847cf760b7e9d0bcb24a6f498d2a8a9dd2 +b280a761bab256dfe7a8d617863999e3b4255ddbdc11fe7fe5b3bb9633fc8f0cb4f28e594d3b5b0b649c8e7082c4666a +a3e3043bfd7461e38088ee6a165d2ca015de98350f1cb0efc8e39ed4fcdb12a717f0ede7fbf9dadb90496c47652cc0ce +a4c1f5b1b88ae3c397d171e64395afe0cd13c717677775a01dd0461d44a04ee30ec3da58a54c89a3ca77b19b5e51062c +a268638e0655b6d5a037061808619b9ae276bb883999d60c33a9f7f872c46d83d795d1f302b4820030c57604fa3686e7 +ac20176111c5c6db065668987227658c00a1572ce21fe15f25e62d816b56472c5d847dd9c781fb293c6d49cc33b1f98f +acc0e22d9b6b45c968c22fd16b4ece85e82a1b0ab72369bdd467857fee1a12b9635f5b339a9236cbd1acc791811d0e29 +b56066e522bee1f31480ff8450f4d469ace8eb32730c55b7c9e8fa160070bdec618454e665b8cbc5483bc30b6cebbfb9 +8c1772bdfacff85f174d35c36f2d2182ae7897ad5e06097511968bbb136b626c0c7e462b08a21aca70f8e456b0204bf8 +b4de3cf4a064bf589be92513b8727df58f2da4cd891580ef79635ac8c195f15a6199327bb41864e2f614c8589b24f67e +8f3c534125613f2d17bf3e5b667c203cb3eab0dbca0638e222fe552fddf24783965aa111de844e8c3595304bfc41c33b +8e445b2711987fe0bf260521cb21a5b71db41f19396822059912743bf6ca146100c755c8b6e0e74f1bf2e34c03b19db9 +87ff9adf319adb78c9393003b5bdda08421f95551d81b37520b413fe439e42acf82d47fa3b61476b53166bf4f8544f0e +83f3c00c55632e1937dcdc1857de4eccd072efa319b3953d737e1d37382b3cf8343d54a435588eb75aa05bf413b4caa0 +b4d8ee1004bac0307030b8605a2e949ca2f8d237e9c1dcf1553bd1eb9b4156e2deb8c79331e84d2936ec5f1224b8b655 +93b2812b6377622e67bf9a624898227b56ebe3c7a1d917487fc9e4941f735f83679f7ac137065eb4098ad1a4cfbc3892 +81943d9eab6dcea8a120dde5356a0a665b1466709ebb18d1cbfa5f213a31819cb3cf2634e6d293b5b13caa158a9bb30b +a9042aae02efd4535681119e67a60211fc46851319eb389b42ebadcab1229c94199091fb1652beba3434f7b98c90785f +91db52b27fd9b1715df202106b373c4e63ce8ec7db8c818c9016ace5b08ef5f8c27e67f093395937ba4ce2f16edf9aef +83cb9b7b94bd6ead3ff2a7d40394f54612c9cb80c4e0adadffea39e301d1052305eb1fe0f7467268b5aba3b423a87246 +8720fd6712a99d92dd3fdaae922743ab53fad50d183e119a59dae47cdac6fbea6064c732d02cb341eaea10723db048fa +8d40022c1254462a2ac2380a85381c370b1221e5a202d95c75bccba6d1e52972dd5585a1294a1e487bf6ae6651867167 +b7bc06e08d8c72daba143627582f4b4f34cc2234b5cb5cd83536f2ef2e058631a3920468ea4d550aea01cad221d6a8a6 +a6e1a6f70fba42d3b9ce5f04ffdcfca46fc94041840c0066a204030cf75ea9f9856113fea3a9f69ea0037d9a68e3a9d4 +8b064c350083fce9a52da2e2e17bf44c4c9643d2d83667cbd9ad650bbeba55e2c408e746ccf693e56d08826e8a6d57fc +8d304a5405a0c0696917fcddc6795dd654567ca427f007d9b16be5de98febbf8692374e93f40822f63cf6f143c4d9499 +b968db239efec353a44f20a7cf4c0d0fca4c4c2dc21e6cbb5d669e4fe624356a8341e1eec0955b70afb893f55e9a9e32 +98971f745ce4ce5f1f398b1cd25d1697ada0cc7b329cee11d34b2d171e384b07aeb06ac7896c8283664a06d6dd82ec6b +881f5a20a80f728354fad9d0a32a79ffe0ba9bed644ed9d6a2d85444cda9821018159a3fa3d3d6b4fadbf6ea97e6aff6 +b7c76cbb82919ec08cf0bd7430b868a74cb4021e43b5e291caa0495ca579798fab1b64855e2d301f3461dd4d153adeb6 +b44c8c69b3df9b4e933fe6550982a6f76e18046e050229bd2456337e02efb75efa0dfe1b297ed9f5d7fa37fec69c8374 +a5bd7781820ba857aee07e38406538b07ab5180317689a58676f77514747672dd525ea64512a0e4958896f8df85e9d4d +a8443d1dc91b4faa20a2626505b5b4ad49cc5c1fd7a240a0e65d12f52d31df1585ba52c21e604dcec65ec00b81ae21fe +a157ae42fc6302c54bcdd774e8b8bafc4f5d221717f7bf49668c620e47051b930dce262d55668e546272dd07ca7c8d3f +8732c10448b63e907ff95f53cd746f970c946fd84fcbfe4cf9ede63afbbfc66b293bbc7c470d691bbd149bb3c78bb351 +a82192f4fd9a0c33489a0486b79d0f6c797c7eccb45f91f7f1e8e1dd1924ca9944b983951025b99ab5861d31841451fe +839efc6d199ddd43f34f6729b6b63f9ee05f18859bf8fd3f181fa71f4399a48bff7dde89b36e9dc1c572f1b9b6127cca +992ef084abe57adfd5eb65f880b411d5f4ed34c1aeb0d2cfac84fff4f92a9a855c521a965ba81b5eef2268e9a9e73048 +a2518ab712fa652e6e0bd0840307ef3831094e9a18723fb8ec052adacbb87f488d33778c6ec3fd845003af62e75125d1 +b630ac3c9e71b85dd9e9f2984bb5b762e8491d8edb99cad82c541faf5a22dd96f0fddb49d9a837b1955dea2d91284f28 +8d886d1b7f818391b473deba4a9a01acce1fe2abe9152955e17ba39adc55400590c61582c4fef37a286e2151566576ed +884f100dc437639247f85e5d638fcc7583d21bf37a66ce11e05bfc12f5dbe78685b0e51b4594e10549c92bb980512e12 +806d7bac2d24cfff6090ba9513698292d411cdea02976daa3c91c352b09f5a80a092cfa31304dcfcd9356eaf5164c81b +934ed65f8579ee458b9959295f69e4c7333775eb77084db69ad7096f07ad50ad88f65e31818b1942380f5b89e8d12f1b +aaf50ca5df249f0a7caf493334b6dca1700f34bd0c33fe8844fadd4afedbb87a09673426741ac7cbbb3bf4ab73f2d0f3 +b2868642cfa0a4a8a2553691c2bef41dab9dff87a94d100eaa41645614ab4d0e839ec2f465cc998c50cd203f0c65df22 +a326513112e0b46600d52be9aa04d8e47fe84e57b3b7263e2f3cf1a2c0e73269acb9636a99eb84417f3ae374c56e99b0 +97b93efc047896ddf381e8a3003b9e1229c438cc93a6dbef174bb74be30fac47c2d7e7dc250830459bed61d950e9c924 +b45e4f0a9806e44db75dbb80edc369be45f6e305352293bcae086f2193e3f55e6a75068de08d751151fdf9ebc6094fa1 +87f2161c130e57e8b4bb15616e63fa1f20a1b44d3e1683967a285f0d4f0b810f9202e75af2efa9fc472687c007a163f7 +8f6400a45666142752580a2dce55ef974f59235a209d32d2036c229c33a6189d51435b7ea184db36f765b0db574a9c52 +a0ee079462805f91b2200417da4900227acde0d48c98e92c8011a05b01c9db78fc5c0157d15cb084b947a68588f146f4 +ab0612d9bb228b30366b48e8d6ae11026230695f6f0607c7fa7a6e427e520121ff0edea55d1f0880a7478c4a8060872d +ad65dfde48f914de69f255bb58fa095a75afe9624fc8b7b586d23eb6cf34a4905e61186bc978e71ccb2b26b0381778a6 +8c8a4847d138d221c0b6d3194879fd462fb42ed5bd99f34ebe5f5b1e1d7902903ec55e4b52c90217b8b6e65379f005a4 +a41dca4449584353337aef1496b70e751502aeed9d51202de6d9723e155ca13be2d0db059748704653685a98eaa72a07 +ae40e5450fd994d1be245a7cd176a98dd26332b78da080159295f38802a7e7c9c17cc95da78d56558d84948cf48242cd +863878fda80ad64244b7493e3578908d4a804887ad1ad2c26f84404dcad69ea2851846ad2c6f2080e1ed64fe93bbec31 +b262fb990535f162dc2b039057a1d744409a3f41dd4b70f93ff29ba41c264c11cb78a3579aad82f3fa2163b33a8ce0e1 +a7f6eb552b9a1bb7c9cb50bc93d0dda4c7ecf2d4805535f10de0b6f2b3316688c5e19199d5c9ec2968e2d9e2bd0c6205 +a50aa5869412dc7081c8d827299237910ecec3154587692548da73e71fa398ff035656972777950ba84e472f267ba475 +924c3af750afc5dfad99d5f3ed3d6bdd359492cff81abcb6505696bb4c2b4664926cb1078a55851809f630e199955eb3 +a1acffa31323ce6b9c2135fb9b5705664de8949f8235b4889803fbd1b27eb80eb3f6a81e5b7cc44e3a67b288b747cf2f +8dec9fd48db028c33c03d4d96c5eecea2b27201f2b33d22e08529e1ae06da89449fe260703ac7bb6d794be4c0c6ea432 +aa6642922ccf912d60d678612fffe22ef4f77368a3c53a206c072ed07c024aa9dcde2df068c9821b4c12e5606cfe9be2 +a16ddf02609038fcb9655031b1cb94afe30b801739e02a5743c6cd2f79b04b2524c2085ca32ec3a39df53de0280f555d +b067d48589e9d3428c6d6129e104c681e4af376a351f502840bbea6c3e11fcbfdf54dadf6f1729621720a75ff89786c3 +b14a24079de311c729750bb4dd318590df1cd7ffc544a0a4b79432c9a2903d36a0d50ecd452b923730ade6d76a75c02c +97437bac649f70464ace93e9bec49659a7f01651bba762c4e626b5b6aa5746a3f0a8c55b555b1d0dc356d1e81f84c503 +a6f4cb2ffc83564b1170e7a9a34460a58a4d6129bd514ff23371a9e38b7da6a214ac47f23181df104c1619c57dff8fe2 +896d0f31dfc440cc6c8fde8831a2181f7257ffb73e1057fd39f1b7583ea35edf942ad67502cd895a1ad6091991eabc5e +9838007f920559af0de9c07e348939dfd9afe661b3c42053b4d9f11d79768cba268a2ee83bb07a655f8c970c0ee6844b +b41b8a47e3a19cadec18bff250068e1b543434ce94a414750852709cd603fc2e57cd9e840609890c8ff69217ea1f7593 +a0fb4396646c0a2272059b5aeb95b513e84265b89e58c87d6103229f489e2e900f4414133ed2458ddf9528461cfa8342 +ae026cfa49babc1006a3e8905d6f237a56a3db9ddf7559b0e4de8d47d08c3f172bde117cdf28dfdfd7627bd47d6a3c85 +a6a3f3e7006bc67290c0c40c1680bf9367982eb8aaf17ecb484a58c8e9c2a7c24932e2caa9aacc9b4fbf4c0abd087a46 +9093e05bd814177a01a3b8d7b733db66294e1c688c56def6e1827c0f2d9a97cf202721641bf81fb837f8581ae68cb5ce +87feef4de24942044f47d193d4efc44e39a8c0f4042fba582f2491a063e3a4640cb81f69579b6f353b9208884a4f7ce6 +975f9b94e78aac55bd4755f475e171e04f6fbddb6fd3d20a89a64a6346754a3ff64ecff8c04b612a1250e1d8d8a9e048 +87cde4d0164922d654cf2dc08df009e923c62f1a2e3b905dfde30f958e9e4dd6070d9f889712acd6c658804f48f3edb1 +ae8e22e158dda90a185eec92602831b5d826e5a19aab8c6400dba38b024c7d31c4cf265eb7b206dd45834f020b3f53cd +a4475807adc28aa086e977b65bbd7c8512119318c89d2619ea03a6739a72c3fb90c9622451896c7113ad4d12a3004de6 +97f1ae1e0d258a94532c7b73fa8ebdbbd53349a4d2d0a217fe56dfdd084dd879960bc6ff45ebb61b5dbf2054642800a4 +b3c832bd3691332a658b0caaa7717db13f5b5df2b5776b38131ac334b5fd80d0b90b6993701e5d74d2b7f6b2fd1f6b9d +a4b6af590187eb1b2cb5ae2b8cffa45c5e76abdb37cec56fc9b07a457730f5af0706d9ce0a17da792bbece5056d05670 +97b99a73a0e3145bf91f9dd611a67f894d608c954e9b8f5a4c77e07574064b3db47353eba8038062cebaad06a2500bab +8e5ca5a675de6e6d3916bd9ce5898bb379372afe3f310e70ff031bc8cc8fabfb7f3bfb784f409bb7eb06fdb4511ee477 +aabbbee4da1f16b5bbe001c19debe04745932d36dfbbf023fbf1010a2b1d54eb92fa5e266ac1e9337e26e2ddba752f40 +b13447c77496825f48e35c14f9b501c5056e6d5519f397a2580cea9a383a56a96994d88926aa681142fe2f1589c03185 +b89c55db39ff0e73dde7435b61e8a4d3e10f51dd8096cbc7f678661962e6de3d16f2f17a0e729cc699234cb847f55378 +82c36b7de53698a1bafbb311fefc6007fcefa47a806ebe33a4e7e0fc1c7b6b92a40a1860702cf9295a16c6b1433e3323 +8daeec8c88543d09c494a15cc9a83c0b918d544311fd2a7d09e06cf39cdebfa0cfc0e8fc0e3b5954960b92332f98697c +b18e55a1a7ae16be3a453d2bfa7659a7ec2d283dd46bdc82decef6d3751eeafc4f86f2416a22955c7e750c0582d4f3eb +b50c743462e2915bf773848669e50a3bcdb5a9ac5f664e97eaccf568c7d64a6493d321be0225de16142ce82ce1e24f66 +af69c9643805fb860434424b1608aababc593aaebc6a75fc017f7f62bb2b1da932b0b9bd5e6dcbba328422dafc06efd8 +b5947db4f809fd0d27af838b82eef8ab4fe78687a23ebc61c09c67eb7e8d0e6a310ecb907fd257859d5a2759a07c21cc +92c7960e163ca5bdf9196c7215102f8e9d88efc718843321c6e2a6170137b8ecec4ea5d5a5ce4c28012b6cdbd777dd01 +b63f9509ed5e798add4db43b562e8f57df50d5844af6e5c7acf6c3b71637c0a2d2433f4a0627b944f0af584892208bb8 +8ef28304a9bfe5220af6a9a6a942d2589606f5dc970d708ef18bc7ed08e433161020d36fb327c525398cd8ecb57002f9 +b722e0410f896c4462d630a84a5a14e94289fc38ed6d513ca88a09005935cec334c480028efa1943c7a5e202ae8c8379 +b56b6672b488e64d4dde43571f9ceaa7e61e336b0fd55bb769a57cd894a6300e724e5f88bad39a68bc307eb7406cb832 +8bf493da411fd41502b61a47827731193652e6ce3810709e70869d9aae49e4b17a40437a7a0dcc0547dbac21f355c0da +9613b60a144c01f6a0e7d46ddde07402e2133a1fe005c049a56415ff90401765040b2fc55971d24b94c5fd69fec58941 +85e2f02b291563d8eea3768cf6a4602c0ca36568ffcf3d93795d642044196ca6b0b28991ea5898e7974ee02831a0ec70 +b08ef66703dd9ac46e0208487566fbf8d8654d08c00f03e46f112c204782ccc02a880a3f9dffd849088693cee33b7b6d +a0b19eeda6c71b0e83b1f95dffef4d370318bdea6ea31d0845695e6b48d5c428c3dbba1a0ded80964992c4a0695f12ee +b052642e5772d2ef6f49dd35c5e765c5f305006b2add3b4bee5909ca572161edf0e9c2bc3bc3bc7f56fd596360ef2201 +8261af164c768fec80d63fca6cd07d1c0449e9ca665fe60c29babdbd8a2b20cf1f556a4b24cd7341712468a731c21b32 +8a17016a1b2fc0fa0d9e3610ea80548fcf514e0a35e327f6b5f8069b425c0f0829af7e206013eab552be92b241be5ac5 +8eea25c680172696f5600271761d27ef4c8cec9ab22f01f72b2c7c313a142fafaec39e6920b96fcace858883e02eff7a +b8e0c590106e125c5bca7e7a071cc408b93629da0d8d6381f1b73fbdf17024a0cf13f679f5203a99bbbcb664b4a94e88 +b9943b29395258b7afdf1781cfaf131297a4f325540755df73401b2ec4a549f962952e9907413c39a95585c4aff38157 +8286eab4a04f8113fb3f738a9bc9c2deaf3a22bf247151515568703da4efe6450ab3970f5c74e978a2db7e8d795331b7 +a10cf383c8a7e3f0a0a5556b57532170ff46dabdcbb6a31c4617271634b99540aa575786c636d3809207cbf1d2f364d3 +a5af7eb998140d01ba24baa0e8c71625aee6bd37db4c5ff607518f907892219ba8c9a03c326b273bfd7068232809b73c +aed5f461e38fccc8b3936f1328a9747efcbceb66312f6d6eddce57c59570852767159f1a7d9998f63342515fef4ba9bf +aec3e94b029aa692bfe2b8dbc6c3b0d132b504242e5ebe0cad79c065085e2fc05550e5cdaa2353892a40ff1a062dd9eb +87c23703960129396018d0347f5dd034abdbd57232b74195b6a29af34b6197b3cd63c60ac774d525add96ae54d5c0fb4 +97964a7768216e1c84dece71ce9202cc64b6d483650aa6f6d67215f655f66cda14df0a0f251db55832c77bfd9b6316e2 +8167aaf24c8a023d0aea16b8c24d993618b9d0c63619e11a28feab8f14952bafcb0918ed322cbc0ae1b2e1786071819b +b58318bd62852ffb712fc58f368c21b641dde7b3fa7d7269974c7a7b5b3e1641569fc7b5f32ca49de22f4f993506d92d +b172e7911d5cd3f53af388af847b928947c711185aebd3328f8e6ed1106c161ae0c1b67d3d9eb237e9e66eb0672edec0 +a6834cf69b2c4433cf6e779bfbb736b12e73e71e149c38101d13dbacf6c5048db53994a6a039381df40bbd67de40fcd0 +882604aa3bb19fffd6db744b5cf4a2431b157dac06d0617e0703684a118ca90b2d22a7758a1de7732a7144e68b11b7f7 +addc128ba52bf7553b9ba49eff42004d388a02c6b6e9809abe1c0d88f467e5ff6cb0c82a8fd901b80dfc9a001f7b9997 +abf19604a3f0cffefa7a9ced81627f6aacb8d7267b52b825f25d813d9afa24af6d70da21450ed93eaff8b4d2a9b905a9 +a3c67e7bf02dbca183d86924611a7149556ee17cb3469793624da496b6c25617a9071925dd02aab9cb028739cb79043d +b1cea4284a3ac4d5b1c6f0947c6ec8365b3281ed15495bf328a907a9a02cdd186e7cb1ef080385b3399df786855985a9 +a6edb126314559e6129caf1111dc3c82ff914efce658b11f2c9b48081be1cf3f46bde482469d493379025a158d95ab1b +9843fd7dd424da1acc6f92f87fac364a8b0d4097d74b6b451386384966c85145d43fc6ecedf04271b0f963ac731fd93f +83852bedca03a97a2e63053cb102387866cbefe6707ebb6dae2d32a59c343079f1a863f299fd64d0ecbe024d0a1247d5 +a570e645a0679ebc6f0ca03cc8f7367b03c3886f3d9c787992de7f3e93360a170d3ac9ae7720999c727a887b1dc762bb +ad644c40555238f28844eed632c8972b63d2602098031d53b5599d1a874903e0d0c428e0ab12a209ea3fb31225578f1c +b64e9f92a14812ed31075f9fdd3324659a036ef2f293ef9ca6f6feb87d0c138e1ba74bc36a910afd22ff9b3c8ec7cfa5 +8f2d75a86d517dafac09b65596f4b89c4a9c0a7003632407504153fa297c9e3228e236948a5d5224b8df49a087c8e0e3 +b02d6ab9292ae336c8a74115f33765af2c9f62c331d70c087cf4c2979792bb3c2666f6699c017f8d4c6b378fd4bda86a +a923d660d2e55228b8bc74f87d966069bd77c34a776fa96f37b48539c85634482e514e2cb76cb8eb20efd85eb9c83fae +81d7ffb53090a6d512055ecfd582ca92805525a05654e39bb12653a6a8902a16e651ba7b687b36b8bea7186632c7e9e3 +83e9b33e29b57ae53d9f72bd4622ff388252333b4fa32ad360a5b00f3ffc8813b9cb8a1361454d3bb7156c01b94b6a08 +ad7d6bffe4d67eb53b58daa3fc8a5a60790c54fa42226ae12847e94c6de3b4365b3be39855a4f6a5f12e4803cdaed96b +a7709fed85abbee5a2fa49c5238582ec565da08c132d4912821491985bf83b681eb4823634bfe826abd63a6c41a64ea7 +b8fb6ed55741132a1053b6ca77bdf892e96b048488373ba4aa2f2225fae6d578724124eb6975e7518e2bf3d25d215763 +85e0c53089529a09b5bce50f5760af6aeafef9395388aa4b6144ca59953169101783347ee46264ec0163713a25fe7c63 +8f9e47a9c37b678e56c92b38d5b4dab05defc6b9c35b05e28431d54b1d69ac31878c82c1357d016f3e57ca07d82d9c16 +a81f508136ee6ec9122c48584df51637f768ccfe8a0b812af02b122a0fafa9abcc24778bf54143abb79eccebbdde2aac +931a96d2257a4714d1ef20ac0704438481632647b993467e806b1acc4a381cc5a9dec257e63239ba285deb79f92122dd +99fb0ff747bcd44b512bf8a963b3183ce3f0e825a7b92ddd179253e65942a79494a515c0c0bc9345db136b774b0a76b0 +a9dbb940b5f8ab92f2d85fc5999e982e3d990fe9df247cfc6f3a3f8934fb7b70e2d0362ba3a71edc5d0b039db2a5f705 +99011a1e2670b1b142ec68b276ff6b38c1687eed310a79e2b902065bc798618c0cdee7b2009ad49623ed7ae0aa2b5219 +9361e9f3aa859c07924c49f3d6e9b5d39a3df2fc1c10769202ec812955d7d3814c9e6982f4df3a8f3bdbfb4550cd1819 +a8aa23f177ddc1e7a7856da3eac559791d8b3f188c0b3ae7021bcb35dfb72b0f043c3699597a9188200408bc3daf6ab7 +a5a502ff673f6dab7ae4591a7b550c04ede22a45a960c6b5499644f721c62b12b9e08248e7f8b8a59a740b058d2a67e6 +ad374f80f0b52bc5a9491f79a547ce5e4a3ce4468a35d7dbca8a64083af35ab38eff9aa774ccba2e2e1e006e45cb0b85 +ab6851827125e3f869e2b7671a80e2dff3d2d01ce5bfbeb36cbaf30c3d974a2d36fd9f7c3d331bb96d24b33dbd21f307 +96658f6a2d225a82f7ccee7f7a7e476967e31a0cd6c62859d3b13ee89702bb821547f70ffd31cb46a6a0d26a93158883 +878f59ff2590bc3d44fdc674717589800748b78d543d3c0dbb50125b1d6011d6a083f10ab396e36b79f2d89b7cf51cdd +b8bdfb97829c5d973a15172bfe4cb39620af148d496900969bd7ca35de9b0e98eec87af4e20bef1022e5fb6c73952aa0 +a292a78b452743998aee099f5a0b075e88762222da7a10398761030ffcc01128138d0f32fccf3296fcbea4f07b398b5f +85da44fdd7b852a766f66ba8804ed53e1fc54d282f9a6410106c45626df5a4380cbea2b76677fdfde32446a4d313742a +84bebf036073d121e11abc6180cba440465c6eaadc9a0c0853a5f1418f534d21cccf0cfc62533eaeae4653c7b4988046 +923dec006a6af04ef675f5351afffffd2c62a17a98f4144221927c69f4553dd105e4fcc2227b5f493653d758cd7d0352 +a51eda64f4a4410a1cfa080d1f8598e23b59856436eb20a241e11106989fbbb48f14c2251f608cbf9531c7c442b30bf7 +ac6d26ae7bab22d49b7fba7fe4b8cf6d70617977008c8290787c9da1a4759c17c5e441efb3dee706d5d64d9d2ace1de5 +ab5138b94d23c1bf920b2fb54039e8a3c41960a0fe6173261a5503da11ff7b3afdb43204f84a99e99888618a017aac1b +8c85647a91e652190eee4e98a1eec13a09a33f6532926427bf09e038f487e483f7930fbe6ff7a2126ccde989690dc668 +a6026ab87cffec3e47b4c9673957d670cb48c9b968d2ad0e3d624d81c1082dcebbc70d0815cbd0325e0a900d703a6909 +ac4f6ff6baf8374a3c62bdd5a8d207d184ff993f6055bcee1e6dcc54173d756c37c24570d6462395add6f7871d60b1ae +a0dd6bc93930d0016557588f2598b7462ca48cbed637c8190be0fb4811e4576217ca9fc3c669c2a4db82e3f8bb24acaf +a67c1d79f7e7193a23e42928a5cc6a6e8e0c48b6b286607dbcfaaa0f10a7ba29ad62d1d57ca28c486794f0908bece29c +822f411bab4882202ed24e67c84e0c9a8da5b3389804ed9dfba0f672e3e1457ea76cad0cb935dbb3d7a39500fba5fe12 +8a1198572323689300a9d7db2e2bcb7c519392e5d3d33e83cd64bcf1517a7dde52318a98203727b186597702c0eed258 +8a84141b02f1d037c68d92567d71cda3a0b805d1e200b1d3fff3caf9902457cbfbaac33157b87ab0bb9e4fe3bac882c3 +8070ace16d9eef8658fdcf21bed0d6938f948f31ca9d40b8bdb97fc20432cd2a7ef78eeefc991a87eae7f8c81adf9b19 +9522e7123b733ce9ca58ab364509f308a1ead0915421ccede48071a983fd102e81e1634ffa07a9e03766f167f5c7cb5e +82cbdf97a755e952304f5a933fd4d74a3038009f242dac149595439130a815e9cc0065597c0b362130183a4c4a444173 +81e904f9b65cd7049c75f64c7261e0cbb0cc15961ffcac063d09399d0d2b0553b19e7c233aca0f209f90cf50c7f5e0b2 +8f5f6ea87429542ea04ad3eb5fc7eeb28fcf69c01c1a5d29b0de219524f6fba90c26069bfc9092379fe18cb46274393a +a4e5815481eb33b7990d2de1a3a591c1ab545b64fbeb4cff8c71b6bcb04d28940097899062bf43b27c5a8f899616703e +a7afe6066681e312882b3b181f462a1af2139d9bd2aefffae7976f3fc357bfd8fbd6ddd4e5e321412f107736e77f0cb6 +b8ab102d7ff8d46b055095d8fb0ec2f658c9e18eee523c295b148b37f8342c120798113553b8bfebf2a11f27bc704cc4 +862175ecc7e0e294c304a0352cd0f1d11b2603d326bb0e54e02b6cc8d04d01ac31c8864e9395aa1f3b90b76bc4397f5b +a4ea51ef3d82509f0e4eb6af705fa7530921cf9512cb5bf030571e69f4504a299297219a0a7e40db1b45165a5ea3a3f2 +a6fb8b573e2ba6db0e8aba53a489e99bebe533c0fcd947dbfa732e00594f03f4e8609ccc44d8215986d38bc3d4e55d48 +93fe8e0bdd5d66df2bd18be5963e864bddfcdcd3298590e7c3b11d99a070a4948fecef46453f19960bbfeada37979613 +acbc45bc55c7080b45c69a3db80cbfc0267006dcf49c47330975aeff2a8ac07b206e1b1c3a515e50866ff510739b92c0 +94a577df0983e4ee3d6b80c73d7e8e3bb78bd8390ff56fea350e51bdf5e0176b8494e7e81dc7b1d842ada961089cd1eb +81eb1fbe9e9c89f5818d0ef98e694da86e88625f0a37cfe88e6de69f90e58297e67f1d5c9d71263b523b63e42685975a +a81a2391ea4d0f65ab4325196559d67e2648b3f1e464509430b40d9948d5b0fc01c337d9b51048a93c4d62e6b73e1e8c +849a026e55ed77135138836c9df67883763e4602357d8566da2ee2505d135d44061de0c070cf333ffb9ac2e55a0894b2 +8e272cc5734374c003c7b2e6ba833eb99b6be608da04e576df471c24705b6b2a790549c53e7971df2d9f0b88d0f570c6 +b0f9e6d985064aa311d4a147f41007fdc576b7b9194aa4b8712bf59a76a71543fec2ee3db21bd3d30d4096f25babc543 +96331837f0d74e2ba6cb1bfaddf4b1fb359bf46cb6c3c664938eb030e56bc85a5ce17bcd60b7fa7b72cb0ba1f3af0b5b +a0eaab6de4b5a551896e7d26153fb5df4bc22a37833ec864090b57b5115b0f8f1279e855cea456bb844802b294b0dbb7 +955e87d3b966edff34f28137f871881c59bbbc6d69986b739867807680ca22b5e3272ced1d25854ed9700d87f133848b +9270a6db157a8ce78a1af6bfe2b5bbe7b621d56cc8f9940a03b5a5f600848b87b05d83595b2a3a315d4b7f4687c46085 +9043328f2dd4dd85e14c91237a3478dc1eed239164924b53d1de9364d76c81315afa9639b58eedb1ab2122e2ae2e7cfb +857fe9f7d00b03bce367de7f789d755911a5f85d78044f18311ecd9b955e821b4a50228347260ba1205aef61219001fe +a0f878050367a7103fddf380908da66058ef4430eae1758335c46c24f5c22fefb0753991b3a47dba5c7eaafa4d598178 +ab5959296b1af14d2878816c7da9926484cbf8896b7eeac8a99dc255013319a67a0209025e1f8266ffd8cd7d960bdc87 +abe53abc57ea46419dbe0ac1f39eee39a4feae265e58b50928eb0695e25938a16a8b00e65c1313837dc3367297e2c258 +93e3e42ed6ba9c45d4e7a4bf21c1e469efafded1f3be9931a683dbb780db2494742fd76c9ad29fd7d12da2b778ede543 +ab3e64035c488a6e63496ddb2de9648cc63a670c5d4b610c187d8ceb144fcc50b016046f50b10e93b82937ebe932ac08 +a3a8fa898f489b313d31838ad9f0c7ffe62ef7155de5da9ffe6ecd49a984fac3c6763e8cb64e675e1c4a0e45e7daf078 +8356b26aa7c9fc9734b511480dad07b164cfec1324ad98eec9839a7943f2889d37c188d465515ad4e47c23df641c18c3 +83c4476f829e0fe91da2353d5b58091e9335157941e89ca60ccab1d7fdd014bcf21bd55249805780ddc655c5c8c2536e +814f6e66505b2cb36de92c0de8004d6d094476522e66b9537787beff8f71a1381ed9f2b7d86778979ad016a7dae6cbac +b1cd7f6da4a625b82bea475442f65d1caa881b0f7ce0d37d4b12134d3f1beb3ad4c2f25f352811e618c446185486adb6 +a71b918481b9bda667de0533292d81396853a3b7e2504edd63904400511f1a29891564d0091409f1de61276d2aebc12a +a2cd3d4104ec5fb6d75f5f34762d5e7d2ff0b261bea5f40a00deec08fbdab730721231a214e4df9b47685d5bacfe37c6 +807f2d9de1399093bf284814bc4093f448f56a9bde0169407cdc0e7d2a34ff45052aef18bcb92f0ac7a0a5e54bd843e9 +abeb03010c3ac38587be2547890a8476dd166ac7b2a92c50d442f031eaf273ad97114c38e57fe76d662c3e615334ac0b +b90a688da4b0bf65ff01bcf8699f0cba995b3397fcbe472e876ae1091a294463e4b94350ae8bd5c63b8441089e0884fd +ad88db4afb177931788fb08eff187e15ad739edc7e1a14c8b777b6bf668aec69ca4749773f94250c1fdda3b59f705f7c +9886809f9ae952797c6527c6db297d2aa3d5209b360efe6a19970575a9f78aee3c21daadb8e8dfcbeeea5290238d16d9 +930f486e95d7c053c9742e6f0b31e6d4fa2187e41229e46a074b469aafb87880aa8e972719b363049fc9fe2db8f03ce2 +8d229af4fa08bd8aeb5fd9acfee47571eb03fcd2f19073b94cd27e2a6735029d31f123249d557f8d20c32ac881eae3aa +84576ed5aebe3a9c3449243a25247628993fdb2cc327072418ea2f1d11342756e56e9a82449bc3ea6e8eaecabc62e9b5 +b775cb86cbec9c46a4a93d426379c62872c85dd08bccda39b21cb471222b85b93afd34a53337b6d258f4891c6458e502 +8be1540e6b535b416b8d21e3ecf67dfb27a10fd4010f9f19426422edaeb0a4961d43ff3afd1db0994170056ce4d77aec +b9c7438e90a5501a4d05bbb8ab68d6db7e9baa8927231a5c58715ee2ab76ca1da0e94910a076958654869148d813d0e9 +aa9bed1c4d2e7cbc2e1a884c8998773f7cc6fa9d6493c8abe8b425114a48305c3a43a1abda2292177ffd39ef02db4163 +897b395356047cd86f576cfc050f7e4546ecd4df30b2c31ed8945797b81dd4ed9b9106cfbe6d7dd8bf91882e3cf1f42e +949a37e1037d9464b2ccd3ad23eda7089570d6b5ffa18025d2548a9df8829de8d62960f04a603f21eecbca5893d45284 +b8a0642f68ff169ffbcd8cd684fae75d96f9bd76949472775bf155edc55a3d9c3e6f0299ee73a6cfb96289361fdbe9ee +a1273141510fcddd89b9b92c19a268dadd1528ad85744b8174684c9b56668e6b35dabb05f2b4cc6ef5611eaea6052f27 +97c7415c82de83ecc066eb922268b8205ad7266c65b2b8f7e0aadac87f076c738cea72f9b0f069b8d28cf9d5438b8287 +b32c7005380c848f71092a74297555dc6022369fc2a4f285e586ac8f53f6bd354fbe4b1f8a4cfb406a101103bf87bb64 +91b48eeba52f02d04f536d32112038f8ba70bb34284fbb39e0f7bae2e08b3f45ad32e2f55d1beae94b949c15652d06a1 +99e24f5ea378cb816a4436af2ee7891ac78a2e37c72590be0abd619244a190fee51fc701b6c1c073611b412cb76332c9 +9465d1e73a1a0a5f7b1cd85f4fa4f5dee008b622b14d228d5cd5baeec174451e7ae93c5de688393d37cc24ce15df4139 +a6ac3986ee01debdacb5ddc1e2550cb4f039156df15c7d5752b79f333175b840bdca89c4959a523e58cf97bbd6b2039e +b7f7a5cc1b1b6145988170d619c170c130231abbe0b5143a9bccaaebeef9ceb1c16e26749bc9dc5650fe91f92fa1b79b +854cb04f1557457383a401d79a655adfd0a4b706ea2bbc6262949c8d657efcfdc9c7960cbe1a50b5eebb361c5e378f80 +8dd199dccbdc85aeca9ddcb5a78dd741a452f7a0d3ceb6546d76624bad2fce0e7e6c47ee30d60bf773f18d98503e7f9c +889e1ca9f0582be9bf5f1aede6a7312b30ea9bed45ab02d87182a013430f16007ae477ee6a823ae86c7fef7da016a0ec +892a60e63edfb3e7a6cf2d0be184413d214401fc1e6c004ca2902c3f1423728bf759a136e6e715d26d5bb229c75cc20a +a2287cd092261b39d22dcb1fa19512590b244771bb69fb62eda72f12be37d48e408b3e37a47608f68d743834edee7f15 +b3b6afb950bbec0ff631bdf18af433e68adc63d02cb479704f24329ca6b6edd9a3d1d606563dbdce6038b676b85130b9 +847da90f37b294509de51ab6521fdff12d5a1ec3cccaf730aa744da7e54b85fd9c70618787e87c0ba9947ce6c81387fb +ad872153c00bccac75bdb30d1ab7044d814f4f8655ff26421d48fea04fb21d4dc82c1900620a57d13adc45c1062a1817 +90fa5ee98fd7ec719f2a8543bbd0ff45ac69296c2416fc8666d05de3deea1017079a68aba55540a19585925803c8335d +962ba6d029e9176d0e8c80a21f2413f7322f22a9e9a32c933697a8b0e995ce25bea5264736a75718b3d330e215a58a05 +a446f9530db30c5e9c1b3844d635e5c2cd311cc4537ff277fe83dd1a0382bcfa73beb07aaa0cf5a97d24c67e688086a4 +8766b2053f16c72db387abe18b43d7b357a542916c9b8d530ee264e921c999494d6eb1e491352ecdf53758640c7a246d +83f32f511f7b0233662acfc14f30df345af99d2d6c777ce0b4bcdc4dd110533f30b45071df17230aaec392cc482355e1 +82e3521bc9519b36f0cc020225586b263e4feb57b533b38d8e89ccf8d03f301d94da90efb4902002732fbf3876697f38 +b5d1ea69c97ceaa34a720bb67af3fcf0c24293df37a5f6d06268b1eabe441531606954ac2598a1513f64231af722b3a3 +956842696b411e6221c5064e6f16739e731497e074326ef9517b095671f52a19e792d93fe1b99b5a99a5dc29782a5deb +b19b5658e55c279eb4b0c19a0807865858cbec1255acd621f6d60c7e9c50e5d3ee57da76b133580899a97c09f1dd8dac +89e6a8b916d3fcc8607790e5da7e391f6bc9eae44cc7665eb326a230b02bc4eb4ef66e608ccc6031048fc682529833d0 +b1a210bc8070ed68b79debd0ec8f24ec5241457b2d79fd651e5d12ceb7920e0136c3e0260bc75c7ff23a470da90d8de9 +85b1954278e2c69007ad3ab9be663ad23ae37c8e7fa9bc8bd64143184d51aea913a25b954471b8badc9e49078146f5ac +98bf63c7a4b200f3ce6bf99e98543925bc02659dc76dfedebe91ec5c8877d1271973a6e75dad1d56c54d5844617313e1 +b7404b6e0f320889e2a0a9c3c8238b918b5eb37bcdab6925c9c8865e22192ba9be2b7d408e1ea921a71af3f4d46806d0 +b73cbbebf1d89801aa838475be27c15b901f27d1052072d8317dcae630ab2af0986e56e755431f1c93f96cd249f2c564 +95b2027302f7f536e009f8a63018da6c91ec2b2733c07f526cc34cbcfa2f895ccfd3cc70be89f4e92c63c7ddc2a93370 +9201d9ff5d0b1222bfa2345394f88ddf4fe9282acf51bee9b18b96bb724fdf8e736d7101acc2795a34e72f9e0545c9a8 +acbff7eb160f427d8de6f29feeddfa8994674e033a0ccdc8e8c73f9243968f1a6379da670a7340f422892d50c97113c7 +97ae8d03352c3729e1623e680dd9664f303b3bcfb844ef80d21e9c773a247967d27b86c9326af29db5eefd0bd3d4fac8 +8e53ae5c22f5bfa5fe4c414dad6a10b28a3e5b82a22e24a94e50ce3b2bf41af31e7ba017d2968811c179017b78741ef0 +b5ac7dd150247eb63dfb7dd28f64b1bf14426dc3c95c941e8e92750c206c4c7f4ad1a6b89e777cfe26ecb680dbf0acb6 +99ae2e4652ea1c1c695e7ea2022fd35bd72b1a0d145c0b050da1be48ad781a413dc20fbda1b0b538881d4421e7609286 +b8abe1fb3a7443f19cd8b687a45e68364842fc8c23d5af5ec85da41d73afb6840ef4b160d022b2dad1a75456d809e80b +842619c3547e44db805127c462f5964551f296a270ed2b922e271f9dc1074fdf1c5e45bb31686cec55cb816d77853c01 +902dff769391de4e241a98c3ed759436e018e82b2c50b57147552bb94baddd1f66530915555e45404df9e7101b20e607 +82e4f2ee7c7ca1ee8f38afa295d884e0629a509c909a5464eb9ea6b2d089205478120eed7b6049b077b2df685ec8ba48 +aa21a68b0888e4a98b919002a7e71e6876b4eb42227858bf48c82daf664c3870df49e4d5f6363c05878a9a00a0bcf178 +a8420cd71b1d8edd11ebc6a52ba7fc82da87dd0a1af386d5471b8b5362c4f42718338bcbc302d53794204a0a06b0671d +98c686bd3a994668fbbd80c472eed8aedd3ab5aa730c8d3ce72e63fb70742e58525437be1f260b7ecc6d9d18a43356a0 +aca0b2df9ec8ede0b72f03b121cded5387d9f472b8c1f3a5f1badd5879fb2d5d0bbb6af1a2dd6bdebf758cfceadbe61d +93b1abd9cb41da1422d171b4dbf6fbcb5421189c48e85c9b8492d0597838f5845198494c13032e631c32456054598e1d +a246ab3a47f7dc5caedc26c6c2f0f3f303ed24188844ab67a3da1e793d64c7c7fe3e5cc46efafbd791b751e71de0614c +b9b52095ca98f1f07f3b0f568dd8462b4056c7350c449aa6ce10e5e8e313c2516ac4b303a4fc521fe51faf9bf7766ce9 +8e2e9d26036e847c2a2e4ba25706a465ac9fbb27804a243e3f1da15dd4084f184e37808661ec929479d3c735555085ee +8b8c4f4ad5c8e57e6a7c55d70ef643083d4b8dac02716ea476d02dbbb16c702a2f2d5dd5efe3aec7704d2b8cdafe3959 +a800afea30d0df333805d295bac25419b7049d70044be00c7c85a92a0503ca471001bc1e6552323f1a719eb96616fc20 +868bced4560e1495b8527058ebc82a538b7cf806f8d8fe8eeed6981aba771de4d5e9f03cbfc7157d38b9f99cdea87b96 +86b86258b0c1feb988cc79f6c4d4b458ff39428eda292f9608a5fc4c3765782c8c23c66f82d7538e78e092cd81d69a56 +9370eac15de2555824c7d48520a678316a7bb672e66f8115ad7dbc7c7b1f35a7718e8fa0c35f37e3ef2df32dfa7ca8d1 +ae200bc5be0c1c8c6ec8e9fd28b4d256c6f806c0f270766099e191e256d67b9cceda2cc2fed46dfa2d410971a7408993 +af2428c77b2b9887ecde1ea835ed53c04891547fb79fe92e92f9c6009cdfffa0cb14de390532ad0ef81348b91798bd47 +a9069eef0316a5d13d1aa4cef0cf9431518f99b916c8d734bd27b789828ae03e5870837163ea6ad0be67c69184b31e8d +b1b1ce6d529f5a8f80728173b2f873c8357f29644b00f619c15111224377ae31a2efb98f7e0c06f5f868030aab78ed52 +b89c98beef19ee7f300e1c332a91569618ef8bf2c1d3de284fc393d45f036e2335d54917c762f7c2874a03fe4f0f6926 +8264f993dceb202f8426339183157e9e0e026d4e935efe4cf957eb14cd53edcdc866305fb1334cdf0e819b69eafbaccf +aebd113f73210b11f5ac75b474f70a2005e5c349345003989175dffa19f168abd7f0e28125b18907502fff6fcc6f769b +9993ad061066ca6c2bb29fe258a645089184c5a5a2ef22c811352749a199be3a3af3a0d5ce963febf20b7d9e63508139 +97952105000c6fc6c2dcae1ebdb2feae64f578d26a5523807d88e6caf1fe944b8185e49222d06a4553b3bdb48c3267a2 +82dd955f208957d74693bed78d479c9663f7d911f68ff033929418eb4a5c5dc467589ca210c1ba3c2e37d18f04afe887 +b816fc4763d4c8a1d64a549c4ef22918e045ea25fa394272c7e8a46dcb0c84d843d323a68cc3b2ef47a5bbb11b3913bc +a7a87ba4d12a60ee459aad306309b66b935d0c6115a5d62a8738482f89e4f80d533c7bba8503e0d53e9e11a7fd5fe72b +92b36d8fa2fdee71b7eea62a5cc739be518d0ecf5056f93e30b8169c3729a6a7ed3aa44c329aa1990809142e0e5e2b15 +8835b6cf207b4499529a9034997d2d3bc2054e35937038deb9c3e2f729ebd97125f111c12816d30b716b397016133c52 +acf14cd6d978ba905cf33b9839b386958b7a262b41cbd15e0d3a9d4ef191fcc598c5ab5681cf63bc722fe8acfda25ce6 +b31302881969c5b283c6df90971f4fb2cc8b9a5da8073662da4029f7977fbb4aaa57dd95b003a9e509c817b739f964e7 +b74669e1c3fa7f435e15b5e81f40de6cfb4ad252fcdfb29862724b0a540f373d6e26c3d600471c7421b60a1d43dbeb0f +861d01615cba6ca4e4ef86b8b90f37fa9a4cc65cef25d12370f7e3313b33bb75de0953c8e69972b3c2a54fe110f2a520 +a58a56820efaf9572fd0f487542aaff37171d5db4a5d25bfb1a5c36ca975eb5df3cb3f427589e1101494abb96b5e4031 +af13d0a6869ef95cb8025367c0a12350800c6bc4ae5b5856dcb0a3ca495211d4139f30a8682d848cb7c05c14ae9f48cb +8c385767d49ba85b25a3a00026dd6a3052e09cd28809d5a1374edf4f02dc1beed367055b0dee09102c85985492b90333 +b5129fc2fec76711449f0fcb057f9cf65add01b254900c425e89b593b8d395fc53bb0a83ddbd3166acc6d2c17f7fc2a4 +86bd01b3417d192341518ad4abf1b59190d9c1829041e6f621068bce0bef77ec3b86875b7803cf84ff93c053c2e9aad1 +a74fc276f6af05348b5fabccb03179540858e55594eb8d42417788438c574784919fb6297460f698bd0da31ce84cebfc +967ed3ec9f1fc51f76f07b956e1568d597f59840ef899472a3138f8af4b4c90861e23690c56b7db536f4dd477f23add6 +b9e678206de4fc1437c62d63814d65f3496be25a7a452e53d719981d09c7e3cae75e6475f00474e7c8a589e2e0c6bfa3 +b028eaffaa4ff2b1b508886ff13c522d0b6881998e60e06b83abe2ac1b69f036eece3ded0f95e9ae721aea02efff17b6 +935f82de9be578c12de99707af6905c04c30a993a70e20c7e9dd2088c05660e361942fa3099db14f55a73097bfd32a44 +96a1cc133997d6420a45555611af8bcd09a4c7dbddf11dbe65aab7688cc5a397485596c21d67d1c60aae9d840f2d8e48 +80d117b25aa1a78e5d92ea50e8f1e932d632d8b37bebf444dcc76cc409322fb8eface74a5dddab101e793ff0a31f0a53 +893229136d5ab555dc3217fb4e8c6d785b5e97a306cdaa62f98c95bad7b5558ed43e9a62a87af39630a1563abd56ec54 +b7ec1973ec60bd61d34201a7f8f7d89d2bc468c8edc772a0ba4b886785f4dadc979e23d37b9f7ef3ff7d2101d3aa8947 +b6080ca201d99205a90953b50fc0d1bd5efd5eadbfe5014db2aeb2e1874d645ab152fb4b0ff836f691b013b98ce7c010 +b546e66ec0c39037bbaa66b2b3f4704a6a72cf1924a561550564b6fcf41fbc2930e708cd5cac1d05e12a4b8ec93ff7eb +8abeed90a01477260f4b09fff8fa00e93afe727e8eed6f111d225c872a67e6ab61d0472ab6add3fe987744e16f7c5268 +8e02342d5cc1836ed21834b9ef81686172cc730f0412479db5f590b0ff7a729a0e986ffed16d6ecafd6b83d65922ca5e +b05660605cf8e8a10c8d3c77cccbe4e7179fa27cc829571f6b722a58e65e4e44d7fe977446118e9da2d2f40af146cc2d +942a00e006baba6d025cbd99297bdb0cbf3d84cddf849b1b5a9fe9ef1745352fad81313cce5d7622d6652096a8fa065c +aace8212b3d8dbe44ac97460a5938a3b803aca9bd00d8a643a859351daf391b22d1fd2a6b3e0ff83cc9ee272a1ad7686 +965a9885a5259197a75a19707a2f040e0fd62505e00e35ebe5041d8467596752aedf0b7ec12111689eceb3e2e01ecfc8 +81d58270a4e7ee0137cb2bf559c78c4fd5b3a613468a8157b6a9c5c0b6ca20a071b87c127d59cecc3d0359237a66d890 +af92b6354fbf35674abf005cb109edc5d95845e3d84b968e6001c4b83d548715dffc6723ac754c45a5ace8cd7dd30a24 +b112caa707f9be48fdde27f1649149d9456857f928ea73e05b64bb62d597801daac0b89165fea76074f8b5770043f673 +b6e7380746da358fc429f676b3d800341e7ab3f9072c271310626ae7f67b62562ff76c63bc9f5a1dbc0e0af87752408a +a45e9e8d0931207ebc75199aa0c983134aa97f771ff546a94a3367bcedf14486f761e7f572cf112e8c412018995fdaf4 +854381128de5bfb79c67b3820f3005555f3ee6f1200046ebbfaee4b61b3b80a9cebf059c363a76b601ff574b8dbf0e6b +aa1b828a8b015d7c879669d5b729709f20a2614be6af6ff43b9c09b031f725f15b30cde63521edda6cd4cf9e4ab4b840 +8f28f6b62c744084eeddcb756eced786c33725f0f255e5999af32b81d6c6506a3f83b99a46c68fc822643339fe1b91c5 +ac584e76a74cafe4298ca4954c5189ccc0cc92840c42f557c40e65a173ea2a5cd4ae9d9f9b4211c9e3dfd6471fc03a1b +a413365df01db91e6a9933d52ab3e5ed22d7f36a5585ad6054e96753b832e363484fb388c82d808d1e4dfb77f836eab9 +8a68c51006d45bf1454a6c48a2923a6dbeb04bd78b720bb6921a3ca64c007043937498557f0a157262aac906f84f9bf8 +b93ff8b6c8c569cc90ee00cfe2fc3c23cccea2d69cbca98a4007554878311635cb3b6582f91636006c47b97e989fe53d +b9a8a44d54592511d74c92f6a64d4a8c539a1d8949916ef3773e544f6f72c19a79577de9878433bd35bb5f14d92f411d +94f066a7e49ae88d497893e4ce6d34edc2dc0b42fe03934da5d4ed264d1620d506fcc0661faa90a6cf5083e1720beaaf +b42b102adef8f42c1059b5ca90fe3524dcd633cf49893b04b4a97a1b932ca4c7f305cebd89f466d5c79e246bad9c5ced +86b560d78d3c5fb24a81317c32912b92f6ea644e9bedfdea224a2f0e069f87d59e6680b36c18b3b955c43c52f0a9d040 +a3829fa7e017c934fa999779c50618c6fb5eafb5e6dec0183f7254708a275c94ba6d2226c5ca0c0c357b2f2b053eea93 +9337dda730076da88798fd50faed1efa062f7936a8879ea4658c41d4fcf18cee7120366100d574536e71f2f11271b574 +853d09a30f4342f5a84c4758e4f55517a9c878b9b3f8f19e1362be9ae85ca0d79c2d4a1c0c14f5eff86010ad21476a7a +b0bc74cb69bdd8fdffca647979e693ad5cbf12a9f4ead139162fa3263bfebef3d085aab424ed8c6220b655228c63c6b1 +88d8dc8faf3aab12ba7180550e6a047f00d63798775b038e4a43a3b40a421a3f5f152a7e09f28ccd7198bb8cefc40c07 +88db2e3b8746415d0c3e9f5706eda69a29d0b9ee5135ad006060be7787f4f1f7069e2e2e693c5e10b7c3d5a949085ae0 +b5bd830d2f1c722188dba2690d21b7b84b92cbdd873a55aaa966f1d08d217bfc8cffe8caea68868f3850b90b4ab68439 +b5ad4be0c9626a33fce6c8501297bdde21b07b88531451912ed41971a4c48fdd1036d8a4994a99a7fbba4a5901a7095e +b0e1337a2a1772191faa91302f1e562e7cdc69ba5b25139e7728ce778a68a7fa9817f852ec8e04a159122cff62992ec6 +b4fd4a4c1be8bc7e4e2bfd45404c35d65b75f45fb19ce55c213a8035b41f1ccbce9766f3df687c0d7cd6cdfc1abb00a5 +814bf565ece6e9e2a094ffbd101f0b9fea7f315a2f4917abe2bf7d070ed8c64a2987bd288385a42fd336ed0a70a9d132 +af860af861dc80894ed69f29c8601d986917ec4add3d3f7c933a5e9d540bc8ff8e4e79d0bb01bbc08fa19ef062f2890c +b66d33fcf3cd28f15111960ffc6ed032c3b33d4bb53d035ab460cc5fa7ce78872f0476d0bb13f1d38f2672347d2d6c4d +89603ae1a5dd7c526936b86a3b69b7b1d0bdf79ba3cc9cc2e542ec801a6126d1514c075d6ad119fe6b6e95544ffe7fbe +8a1b097f46a62d85cff354d1e38df19a9619875aad055cc6313fdb17e2866d8f837a369a9ee56d4f57995e2b0a94310e +8dc165d86c7f80b0fcd4b6f90d96cd11dc62e61d4aae27594e661d5b08ef6c91156c749de8948adfaf3265b1d13e21cf +98e3173772c3b083b728040b8e0ee01dc717b74c48b79669dd9d2f7da207af64ccd7e9244bc21438a5d4ac79b88e9822 +924d168099b6952d6fe615355851f2b474f6edfcd6a4bd3ad2972e6e45c31bf0a7fb6f7fca5879a0de3ea99830cfb5bc +95452f0b7efda93c9e7a99348e13f356bad4350f60fcd246a8f2aa5f595a9505d05ec9f88b1fe01b90ecd781027b9856 +b95e8af516bb0941fc0767ecd651ada2bc64cc3e5c67a1f70048c634260c0f2c0e55ed22948e1870c54590b36683a977 +82f7feb71e746d5ca24455e3f3e57e4eade92669ab043e877b836612efd3de82009f0555e5d8811bff9f2b75fc57a01d +87623c02caf590ea84cf4a84d1be501f89262e26eb463f2f94a2d3042889c051b058823c3367a989498e46ff25edab16 +b88da847b1ef74c66f923773ce8c920ca89751335fde17b3a98c0603862069a2afbf35b1552b43ad64dccea69f040ff8 +96b734758c823e5ce5b44625c252957e16fa09f87f869baac195956052dc92f933f377b288c7f63b8028751cbbdca609 +a23cc5fbbe5cb7c1d33d433cec4e502f6548412e2374e285d307f75e98280b0c0af4f46bba18015be88cdf7db8b1239c +8bd5bbe04bc929ca8f546e673803ec79602f66ec24298d3e3b6bf6f2c25180fc0032ea6f86c38a6e0ec20ff4eaafc7a1 +b95768ca113e5d57ad887a1cb5ef84ce89007ce34c3156cd80b9aa891f3ebaa52b74c0cb42919cfbcf0cb8bafa8085f9 +a117f99045f65e88acc5a14fc944f8363f466e4a64057eb8fc64569da5dd022a01f2860c8e21b16aff98aebdf89461b7 +895cda6503907c98c43477eaf71dfd26759032523691659f13662ca3a967d93bbc5be342d168223cef7e8a333987d6a0 +a084d77d913d3ec0586ad5df2647610c7ed1f592e06a4993a5914f41994a29c4a8492d9dce2e14d8130c872d20722920 +84a328b73c64137bb97a0a289b56b12060fa186ce178f46fe96648402f1b6a97d1c6c7b75321e4b546046c726add5a08 +b7c35087b2c95127ce1470d97bceb8d873a7ad11a8034cc1cba7b60d56f7e882fc06796048435a9586eab25880787804 +ab05e3394375ee617c39c25c0ec76e8a7f2381954650c94fbcd11063ea6772c1823c693d2d9dd18bd540a130d7b92855 +82ba5907051d84b37fd9d28f8b9abebc41fc4aaa334570516ca2e848846644016356d40fa9314543017d4f710d193901 +9170517b6e23ee2b87ff7c930cb02b3e6bd8e2ae446107b5b19e269bf88f08de5ded3d81a2ff71b632ca8b8f933253a0 +93dc0e3f6234b756cdbb3fe473b9214e970972e6bf70803f4e2bf25b195b60075177a1a16382f1dee612a4758aa076ee +b4b49fac49cdfccda33db991994a8e26ab97366545166cc7140aef3d965529f96a5dac14d038191af4fb9beb020ff6d5 +b826537670acdf7a8a45ef4a422d5ae5a1b5416ad0b938307518d103cc7ba78e495ea200adc5941414a70158a366e8a2 +8ae3588b1fbecbc769c761f0390d888e34773cf521d976ee335f6c813bf06dad38850871ac8a8e16528684f1e093d0c1 +ad9c00b8dccdb545315fbf26849135699c6aa3735f89581244281154c906aba80d20c1e7f18f41acc61e0565f8015a33 +954ce68146c05fc1c9e536add3d4f702335d93c1650b8c1fad893722a81f915eee2d38275dad00ce87f3f5bc90ef7341 +8243feaeff9a12f5aeb782e3dd68609ce04ecde897c90fd8a19c9c5dace3cf43bd5bc0f1624bf7fd2607ca0d71adbba8 +a8a1be55259cd27898d9d60a61998d8da2bf2d439ba6eedb61d6d16dacc4a81ec706b9196dfa080ba20701d2cd9fa1f4 +b0eac6212c7a62ef6062c30875fbe24b8e1a9d88854c035686f849a9eed4d17fbc9af27429eb7c3fd60b47a5e29f6783 +878561a88412e95f19f1cb8894be9d0ea4a2cdd44f343387f87dd37445e5777bceb643cebc68c910acb5e588c509cd2e +a57b6c347955d8b0057a87494223148ff9ff12b88e79dbd9d0aae352fe55e15ea57fcfb9add3d5d269ee0001d8660f20 +a07fa66340d4082585e4d72c77510c59b272e7a3345f4b1de6be7ff4a11ea95d712d035a7355fc8d2e571fa65fe8236f +b9d84a627462438e8ede6c453e3367bfaf81cff199d3e5157ef2bc582d358b28b5ccc3bc27bb73af98ef45179ea79caf +b14f26ea7ca558761cb19508e5940fbf5dcf2ad8555c5a03e8ff92481994072f523b1ab6b7176f698e2cfd83d4f8caad +800cca1cbb14e1fc230c7b420ff06864a934b082321bbf5b71f37340383923f23183d4fdc8fa2913928722b8892db28e +94790c950b92e971ec39e9396c3f32dee32a8275d78e6ea28a47130651bddc86a189ef404c5e8c210bd291186dee0df4 +ad7b3b3e377df64023b8726d43a7b6ec81e5a5e8c0943c5bebe5ab5ddd6597255f434a205c14ba90e9e5e3c462a1fe0c +86ff8156cc857a416e735009cf656b89da59b766b4c4e5a0c0165282b530c10657cc28cf5cb847696725c37ac48b69d7 +89cb64cf9294f68f01533660a2af2aec0ec34cc0b4a0cc36a128f2e0efb3da244981f69aede962f50590faeeb9a5da01 +a2ea5a94a524bb8e6f767017246cd1af9d87c9abb9894e91c4e90c34c5161be6179b49dafcab9cff877a522c76beb145 +b5d9abf29ed6030a1e0f9dc19be416c45ba8cb5ed21aff5492233e114035715d77405d574cd62f2716285e49f79b9c99 +ac441cf6104473420babdfb74c76459cbea901f56938723de7ad3c2d3fadb0c47f19c8d9cb15a3ff374e01480b78a813 +abea34bd2d36c5c15f6f1cdd906eb887f0dd89726279925dbe20546609178afd7c37676c1db9687bc7c7ea794516af03 +8140abfd0ec5ca60ef21ad1f9aabbb41c4198bac0198cb4d220e8d26864eedb77af438349a89ca4c3ff0f732709d41a9 +a5a25abf69f3acd7745facb275d85df23e0f1f4104e7a3d2d533c0b98af80477a26ac3cf5a73117db8954d08f9c67222 +b45ac8d221a7e726ad2233ba66f46e83ed7d84dbe68182a00a0cf10020b6d4872f3707d90a6da85f6440c093914c4efa +80f586dfd0ceaa8844441c3337195ba5392c1c655403a1d6375f441e89d86ce678b207be5698c120166999576611b157 +b8ce52089e687d77408d69f2d1e4f160a640778466489d93b0ec4281db68564b544ec1228b5ab03e518a12a365915e49 +8990f80bae5f61542cc07cb625d988800954aa6d3b2af1997415f35bd12d3602071503b9483c27db4197f0f1f84a97ac +8329858a37285249d37225b44b68e4e70efeef45f889d2d62de4e60bd89dde32e98e40e2422f7908e244f5bd4ffc9fe2 +8d70c66ea780c68735283ed8832dc10b99d3daeb18329c8a44a99611a3f49542e215bf4066ff4232d36ad72f1a17ccc3 +a3b2676cc8cdf4cc9e38c6cb8482c088e5e422163357da3b7586a3768030f851ad2a138eeb31584845be9ffb8067fc00 +95b1fa74e9f429c26d84a8e3c500c943c585ad8df3ce3aea1f6ab3d6c5d0ed8bb8fa5c2e50dd395fa8d4d40e30f26947 +b1185f2ac7ada67b63a06d2aa42c4970ca8ef4233d4f87c8ffa14a712a211b1ffde0752916bfafdfa739be30e39af15d +8705a8f86db7c4ecd3fd8cc42dd8c9844eab06b27d66809dc1e893ece07186c57b615eab957a623a7cf3283ddc880107 +af6356b372f0280658744c355051f38ff086f5563491fc1b3b1c22cfec41d5c42b47762baeb9ee6c2d9be59efd21d2b7 +86bdd4527b6fe79872740d399bc2ebf6c92c423f629cdfcd5ece58e8ed86e797378a2485ead87cbb5e2f91ba7b3fbda1 +a900f0be1785b7f1fda90b8aedd17172d389c55907f01c2dfb9da07c4dc4743cb385e94f1b0fc907dd0fedb6c52e0979 +a9f59f79829a9e3d9a591e4408eaec68782c30bc148d16eb6ae2efccb0e5478830bbdaa4ae6eac1f1088e7de2a60f542 +99cf54a69ad5e8c8ec2c67880900e0202bcc90c9815531d66de8866c0a06489ea750745cc3e3aa1c4d5cb55dcd1e88f7 +8676246a4710d6d73066f23078e09b3fa19411af067258e0b8790456525c02081727b585d6f428c8be285da4aa775a4b +b596c7014fe9214529c8e6b7602f501f796b545b8c70dbf3d47acc88e2f5afd65dccef2ef01010df31f03653566b16df +a12205c6c1780fc8aebdd98611e12180005b57750d40210b9eff0396d06023bd4ff7e45f36777123ff8bed7c5f52e7a3 +ae7dbd435bba81685d5eab9abc806e620253da83e56b4170952852d442648a5d8743f494a4b0fc9d606574f87895b0d6 +9786257b1726b7cdc85219ca9eec415f98f5a11e78027c67c7b38f36f29fe7a56443570fdfedc1d9293a50e4c89d89f6 +aaf0515070d1ca92aacdf5fac84193d98473d8eb2592381f391b8599bcd7503dbf23055324399d84f75b4278a601c8b2 +b31654dbf62fbbe24db4055f750f43b47f199a2f03c4d5b7155645276b2e456a218ca133743fb29d6f1a711977323f6e +8f4d39106ecdca55c1122346bdaaac7f3589d0cf0897a6b4b69e14b4d60550fd017876399401ce7c5d35f27da95f50be +8a7bfdb48cd47afe94aff705fac65f260b3a3359223cff159b4135565c04b544dd889f6c9a6686f417e6081ad01e0685 +967ba91111e5e08f9befcbaad031c4fb193776320989f8ede4018254be0e94586254432d3dbae1455014f3a2f2549d01 +a9db52352feeb76715a35c8bed49fb3a8774c9c8e58838febf800285fd6c4938ec162eb8457029e6984d8397dc79ea19 +811794e6bfe2539e8f6d5397c6058876e9e30763ad20dad942bb5dbcab2f16d51718ce52bfb4de17889ba91da1b85bcd +a6db0f65a6dc8b8cc2312a3e0146d8daf520255bb12f74874c05693914e64e92be0cd53d479c72cb2591e7725dfaf8b0 +918d21bfa06d166e9eb5b7875c600663a0f19cc88c8e14412319d7aa982e3365f2dff79c09c915fc45013f6b3a21200d +9894852b7d5d7f8d335dd5f0f3d455b98f1525ad896fdd54c020eeaf52824cc0277ecbfa242001070dc83368e219b76d +ad00acc47080c31fcc17566b29b9f1f19ccaae9e85a312a8dcc0340965c4db17e6c8bd085b327eaf867f72966bf61452 +965e74649e35696744ecc8bed1589700bae9ca83978966f602cf4d9518074a9aa7c29bc81d36e868a0161293f5a96e95 +961e29a239c2e0e0999b834e430b8edfe481eb024cc54ffaffd14edaf4b8522e6350dc32039465badfff90dcb2ba31cc +943dda8fa8237418a07e311efde8353c56dd8ec0bfa04889ccdd7faa3dee527e316fdc60d433a3b75a3e36ca2aa9d441 +a0ed4c102e3f1d6ebf52e85a2bc863c1af2f55dc48eb94e40066f96964e4d37fff86db2cff55a8d43d517e47d49b5bd7 +9045770ad4e81345bc6d9a10853ee131232bf5634ef4931b0e4ba56161585b4286876bc8a49b7b1f458d768718cb8ebf +b0dd430295ff28f81895fde7e96809630d1360009bbe555e3ac10962de217d93ead55a99fd4f84d8cadd1e8d86d7b7ef +95ced48419b870ea4d478a2c8db699b94292f03303f1bf4560b5b1e49ca9b47e7008514fe0a9cf785717f3824567e1b2 +a7986e0e389e8aef6aac4a7a95e2440a9af877ae2bc5ad4c5f29d198ec66aa0db1d58c451e76ae70275a2e44c3d3fa68 +85a8490faf32d15de12d6794c47cc48e02428af1e32205e0742f8299ea96b64bcd6d3b4655272afa595eec74ecbb047c +b790d7fb1307aacc2d303d9b6753a9773252b66c6b67763cf8841c690cbccc4866ffb5fec1c068b97601a7953fe0f7e8 +afcc4011f8c53f10d63c29b74d9779cd75c861e01974c28a4ec2cbb909b67a1b2287ead175231343c936ad75dfa416ff +918058bffdecc1ae8779dccf1d874bb9e28edbe34c8b5954a8da64a848858d2f0776437b423baf4e731f3f5fa05a2841 +ab554db549aa36dfa9f966a5ed6be8267e3aa9ced348695f3dafc96333c6dbb48ef031693aafd59d1b746ecd11a89c51 +ac4ecf746b46b26a7af49cc9cc1d381e1e49b538dbd7fb773ce6b1df63ae31c916693cca8a90fb89f1e7ec5e0e8dd467 +a8de66d48f16b016f780a25ba25bd6338fd8895a1909aabcfb6e70f04ff66f9866e6e2a339bcbfa4bfba4070a6a8db26 +b4b49374eff6dac622e49b0e9c0e334ecbec513a96297f6369696ad39e5ec0de81a1417f6544be866c9f60957a9ba09a +b8023968549ebab6c1e7a8e82954a5b213bec50bbf35b36697a8d4fd75f9e12d510b365962aace4c9978c5b04da974a7 +8d4bc016026dd19e4059d1c5784897cefa47f7ae2ed6dfa2b3c14a852fff2b64abc09549d106584e0daed861a2d6d6c2 +85e26f433d0b657a53da4c1353485e0c2efa092484c5b8adb3f63dc72ee00be79197ebef7937b37a6a006571641cd6af +abb37a917301e68328032ff4715abc0fee32e5f5be68232ca8bf7ffb8732bc47504e75b40bcc0a7c7720b71496fa80af +9837c8d2660522c0357f5222777559d40321a1377f89ca1717215195bad4a348a14764bd87fa75f08e1f6263e9d08982 +97e06f971b4c56408ed5f1de621d233e6a91c797f96ec912737be29352760a58831aaf1f64e377c3ed9f2f4dc8ad1adb +a12d211304da7b91101513d57a557b2504069b4383db8ecb88aa91e9e66e46e8139dadc1270620c0982103bc89666215 +aab74ba48991c728ba65213e8c769e6824c594a31a9b73804e53d0fda9429403ff3d9f6ea5ef60884585d46356c87390 +92f19be2b7adf031f73611282ad33e462852f778c5e072f689dd0e9458fa6ebccfae02f2b2dc021802c9225035862468 +953bb843c48d722604576cef297123755cef8daa648c30c3a678eada8718dfdb16e71cc3e042a51fedc80577235c2563 +86f509e3c1b9ee9a3b95e6da8516b47feb8c8a83403984228f4903c7ee1ee4f03addcb8fe86283af1196a54b36b9470c +903d793a377e98e2562c49de33e3fbf84bf99211925e7002a4f688470db655884e1efe92782bf970ffa55d9c418ef3b5 +a41b65681ed7f10987a7bfdf9e56b010d53683819d845d880fc21b2d525540605c5823e75c434f17b5a0d08a091c1564 +971be802de51cfc0d10a96be7977c037873f19334ed4ed4904b7675aec8bfa1f8956cd0150b07064caf18229ffd1ccd9 +b253ebe4f82cdbefbc3ef816d40c497fe426a9f0f0f170e783fa4a05ae6dabdfa8c448817a24e723a314b43e76a7c422 +86f397c95025489929ce9230b1466b5c330ec7c58a3c7e3153d6d05bcb8348a13398908e192590b8812f5c5ff09c133a +a0713983a3dc9f10b3833687cd2575de2fc63c4ad8d2f54ff85c6db23dd308daefef1bd1e51eec26732f77c1f37ba793 +8249a1d53ec92f311f4fa77e777800d777f3e9d4d452df740fc767fa7b0f36c8dce603d6e6e25f464c0399b8d0b93c30 +a73d0a206a62922f07b928501940d415e5a95716ee23bf6625b01ff2cd303f777adfa373d70279ba8a30fbb4c99a6f1f +b1106b407ecf234e73b95ff58ac9fdf6709ad2e763b58f0aacc5d41790226d441b5d41405ac03a0641f577848a4f5e8e +b009963ccc7b2d42792f09ab7cb0e929503dd1438f33b953104b4de43274ca3ce051554d10d7b37041b6f47d7a2dab6f +b744512a1b3c7ef9180b095c6a0c5bc16086a50020cf20dc2216bbff24d91ca99b95cb73070444dafc3ab45c3598960d +a0209669ffeddc074d35cc6aa2dac53acac8e870f8a8a5118e734482245b70c3175f760652e792118fdddac028642259 +8ddd3e0d313da17292fdcc1bbc6e9d81189bb1d768411c6fe99801975eddb48dbf76699dcf785cac20ab2d48e392c8fd +8392aa285b8b734aa7a6e0f5a1850b631ddf6315922e39314916e627e7078065d705ff63adbc85e281d214ec7567863e +b655a1fff4dba544a068bf944e9de35eaaa6c9a0672d193c23926776c82bebed8aa6c07c074b352882136b17abdab04b +af5095f40d1e345b3d37bebee3eb48c5d7b0547f12c030d5bfe8c0285943e0a7a53a186f33f791decba6a416cba0c5c9 +8223527f9eb3c8ff52708613cd2ee47e64c0da039cea3a0189b211dc25e9bfa3d5367a137f024abe94f98722e5c14b67 +afdb106d279273edc1ee43b4eead697f73cb0d291388f7e3fc70f0dd06513e20cc88b32056567dcc9d05364cb9ca8c58 +9319eac79ff22a2d538dcd451d69bca8aa8e639979b0d1b60d494809dbd184a60e92ad03b889037a1ac29a5547423070 +b79191ce22dbd356044e1777b6373b2d9d55d02b2cc23167642bc26d5f29fd9e2fb67dce5bd5cf81a602c3243bedd55c +988e0da1e96188ffd7c5460ecdf2321f07bc539d61c74a3292c34cb8c56dbafbca23eb4471a61e8e64e9a771a49fd967 +b0792b6cf4b10f8af89d3401c91c9833736616bb9fe1367b5f561c09d8911fb5a43b7a4fd808927b33ab06e82dd37a28 +862f68ea55206023ca470dbd08b69f0f785fcbabb575a1306ff3453c98ffcad5fd6ead42e8a1f9edf14c6fd165ffd63a +815ff0898b1330ac70610180c0f909561877888ff10def749a1e65edf9f4f7cea710a757c85241dfb13d0031efb5e54b +aa6e6ce21776ea4507d452ccdaf43a161a63687aae1cb009d340c9200e5646e9c2de4104dfd66b8e55dfa6de6ee83e4a +8e8f3d3403e0256ecc254b9b1464edca199cad3f3348002d744721c345a1a3c7f257c3587d2229774cd395e26693d1ba +90483e28985e4a0f7a3cb4bc5e865b9d408b94cd2146c04aed00b48a7ab80a28deb05efec320817d63578d4f953bd137 +84fb2a762ba29193b07f1dd84b3f69153cedb679b66ad04f8a4adf01c14f115163a107e6db23aaf0f0c9687824ded197 +b4a23922bf4302cc9a6583f252a1afa026c87c132b9ae44cc1f75a972cb6ae473447c500827906f9b677617ddd6fb473 +809bb9edbbe3a2769165f029f2a48b6e10e833eb55d8f9107c4a09ca71f0986dc28f3bf4ead9cab498086eb54c626bbf +a0459dbb08db4155d16301933ec03df77c4f835db2aa3f9697eeb2bb6fcd03337fab45fa43372a469fecc9a8be2e3119 +a638eaace7f21854de49f4db6e4ea83d2983751645e0fb200c5e56561f599fd37dac70bdbd36566fdd10d4114fbb9c2f +a3a27bc2728390643a524521bf8ef3b6437cfba6febfd8bb54f2b6ecbafafb96196d3dea279ce782efd97b212f364ef5 +b86693b3ea23ea6b2c4d52554f61ef39c0ef57e514ff6da80c6e54395df8376e2e96b9d50e4ec301c59e022c5c5610db +af4d7cd678d79e67ae19789d43331dff99346cd18efff7bab68f6170c111598d32837372e3afe3e881fd1e984648483e +b8735a555ba7fe294e7adc471145276b6525de31cda8c75aae39182915129025fb572ed10c51392e93c114f3a71bd0be +b1dfb6dbda4e0faaa90fe0154f4ddaf68ee7da19b03daad1356a8550fca78a7354a58e00adeecb364e2fd475f8242c24 +9044b73c1bd19cd8bb46d778214d047f5dd89b99b42466431b661279220af5c50c0cffecebd2b64c3d0847a9c7a8b1ec +891f0d162651a0aa0d68fb1cc39fa8d77fd9f41ff98b5d6c056c969c4bac05ba8c52cbfa7fbb6ef9adfe44543a6ec416 +8920ae1d5ac05bf4be6aba843e9fc1bc5b109817381cdd9aa13df53cabea319a34ee122dcb32086d880b20900ff28239 +abb14023142876cbc9301336dced18c7878daa830070b5515ff4ac87b7bf358aa7ff129ebbf6fb78e827570a4142661f +a74b15e178cf91cde56eab0332e62d5ff84c05fcc849b86f45f94d7978bf9c0fc72a04f24d092a9d795ca3d976467f46 +806829621a908ca9b6433f04557a305814a95d91c13152dca221e4c56bfaa3473d8bb1bacd66e5095a53070f85954278 +b09a3c185e93869aa266a0593456a5d70587712bca81983dbc9eebbb0bd4b9108a38ae1643020ecf60c39c55bb3ac062 +b2bbe8f5361a3ecdb19598dd02e85a4c4c87e009f66fee980b4819a75d61f0a5c5e0bdc882830606cb89554ef1f90ead +825e16cb54fc2e378187aedae84a037e32903467ac022deb302cf4142da3eda3ead5b9f3e188d44f004824a3b5d94fbe +8b39d4a11d9b8ba885d36bcdb6446b41da12cfd66cb22705be05ab86936464716954360cc403f8a0fd3db6d8b301cb59 +ac19d453106c9121b856c4b327ddb3e3112b3af04793df13f02d760842b93d1b1fbdff5734edc38e53103a6e429a1d1f +b1cacbb965ec563f9e07d669ffc5e84d4149f1fb9fcfbc505788c073578c8f67956fb8f603e0b9a9d65e2d41803038ce +b7612d9e7dc930bff29191d1503feb2d6451b368b69fa8ecb06353c959967daccdc262a963f01c7fb95496f1bd50d92e +93f8fceb65ea9ef2052fa8113fb6720c94f0fed3432d89014ee5ad16260aeb428aadea0d1f1e002d2f670612ba565da3 +b3eb9213752156ed1fced3bca151fd0c630554215c808b9a0938b55fed42b6b89f9b76bc698f3e37c3c348d2395dbed1 +b46ab3553ef172ae40fc21c51d1d7eab8599a67f2f89a32a971aa52c2f031664e268b976dd2f7dc2195458fcf4bf3860 +8fb66f2c67ca5b6fb371c7d04592385a15df0c343857ba8037fe2aa9f2a5d4abc1058323ff9652653261b1c7db0edc24 +a7dfdbbf0b14e4af70fdb017875cdc36ad2108f90deb30bfca49301c92cbf821645a00ade1d1ee59a1a55a346675c904 +856199cad25ec80ee0327869077f272e33d59bf2af66c972e4a5839ec3b2a689e16f7fd0a03a3138bec458fcff8edbea +a2842ac5a715c2f48394988c6f84a6644c567673806feaa575838e906138c1b25d699e1b6ffdfc9be850b15da34077e4 +814b448ada88f769de33054c3c19f988226317797acacdbe55ed2485b52cd259ac5bcbee13f9de057eee33930a7fa0c0 +b49de8dd90da916ed374ca42665464b6abe89ff4453168921f5a7e5ddd3dcfa69422782e389e586e531fd78a1f236a8b +851f9d942b4c8ffc020c02c7fbee0f65ef42b1ab210ab4668a3db6aa0f8ab9eedb16f6fd739a542cc7e3cc03172b565b +a5128c155b8062d7fa0117412f43a6fdc2de98fa5628e1f5fc1175de0fa49fc52d015ec0aff228f060628268359e299c +b0765849127cc4ce1a1668011556367d22ce46027aa3056f741c7869287abcaccf0da726a5781a03964a9ded1febf67d +984562c64f3338ffe82f840c6a98a3dc958113f7ed28ee085af6890bbc0cd025723543a126df86f379e9c4771bb69c17 +8087fe60a9a22a4333f6fbe7d070b372c428d8c5df3804bb874b6035e5602c0693757fb30a9cd5a86684b5bca6737106 +a15e195b5850f7d45674cdc3bd74f972768b46fe9473182498263edc401745a8716fc532df8fc8c1375e39e391019226 +858ec10208c14a67c4156ea9c147f36d36c4fa0a232195b647e976ba82c8e16262b2b68d31e3b4702070c3dc701bccb5 +84bf3fb83c003380ee1158e2d6b1dca75cd14c7b2a32aec89d901f0d79e1475aa0827cb07cba1784a6bb0d37f6ca5cd4 +91e69f5392648e7f7c698059a0fc4b8478ab8af166d3842fb382ec5c396daa082ee3b2cb0192da3c9d90f6523c4c039d +8f7299f451c5e641d6fd961946b7a6ba4755685b2a40164e6276c25aefc66715b92492097a191813d39bb4405dc5da36 +ade2cf04ff6c94c1019bfa1e0e8f580696230fa6ee9695c4772e5a44501b2fffdd765ec7cc71ba14b83559ad62cc0fc5 +85fc98ecf469d6f98c8b3e441680816f764de39001a249bc7162f990c5a5354683e849164d4fc9287ee516780cdcd436 +928d118188120d038c37abdbe66c05adaa87f1cf9957dee2783b09fa91c4c43a7b0d0b2b6c5f4dea57e3ec8af230e84f +8025f71cf8d3085d6ea5104dddea8fa66cdb8527e40db01472469be021632daf22721f4acf1a8698a53439fe2f82596c +83266fffb12b3c795a6b551ac2aa7d9a29c183f861e78768c11286a04e22bd423bba05a68775bd77273e3ca316a4318e +95fd0c69c2d9df4e795c7ba71ed71a9d9f2878cd7e3a64be7b671d9611649fd41d29f8bdab642ba19cbd3db660d6a7e7 +92a912cb4d5ef4b639876daf4289500c4ebdbd80aff07fd93dc3eea645f084f910e5c02c10492a37f16acaa7e646d073 +b3d2622c987189a0873932aaea8b92ebb6e9e67ff46e91a96bf733c3b84175fffe950f8f4622cc4fa50f116321c5537f +a98f9a40054b31023a8f7549a44cae853b379bbfe673c815b8726e43ecd11a96db40b20369d712cbf72ffab064ecfac5 +b4e9a38e371fc21f4b8a3d7ad173c9ffad0554530dc053365d9555ddb60f5c9063c72ff4c65d78b091af631a9e1ee430 +875a31aee4ba19e09f8c2754fab0b5530ec283c7861a4858b239a12432f09ef155a35fedb0bc33eac2117c7e62f1c7ee +95edd0d1a6e94af718590756b5c5f5492f1c3441ecc7fa22f4e37f4ec256b9fffd2fda4c11fc1a7c220daee096eb1ff8 +b35fdc435adc73e15c5aaf4e2eea795f9e590d3e3ee4066cafa9c489ee5917466c2a4c897a186b2d27b848c8a65fa8a8 +94a5ce56f8d72ec4d0f480cb8f03e52b22f7d43f949a4b50d4a688a928ffd2c9074ecbab37733c0c30759204a54f9a6a +987562d78ef42228c56074193f80de1b5a9ed625dd7c4c7df3bf5096e7d7b08e2ee864bd12d2ea563e24fa20ad4d30ef +95a8218405038c991ace2f45980dbb1efa9e4ad0d8153486b0213a89e4d7e3cac6d607100660784627c74f90a8e55482 +b6a29d566f5a924355b7f7912f55140e1b5f99f983c614b8a92814ce261f2750e8db178866651ea3b461fb8f92890b14 +afdacc0a13da0446a92455f57a42b3ba27ba707f24171727aa974d05143fae219de9e2eb7c857235dd9c7568f43be5a8 +862a7dc25f7cfa4a09aeca0ed2c9c5ee66189e119e226720b19344e231981504e37bca179aa7cad238ee3ab1386aa722 +a336364e76635f188e544613a47a85978073f1686e4ee7a8987f54da91c4193540ac448b91d07d1fc5c7a8538b1f1688 +8f1ddca9638decd8247c1ce49c1e6cf494d03d91c4f33e48a84452d12b6736e8bd18c157068dfeff3a90977af19e5b1e +96ae91b9aaf00e437c18ddfc1aef2113ee278153ba090aedeb3f48f1e66feb8897bb1ac7f5ffeffc3be29376dd51e498 +8230b5bd9067efb6089e50213f1cc84da892e6faf0b79d5e4768c29303a80b1b754cb09d17a21933aba4c5f32070878a +a79dfe217faec7b4d3cf97d8363949efbc6f3d2c6bbc25df2c7bb8b7fd2521e6d3fa76672bfc06de6f426290d0b3cc45 +8290bd36552609d6b3ac9ccb57ff8668fc8290548eecdcee9a231f1125298c20bd8e60f033214dfbd42cd3c8642c699b +8945db9e8ec437c5145add028d25936ee8823ceb300a959402d262232ae0cbd9a64c1f0a1be6aed15ff152202ea9a70c +949e232b48adeaf57bd38eacb035267d3e78333c6b4524cab86651a428a730baf9c27ff42cb172526d925de863132e82 +98917e7a5073a9c93a526399bb74af71c76958a74619caccf47949f8fd25962810a19e399b4efcba0c550c371bea3676 +b5b144e0707aefc853ea5570bd78dedc4e690cf29edc9413080f28335ac78022139bfe7f7d6986eb1f76872bb91e82ad +949945072a08de6fd5838e9d2c3dc3200d048b5d21183020240fa13e71a1a8d30e6bfee4e6895e91d87b92f1444d0589 +b351a03c7c98506ee92d7fb9476065839baa8ed8ac1dc250f5a095c0d4c8abcfab62690d29d001f0862672da29721f16 +a82d81c136bc5e418d1fba614cb40a11f39dc526e66a8b1d7609f42fea4c02b63196315014400084f31f62c24b177cbd +87d51c907fdcdf528d01291b28adfee1e5b6221c6da68fd92ab66126247cd8086a6bcffff0ea17e7b57b0ba8d01bb95d +a2a9a1a91dfd918f36c1bfeeca705ea8e926ee012f8c18d633e50ec6e50f68f3380ef2ee839e5a43cf80fbb75bfb5304 +86f22616caed13c9e9cd5568175b6b0a6a463f9a15c301b8766feca593efa6e5ee4c7066e1cd61b407c0be12b3d8236a +b57e0a2c42790d2fd0207ef6476a433fca0cf213d70840c4af1ad45833f23fca082d21a484f78af447a19a0b068ea55c +8ae9bda5d85e6e3600dde26379b7270abd088678098506b72196ac8f9ce5b0173bc9c7ff245c95cbab5b5b967bcb043b +95c7d11f6c874f59ba632b63ce07a7a9d917a74d0b89cefa043f52aa1a7fe2e81c38dea0b20378264b5b4f64039932bc +ac7dee7479f50722526ea1c9d4e2f1a4578d1b5cce2092a07722069c96bb4da295de1c4f16e21005276e3b3f1624ac5a +89b8aaa49bd18b09f78fc5a1f3dd85d69b5dfcff28fc6d5a92b1520bc54107b8b71bb71fd6e0bde10e0a5809c633e5d2 +8982cb43fe4d3488c55e8c08b935e6c8d31bb57e4f2aeb76d6319470cce99ebf7dc2f116ac15b9d845ab1bc16aa6a583 +a12c63f48e27b1a1c83a32992642f37fb5b89851a35e80f6d1f9bc483cb25acd0e12b1dcf68781ae0cc861f002368bcb +aa6da92a4b4fa229afc8007abca257ce0ff5fad3b1ccfe5d836b9b52ff6b72575a0b915a759403b993733b16a47fdb15 +8bf706a92fe54f15d633b9463926b874dd43e28aaeca3fe2353fb58ad7753c8a293c56b0e94176070e8a9ec7401073a1 +b81e86de4bb5c1046e40cca79585c5b98c8673626fd3a28e563c5a3296256c2f7086522ae95cbabfaa8f1a8f7eae6272 +ad10f895b05d35cb251f78cc042d3f0969a8b6b3f289ddb4b016e0b8e06bfffc3a3e1afa9b0cc548f8c092832bb766bc +ad993aceb68d5217cfb07f862956cde83d05dec5060fc7a8fbfd37c6bfd5429ba69bdaf478b6cd01c323a06793dcd9fa +83da9c9a8fcb2775df0777aceabe90642a2df1c6abc646566e954f42d6e43455b00b101ec5ef58850c8d4b3100222ca1 +b55484f339fe7c7d107e70432601f4a34e1cc02ae4de5d18b99e5aa995f7b3710fc745769b85c1af803d457491dd8ce3 +8009d80593e82f3e751cec9e7e495fd29ad6f45f8d3ae513bec998b43c49fed74c44229c6f27c421e80c65413b897644 +9868081bbcc71192f7ff8dcf99a91dcd40f96556fbd6f285bdbfdfc785f604d8bf75c368c59db5ac8cdcc663087db53a +a04b1e91af025b4387ee0a2d790a1afb842e46f4c3717e355578efd1f84fea78782c6f7944b4961268de7f1ac71fb92b +a7b6301ddb9738b89b28a36d29d5323264a78d93d369f57ddab4cea399c36018a1fcc2cc1bfadf956a775124ae2925bd +a6cdb469014b33c590a07a728ce48f15f17c027eb92055e1858a1f9805c8deb58491a471aaa765de86a6bda62a18aef4 +828a23280ec67384a8846376378896037bd0cb5a6927ff9422fca266ee10a6fde5b95d963a4acfa92efbb0309cdb17b4 +b498ec16bcdb50091647ae02d199d70c783d7c91348a1354661b1c42bc1266e5a5309b542ef5fdf5281d426819a671cb +806533fb603e78b63598ff390375eebe5b68380640f5e020e89a5430037db2e519ab8ae5d0d0ad3fa041921c098448e1 +9104ad119681c54cdee19f0db92ebfe1da2fa6bef4177f5a383df84512d1b0af5cbe7baf6a93ad4b89138cd51c7c5838 +ac695cde30d021d9f4f295109890c4013f7e213d2150c9d5c85a36d4abfdca4cdc88faee9891e927a82fc204b988dcd9 +a311c244df546d5dc76eccb91fe4c47055fc9d222d310b974d4c067923a29e7a7f6d5a88bfef72fd6d317471f80d5c82 +89e4518335240479ad041a0915fc4f1afaab660bd4033c5d09c6707f0cc963eb2e6872cabc4a02169893943be7f847d4 +a8ad395b784c83aacf133de50d6b23bd63b4f245bb9e180c11f568faca4c897f8dbda73335ef0f80a8cb548a0c3c48fc 93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8 -ab54d7c9a3ec7da862f55ac9ffb4c959c60481ef5142df42c1aae63a40fe999ef89c020ce9b97ead5ea155a31ad9dc951253ff1703be99ed05fa6fca6b22850a5bc2ee8d6b5bd7ffc1242c2199309112d240d18039e8036509565c19dc099d11 -8a653e72f96f4553bdfecb4d7ee0802e8bf086edbf06d07a64ec4902d961f9c4655f3ad9472e48a1ec66fb30aabf1fe00ff5f8abe82276df35cbb14ddb6047a28f792fea1ad009b9dff0e5e34e6fbc8d054a9f62432d0d98d4f0974ef6298d64 -89ab5abfa1424db4981ec60bb0d96005dda380506c4ac4358e8c464a4e50c1cee2e8aaf5f2d4b0b5e43dc907fcaff3ed006ab5292b6014c816a06af573d94cfce800dbe306ca3b0342bb570afb0575ae013f55ab5a0c018dfe222793c582bb50 -b11fbb2ea855632e0c164ad83c5a9a230b15dbdb74ccd5fedda7d5e162243ca182435abe98b3b99952672e802ee3a7e001c7909571a6782988055b1ce529aae79c7c5706141ec42bb455ff6224343e272e1457c207372c632b7fbd5123d353f9 -a0ac685c627e5b7ab90cfe24a9987d5a59b354e49fec06af0ec5b287710aa4549d49fbe04e5359e755ff5e6745d190a200326ff548f948866e317970ab13bc01a5a38059a9d49df21300036a69cbeeaead3992b5384496776216aa49e703adbf -b2876c27e287955196e8bbf5866d7799297c5facc41866992fead253d1dde7a91c937272b1cc56735f26ae78df2cac00006bd67347ce3d3a48d459106e566a7b04acea0bb5932fc80906e51c5ff92c16c18a0b55febe7e06ef80df9a4904953b -81fe59b70ff34adf0bab40e1ff6f8d6c6b3066307b3b11bed978b3bb687116c60fdd9ae4ab423771139cecf7b428232500cceace9dcee8c35ca1718af838a6c6318747513a26553b8e1bc356d965f7303c74e20ede959121aca4dda825239244 -b2c50fbb6695225b8f492a24b7ecb0bbc6761f824a61332ddd4fb113a43647527dfdb0bfd9055f6be1d3b7c2e858828116b1cdb8c4c9d0874e417f4b5c524e83ebe131980e7ca3f0d6f4c2720e9dc5f187adf0653a458355724a7d9288ee090c -8383c9a4d40c69e34780d5a3996a7d28c320ff829aab31508dca6e1aa71bea9bc6cb155e15f054249c719d9851d6270d10c868dbc3907f58e099d4544e19486e995bc107c9604df3451af0dd2e949967a0fdbbe361f43eb60ea088600994a8ca -b83a55c54e92080190c4dfe70a67c38b391191f0351f557bd329ee4a8096b10ea5f5becaeba7e86f9411ebac0c226e7f12b97baca8fd905f3e0e941c2a4fee39c490a361b30e6b7ecdc0b09fea3a5799d9f6c6ed753e02ad2baaa98af5375a58 -841e674d1c79edb849aaff2cbe0585c9dc2953e322aa9bdd6f8db7c625a4b6042574ea619ba945f4cf31d5f2b31d21cb0d1119c43ff9e587d296ca22e1cff8c5ea872421caf7eee2b2b2475abd79f9ef84d9adf822fc3379ae001d58e5046b8b -8f5498b0198365787c19d7b1789b6145dd0e05330ddda91bf9bb9d70a7c2b46d5444492e315e1cfb0de7bebc8661bd190167de053fb75c62bedc28c624915b10afc0cf699cc4f2c0ed2a8a90a0f41d4f1140d7acd46d3ff49e3f9357792e6322 -861a9dab0bfdc3ef2d589f8bd5b1a4b478a81a6455872744f885e6e8f436f73a3d7dcc65922369468c5a3310f65d98f312426571ef1ef266ad52d83d3b89ca7ab31dc942e4bdfd4440d9e847fdd04c19bfd8410a9a531568cba45e8d2aa3d246 -ac46a8c7349e2c051f6f0ec3fc396eb2fc419bc15ba9985e7a8464ae38e0311ed8af9a0c68c4578645a9f0d8038056e609a048a0580ed1c3ab5c4d3e7e5ce145dc26599a2d80bde5e2770cd928545747179d23b1f514ecc59a66f59ecb9f66ee -99c914aefffae6b7749a242356c88e00dd29593b243059faf2060ba338241d890c57e1cfadc52a03069be8b7f18abf4b19efb4cf7c41dd8c52b845e6de265f06c92db560680d6a2acdce60bce9be5b9a8e1f2625ceabb3701a14fd30c6ef4d05 -b5dcf9b83c24fd1fb2be97f703dac64659ae7ff80f7e4c21ea36c1aee3df257ef51d0d1dcdd956c98b3cb11fabdec4e809952a27dfbcebe2393f3c2762e160d78a151b26cb4ba0d49617802f9baef51d8c6eaf5a6b2da20c1f5c208b494f3de1 -a8a37f4dd5f16199de8454685158549e09cbd9e81a561955995429d04dcab25fa71d41973ed181e815e64266da2520cf19be6a5aba3508917ffc48fd4446daff2ea68d723ae3eb6f46e6a59c17abc1d3aaf40613cc4c043de018280d48ce0efd -84077ec9f2de368d0f711aaf0620f00713769e412e55c7988acc061b2ea51b233a53cbda551b09e6306d1c4615b866c91420b16e77b8f2f8d911fda6dde4c6e099601f6212efd3b90042cc3226a91097981ccd51302c1fba72efea1cfaed9de1 -88b74d8ecafec474022e41f48a66c5ad71422cb2706680c01c970fcdeaea8a6e4418f1545c7353cceaa78b168ae4a2b70a30a2c51549574ac53126c588f5f1e72053f5811b1fad709607254fa4f87b6f7d6e89938a6761e27d37c9b803770f54 -a65d3c4adfd929d531bf86ac0ba7ff140cc1181f693f5ca440b4438a641b332fd369a2df230dd7e2e6b1df5f54017b011605815a7325ce3d45935f96d3012661eef5839c2e0c31d2f8d0551ebdde6e36b712acf97d41be5d28339f70adb57707 -9476a90c417eafb01659638a98d235ef2433ac97470ee78879a0eaf93941751b3e0dbd9f6500bfbe40adf015223a89100b6b533c28e98c9aa4addfd27c520cbb6b16b231acacadaeedefdad5c8734b57edb9540c2b1e514054f15a6b3a6d5f2c -ac290f34fa6b516e3899628448ab9e60a74d38bf3a9ca36f2f186c119aaacab914fd5efeb41c4af372037d324938db4d0d5a66dd636b097108dafdce046a37b79e6b0acb09c9775bce5e859e4c4246bf3d8c753ed6058242391767baec91f0d4 -affd61eb4bc24483d6daa055cb0cb6ad7e4785f4a13a3fd919ecb0605382b35ff96055e2b991156fafcb8fd85807f7660d84f02913fa0f2a5961c9dea3452fe532349357ddd79d24d23396c41447163079fe69a8a065f7b5d3230edc713c7600 -994d275b27dd228cbbb0326a1ac03e3d6ab4dc8f6cfb70afe97f722d6a256a84e5dc86e3677dccc5b8e7aa54ff5f03f20b2aba4c31cfa86d8484b61f24d2baf9e5a4a0bd74c88baef9c6b707fe18da94191f3fa7fc008758a0ffb46a9480619e -818850921ae0a3cd4e07e3c3c7231c4ab325188df7f679215a41c983ecd85e538699ad5226063f38263433838b5efe800c37029a59cbd1d379de7d61b3b36dc76a599e541d0f489fec3be704902dcbb5c03184a62a20e28b46143c97868c083e -9628d869c63f03f1844cae49caa5e4740ee72a3177375679ea5c5cad4a96d64dbdfc9f82321d41fda33069cbff1e27fb0c97ee422b558d975df023c19f6a599d7a958ec416536249a16f92c4a7241c2d14eb94b2bc717f6ac11fc866f47a35f2 -af8e9cf99bd6ebea38dfb0aaf56cf2bdff5251f770962cb44cc336aa0a8b5d757df79aafc51becb51190120d4bc673b40a27a9ae1c99726f5d597800b197802e65a63e1f6a2f28b457b891e708fca0aec375f9089fabb82f3c92a66439a8083b -b777f84357ef01797b362fc5db838ddbff82010095e91daa6949561786f661b2fd829bf0b4e656f29fc6196042cca0b50212da28d1ecb84b72311f03dab329d701aaefcb926e38be40e3504973c07f96242ad89b2aa716ba508f27eb30e92674 -b01b9e63a0793ea1789da96201ad17381a158576abf399c6926c54b585c1a9a7771598d395036dde3ef1d6f3e512b0d5172c34cc4624a19e6466f3e8befd162c24c794590d6548c591a535c674d80e29c25048e8784d998bb21ad99ad3bf10f4 -a8a899c7d601b46204b8eb5391d638fdbc7af8d26e57e77cdf879e990edddeac969b6c016c7abcd7ee218cde65284cc61461cbd54fed218f3efac5e060f260c1bb0421a1da7129d41c2bcad5e96ed0d6a5e9c40cbf21530abb25dae61dc3b128 -b55fa53216c831161ea290e030cbb7dd7838f480bd0737643f765195d77ec592979556ca59d0dafdcb559ff03ff7b1b90fd6368c5c205e3d7f5e2ad27b5383a19a62067190494d1c6b3d5d660ce9a8a86456f3de33c2908951503af10f7831be -91892b185022682a326310fa2e2e03a15ec46adb1892f1d8cb6a62abfaedd24ab33fa8e69ecc4f7e516f24bfd1c061580d9bb96cf6605512652d56070594ba35479c8d6e47d92343b9719898ff620067f38d5dd53e60c136a7231e81fa37348f -909abb17a009e1060cdef285a571451205a67d370430fe19fab5d495670a8824098693c054e70b6f595668629d58a1140d06dfaea317aa7c51618651aaba82157d542ab590109abc8ac36f44c720c11e05dd9faa64b96819b09ff8c761de4453 -8c91c0c8b1db4005ed3702110ffd75230b00bad6c969b95af6282378e4fe2520302b13bb9acfea47573498ae10a395ff0de9cb7714a29c48762482239492cbad0d6a2dbc33a4dc2267d620f346619260d4ea07967dd62ee565bb871e3755eb3d -977f426c94b291a9b398448974494487303d7157cc414bfb35ca8c37a8e5a18cd717254f4aae29f74695a813cea40f0301b52ef41257acdbba37bb9c021b0ec187b7a3784bc12ed376311fb2fd1a105748c9d143a408888c9d6426758591dfec -866ffb2ce1ed33593f9aec6d0e7195e0f4513372230e4ea7a851d028d99d00d4a2412877e3735b7d47027ae900ccbbfa0ee918bfb52ef8ae0f964ba891820b559bcd46ca9844efe1f4045f4d3ccf611cb8545a375484ada1a30c606cd64cbddc -863446f32a18aca3874c7a15289030870bba05fcb839fce789cda3da3377ba7ecb1a977c84faf2667b4144f322268e5c0eb7de69911ec46ec8bc017f19ec14c7666046bd2bb338ec531062e46d53794146cf9f5c613bb144f1b1f8442a7cce43 -870a2e8743b845f056230fc62b8f5149335242b71578bdf66bc14fa6d7527fd5bf85d0ef516e6f2246dd601413b67357138b794aeffe9ceccbccdd3900dc9fbdbb35dd3adc4a0221493e594ce575816aed8af0fb53d8df3502ad51bf5c9da124 -84eecd70ce4bafd7d6e0b7ea685267812ec23f6e2178f5fc569487e4969e36c03856ccb56674e65d49d4b3150cc4ec7d0e936a0bf8a9ae558f838ce0b5b5989ddbe26ebb9c0224a2f820bcdc76124a45071146cb5e89ab8656ffa27eb25c8fbd -ac6b775771419cd38e7cd37e9f594a89a66e7cfeaf5b9cf21c6b44b41a765ed54ad2888c6fbd77a23285037efc883fde05ef82ed9fc49afbbf4f35e8401c7df4ef88f6a9a1417a29ef534e365b58da5bc6c98d486f2bfd839424f0a709d7e8d8 -9954ecf7e25e1b8e67d8771449e7c00bc2ca4e48e604b92fe291e3ef8fe5608412de8acf7fd500f62115d9e10a0271bf0b02caeaad3f1ee939ee8a03af9f37ca50915189b54715a934ef01df0e96b91d0452a0b27254f46f94660c1ebc287be3 -831abdd3d7a5bfcbf39f38fac455e5e113297e17bc4dc8c49bdd938dfc332bfdae6af6c06cc8228224940ea4d0316549152214e732fe2032b16d0517acc90f9e9e0f496645a49b3864eebe19b1e4b55c5a5d86533697f00cd9ddfde38ea2af70 -82f11302ec5c2842184939b9d43868e03cc90120e6bd5554f2c051cbff458d0046e74652ee001deb081b8aea0c37c48707081ad9f82453973fb358ada46d2dd5c6b7ebb9e5799d23dbae4ac90fde75701f921ebf244b73b0f04db659454af562 -a11414895fa706e76387b79f47e814bacd9e437b7aca346b101d66d962021a4f96b67a30b4436e305bb3317eb82d0c080e657be2c0bf247e534c6e31f85f1d9bafe4455a2ae22a0192e53a1e9582e66b460180cd0cb90300b4cabd2c36bc4d21 -b55043990ddf27bd285e9221319a1d918060a315e92d8304afe887e9af0879e17da53871865882d96ea2b8daf20bea2215e9a2b2b94dafcad3612c9fbadeb7c9f6a4e2adb4b8e3ecf024737ada651b784a76831c2c7b6971143c4f9f352c97dc -89873bcf8754282b6547a7a0e1787531d0fa2779c5062e7de81afbe132df403d70fc2ea87be4712c7a58514250fc62d418f38264a2b29a0d10d27483a9574387557914b7a178a982c22160d0c4c1c29aeadfe3250fb682745e4f19f76adfaadc -a00fb88c700529f3bded83be19527c82f6df1a40bfce42faa1bdfc2a5729e9d2766daa8f6a65885d0c0f3cfebe3166a619a8aaaa135907dd85694e26eee0e7062b7e9ec3b9db463703028c8ff9515f9b6e190b1fa8f04aab30c6471158e56ebc -ae77f46684ff49e2436fe636ab74c5a244376fd6e34f6c207de277438cf075bffd1d37c47b5beadf997418145e4038e20eef9391a390b5bacae18fa203ce287f6622eca30b86c8637dc76db81a77e3796b58fc88e3b61accc8f7989a086ec543 -837c575f3a129520019420647875d082900b506afcb89e4894dddd49a3ebcdb114eaacc432f33119ace647291ae759a81273bd920e4031e9760e8ed4b744aab9b44dd6cf5f251e75f5404d0cfca3e15d8ae457aee8afdee56e794491259bb454 -a010bc4d0787706e474286e18d786e4d779a3434db592b7e6398b3de129af9f16251f4b929eae78509e3c0cd06caf82813fda1cc561cef36c1ca5ffe5521f29647e80b2ac0bb5ac953cbd83096627ad4c6d19c15249a7583ffa681a5b8203af9 -8ba5e82ae9c88152a4e6ca6b54e18f693c94ef2ef732470e1ed4547488a0a752ff1bb2f6da9c9d25b875f962070bfe0d020285e031327544ad9523f9beb3463ad4d22a470cc86e91b6d5f83251f7b39e020726776eec14de815f8a428081e89f -a5ccf8af69bd593dabf9e729bec46b8d4333236ef2fec9b3a5e5be580c34faa056e83de2f0613712122a9f4f531692d0052255c3822aae87c04d238311b51c6727f8a20d56e7e221aa7bbf4430fbab74058d390e2cf50f426ab5db18f18818a2 -a36885e433a3c6a7db407194cc6307b3568a1d000e4f6cebc6731abaf8652322f6f8a9d9e589421e436afce02257e9b0195610a1fb5e0a067401cfa3e64fc0f558dc58d15b5ae676d3d4761e11c34757493f1d78fd5c58f0ed56b841479761da -8e719fc50682758ac95fb5547457ded3df801de84f6f9883d567120d0097ae8e2eb634a70cf93b072b93aa436f2d50dd09b905a9415f6effbeaa0515195ad3b4b5bdfe6397e68094c2918c44dad248953b66eb6846d8b0aac41664326239e9d3 -877241b94fba746c0c9ea95c294604e5c6dfeab9e0ad7f31fc4bbb9e2610ffdaba310e5ea82404ce3b3e5618b2b336cc194eb0620c969dad9f9a681aefdaa4370bc1051c71719e551d1f1c51f4b1735bf5c706cff6612fc3c918ddb0061a208d -8d9a0776b02b26b7e41bec72b65f6f693e4f0c8fdd6252a9457e3a0ac315844759c3ecb46f1793c6397932f801c8b4d5147c77408b4edfeb5b19912733a15fe82b7c17138a5f2f0f17933eef986b12bc6ca35d90e5f7c0395234c62f131daf2f -839f21c9feb77867e256ee4165059276b6288f02c5fb580a22d2e3815c375d39bad16d76683d03b70900a416a66963d608fea8d566c8035cb965449c8d8014a38ab7c17d057ba802643a08bd4bfbbb675ec3df330dd6c8df1cf454a917e530ae -87cbc4749fc46227127f484de3f0cd72ba401ed8550249dfc0e3abca082485a39eabf7e58be310b26a5bf52d8ff98b32001239f2d38ba6202393251f7a6c71ed8668e017e25e78639b7d1f4aa1c99026ac98da899286135642649016f54ab494 -b23b59cc019cc068b0db66b2b90a3a0df4c0d65896220d6c1a4866635b7813ca0e01c8a4211a79296c0d74ed4287a8a815118db3f924820a1ead25fedb7384a71480d594106c81887f57bb5cc86bd9789b2eda2a2765a923bd3e6832df4812e1 -a509cceb4138c0e2b57e00caf96ccbe3942e410e6fdf1c0ebcbdf7b14d26ead2713128457cee482bb0de9c29668a2fcc16e4183b7c7131c2aed2378d30b45db311ff4ebed23aa2983fe6be54b6bba0b9ffe7add59f28f1925ac5cc67aa3a495b -a43e95552243a3915f698505c0b8e2469d6f28f431772279f7731923a323b4a96ab644e75b2cb9fd7534c6e441237f921194a230d81d7e1409810eff348edec6a614cfd8cd48ecfd956eca82669ebde2fa48fc9090d0643f71250fd7caacad4a -8fea8707e0f15584a51a93094a5a517f5d46dfb5243c24b977b89bac5fb75791b38703bdbb62820058c5743be12bd6cf0b0d578ff7877ed1aed0f723dda1e75510988dc41be225d07ee8b0698d0641a91008488516fc3194a36985e342632551 -9804a5bf830c8d66d2bb07c3ced70560aa5738b3b8af5427ed5aa119f7110dbf224106a03a42ebae2b5db06c2f5e5d99008451c52a29711e7ea1133723a860df497b2750208b4a430ea2e62c42db91247cf2640eb92ed834e6a63e8829cd068f -945e3136e24d0c72ea9a13de7027e038c53d384d40e3b191eee05d06b0df16acb7264acfb4802fce61116e442510493b00d0c2a31f72bcf3b2f4642f9bb6789935adfb9c05dffe2e0bbc77c4dc008d768a49fa0b74e480370ef63e0225c025e1 \ No newline at end of file +99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d +88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659 +a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3 +af565445d2ad54c83a75c40e8895f5ad7219a8c728bce9d58d7a83716e095432993ebbd3f6911c66415a6f920d1a4d171478509b54a114308a020b33bf4487a7a8d0aa76ae4676a9b54e765a680f562d3a4fcb2e92c58b14b49b5b2917cc258f +8aa99cfaf514cef4801599cadd780d222194ca1ad69a34779c2bcfda93e5dbeb931e13914421b5809a6c81f12cf7038b04a35257cc9e94c33761e68565b1274aa6a6f9d66477229747a66b308b138f92aa4326a3bf23df65a1fe33b3b289bfe1 +99ba36d8b4f56bde026099278548b1afc0a987cbd7c9baa51fc8e6cbb8237a17636f1a44a385cec69b05a5802059956a11fe793cabb939c38800f9c239ca2518e898ade1ec2513c9ee492071a35aabd78182392a09123d28dbc233313c9120c4 +a7dc40c36afccb30a2eaff250860b28b227c195cf05674704c567d77d6655c446ae835f8fc8667e71147ab02afcb2dad0babe60cbfa37d7c2cddc68d2dec54f28a4142f8353590a3902d5ddaa22066ab563dd1435dda83f276387b9767d69120 +939e6cc97a8b88572852a5b7f25e4838556307f60aeafb5d2b6961edbcafd4b48cb6ac980ffbacf4be963f324ba81e3d12de4f1459d8c746d0762c66ae1b166027f7fbe641d9c48f3c7d97b06d956b0be51dcc9aab65f3e99e1388e63bdd79f9 +b391e156541dfd4003d1697cdb7ec815b309807320574906b2e652ef0175828b356d215cd374b1b34d9f470b3fa0e643113e67b2273268f922f04f072cfb89008358185b25cd631f82911a3f20f90f75758ffb99bebb8076458ae1e9d1ae898c +b9ac9c84934cc2a85c876eff65577e1dfce1935cd6392c877dd881a7d2f5c3e9344f28c04f90c62a6db4237ca00f9e0d00cb5f63e3f060fc7303916e19273b6fe455f331cabbe2fe5a22d584484f0d4176120fec9819fbb0a01e6d38695acfcd +88209eb030c5d78734bf2c2a5c539653fd3c24b4c08e624f9ddc4a6550efbdc1054a56eb0c807595aad6de56fda326aa196d032a8b4b48d40140a2d77df3c7243eda6507936389a321a5811eb38e32ee433c788deeae1eb928b00940e2944bcc +a8632ddc9cf7cbc1e8b74a05b7d4a89618c64afe30367ca0c9550ae7d320bf4e51c5a69e1501a1d8bee4240d13d7835501aa39fdc401a74f4d5734e268a7ce29a1fcfdb0a8bc64e0dd4a9e8578d6985bc2bc6a3764ce7a3703f6fb2e52557a2b +a037ac67e8bb6f4193ac967e05d080a489f58ef8d3d30a89798246f3e4936121ee445b03e410a09e8ebc0db2e2477d110aad0ade99b0887f1eb016e750f42135866907f150bd6f4f99a8cb94281474166874808ebe03b118c5daab16dafdc38b +a50d9143116bffa3b237da8e1805327e81e9cd25e658289bd727d5f9e0020172cc8690dcfe31a240e5cbc48353b88c4908baa1dd7320165556e0aa633f62fcbe7870222d345a3bbcdb7ab6c07f0fd86be559964afabf56f0a8cbc0b4b91d477e +afa988ea6fa4f40c5ad07d2d580d29025ddf56d6ef1171a8b8de3464203f70b97d6f5ace72747345204b35150e06154d1477516a989ce8eea7871cc0d0de00a077c0fb23ad4837e409d0b885bf3f2dde11a30fa6273d662e68e09f461e52932f +97fa1a943ed8b81574304a3d03f4f15907f6e6e0cd36a66bd2ad2c75afafc70a61d3ff69b77ebe4dae9ca0fcedef80081062705e60bbb6ea0f1f398c84d2f8e4a3ac142ac66426c21ad5e9994ebbcc406af474c4aec5e32fadcb21875af7c9f1 +b30a564614493886f14a5dd71c89457504f8c59a7ac01b665ed167e9a8f9ee5832198fd319ecd234196ee57031bdf3840bd5a923e203a1938bc795c704b5285389750e1fd10d7050061ba19db00a60a2c0384a7d661d7d48ebe6962272230859 +84c8dea942cfae71cb02e705ec496d967425793ce8812e7ee53c2f23713abeaff566a658cd1c73dfd18187d16253a6ee0a623e82cd18e31cd1a1875d19c078835dc9292e141686150a88065226ada264740143e87c03a0f6c4da8c187438ebf4 +8c3abae8aed60338f8c4ff80aab22f8a2ae56756a93566c906f490a97151d34a1c3318054e1c494c60cc53327ad86a2d02c6c76a406726ce4f88635bc32eff0db0b61762dc518b95fa8da82e87e4bf3de54f1d72180ef53ed7bc5413e6a9a510 +a328230c92a6b1cef6a444bcb64edb992f71e3d7b93f0b6b8b408ba7c908db746d92ddb2c7588bab438ef3bc61be1c2f0dfc86ba2ff514b42b35c80f89b2e780f813ea1dfb977fbded2cd9b553b747fa952e227ebd8f071163d421fc337f04c9 +b482cab423cd5f1c5df036070aade7aa016283d69619d664025c3feab866a0a5691d344b2ee2bedc5dedd1f9a73eae16003a3827c9e5bbe22ded32d848fba840ffad1141ad158f5c40bc8ae0d03781b9705d851a7f1391b096c576c0f4f2a6b0 +919ee1df27fabcb21237a1b7b98f53d41d849e1b6a8f9e28c3fae2841c6b5a250e4041c737e6725476e5cd715e34d3880f58d80f61efaabc261bdc703e8750f48a923e9bf8980931b9fd9e40014c66c54b3e7c98241d76d1aa47af43313a65a1 +ac94830145dbe9a8f7e6e0fc1f5fb454502d22abcafdc2dd96c6933c604461fa83b2b37385f4bc454875a02a6d4157841250956783515d11c7456e7f11b745f12856d89f5feedaf6a61a483a6c33a21cd2ba0c18eb41a1a2e7fc33bb53e4c570 +b209c699f1233735c5bb4bce848e4365fd76651ae2184d2279a90df0c2f69ffa2a24d84a9b9f274021072953c0d65e1a0202d490d6c37186af240114e445d87bff754b4824937e4f2c90a574061b1c4910fed88d90f698025a2a264e656cb8a4 +93320dc0576b0d069de63c40e5582b4486d9adf5e69e77e3ebaf3da26976fe42147a65051501bc8383f99e7ba75479c70a6726c2cd08bf98c7481f1f819712292d833a879f21a1221a9610bc748fb5e911055122fdb4055cdc84e8bfe0f4df9b +a4380b240e998cdf668591f71a0c88ed143b0185a920787627ce65095f8223dc606fa5bce93377af100de92d663e675c0736d7f1973603a84a5c4162fb5e01c88c7493503ae1d7e9fbe8ece9b418397d68c21eeb88dae226e09875d372c646dd +aab48517d69135a16b36b685adfe9b2544a709135a21ba3e75981a2cba4ec81d1fe28ac0f72fde0c0001c15300ed6a810f58d3117bdd58d0149751d6508cf8a1a1ff7b63dd02d2730a9d6fe96c77c502fe8ed46d50a181ec4bb35e37dfbd6af4 +8277265fe75ab89ce4ec65b33fb4084bec0a56d81faf2f7a9070d2ca3065678e03a790350eba56323a54e0285bc32fe8007d5259740fde226e16cbde8354eacd562294eb9b7f727ed72ffbdad86f467cf057c737b34b80a41deb92634ed866f5 +aa40a24cb2ebe606d969392c03020070f044c95088d80f57f771b837c048342d2cd3474600d7660441090ffb8d2ffb7f0eddd67eb378e3e1477a6ba0bc38096d5d2d3355bc8b60f605f57f0c1899da591457440352381d2b38c0aa9acc7fe419 +80815d10685808cb630820629bcd2fa9041c9b74433630c0b9c1b7f7e8edf1440b520217f76ec9a50c125cf4438aa66006a1928a9ed2321da7ea325c3d56b65462b72118ca2c99a0ea733aa11da9abbeda6cc71ffeed301ae70213a29e697dcd +ac235d079f91b00b1fead7523da8f73a5409fa8970907af0c5d5e4c6a0996dccfcdb0d822d08c7fbc0c24799457d011d04312d20831825f23cf988141056a6814c8a1cac9efe37bdcbfa272aed24cd92810fea7c49b0d07683a5c53643872179 +b8aa59534d75fa5ac1c2c3f963bf73899aff5210059dbde8a8635561c6249e5143affee3bd2fd57575213b52d9a73d5702525867a7dcbb1d0a49b98c2925556fc5463ff0209742046a24ab29e74257d6419401093cc4371944d811cc300b6a67 +80bbfc5b816eea29a6d84e2217dee4d547306994d39e5592515e1b0807b67fe960d1d5addb0ff1a20c158bdb294c04bf093d28996121845a2c9268e2c9ac0f4067e889c6aaca62f8535d35b45036954bd069e3afa84f04721538c26003304c20 +a535c17d0e151d0e03d42dd58ba8c715bee3fabca2890e0e016071d34184b6b34e770d2be29c8ec76b69bcc471d50f4d043c2c240e9b93a81cff7ee2724e02018dfd9b534e40be641fdb4884abcd83b76f517557ffba508f1ba2f56313f4de94 +b237eb7465df0d325a3aa58269be2627e4978f9863f4f100ed4c303cb1f6549e606f2e3c9180824d8049191965c8dacd0a0c76cc56cb22cf1bcfdb39372c8aa29b4f7b34582b1719e6bd59c930d87d5ccd838743b585d6e229d5ed42337315c0 +805c335a2a9d2de30809cf30808ef836d88e9453c510716f01696f14c72dd60505eca8f128970edc8e63a9aa1f8792ac0dd50dcc84fbf4cc8b32349c682a6a27bc7551c7aa273a94c1606d07710188d93579afe3be1781bded15a34ed6047922 +b25dadf385ddd3c39bcb0a014d3d4f66127946b1aceae8809e3a03d66cc25e27142ca108316391f857fe82fdea4db2520cc73793b695eafbf3ade00ef7ec747b0457e49303f5e1a370f5263b436566fe24a0876e5fe088238c7be37a0718d65f +b0f753081cabe2c8fce73aba82ff67dbc9842598b3e7fa3ce2a1f534536f8ac63c532fe66552ac6b7adb28c73ed4c8a4184849be7c1756a4681ce29ebf5e1c3aa806b667ee6bd68f6397aba3215dc1caec6742f21d681e32cd1160d6a3b1d7ee +b798771eeb3d7a17c62ba5916cc034bba870da6b1ac14c2e1cae71af3ad4e0c0d1ff983f691e0e55289d5a33b131f2ec12430c9566dd71f4d8be9c79155357a5c30c5efcfd75bbe1bb6d5ada4d50604ea49ed838d3641f268ca6e25c9c4b6b72 +b52554c017388b099804abbe565346591a086d9979e10140ddaccc0a3680e506db775d7cbeafde67563adf0f09f5c2420caf19629f4e8f03e6fe02e9416ecd5269989e482b90004a083967d1141387eb74865bac6bd17e7a6d5f58225e52d4b7 +b520ff694520919023d44d53f98a7de2f78ff37b2d9193dcaa35556a6a0febf767781a4c961dce7c804bfdf81935f8f0082865253da52e79dfa1c5ff74d61495b2da76e167d46114709e877a7791a3a95e33a42f56b83f5f5afe271c67ae997c +b721401983440797a03d5b99f2088a0b249aa911969c34dd6c615b0060325da555d2ad99d931170c0868b0488a2234a4114cc0013d5163b833f5c45c5eb536421c016cf85788390176bb2dc4c196d6be26bbbfceae048b82f0d8039222e71c94 +acd9d833ba0a8cbd8d1ba939a11ea0fa5607e1bc6e693ec318bdb097aedd042d76e695dcebebd142e2e4ac30b1905dff03ec36d9cc70577e4dbe5e9ed7c20c7afb13a7f0155f203c6b83b9f1ad3d20a0d4aef0fbbbcf466ffc1bcd482bc2f5e0 +8cc1795de015f2b0e72116f169f3b4624b7738ceebea354e0bd9051c27b86f647ea36cad57ea6884c1a8adf9b45cd83514fa687e68878bbd613d793aa10986d5a0411f081689229e0d72133b3667b9f3f1a02211d0e680564eb1ea43393e1f36 +aa9281c61113c343a108de1036570feefc72fb7a96ff11f73024de12b83f29631f5a8a5900e6f10b15227c6f7462881511271bf785ebdf95ce288100e5dab391f664f6ff76c72b65b34479a4f43e5e8eba292209d6654157286ad3242ac342db +aaf16866275082e59d415db317aa874267d048ee405a553e852e6d175711d31a1fee99912345915bce121f43bc3e00d81338e5fcd3c8a1012fb4f172a9fe15622dd368b4d9d5cb60d189f423b071791fe26cea7676aca8df07965cacf80b0cd0 +accc80b3d8a6ffa648487a3d3c0ce1aeeb5401edf3cf2e385ea4a6d5fc110054fcce38f01f1da7141bbed30eb7a0a6810c82212bbb9da75d6033082dbcf6bc6a5791f85aa0f045a10da5de015edbf369b4d23b32b0c058962d2ee88e6911f994 +83f1089395a16077738cc7c9a6d6a3dc9033aac4abc508af5a1f007ca92e1a80b2e6f2dbda7fdcf0d5646de790a6201d0a9cfbcb6620a1426600e3a6a425ec004384f49fb9dcd166691a47177d45dcbcb761a11d46220b0aa09fc946131f7aa5 +9246bb586d43cb817c2e15ed609156e9f1cd284ba2f4797bbfa51c0341e1ba382eaac059aa9f63fb88d228a1a932839a171e7c7d00199dc7c4d6c5ea038a02cbc3cc5297c70401520e70ebbcffacd6a703f62896f3c788f94dde3c33ab0ecbdb +a316cb7c74feb0563c56cc79015e2774fbeca458bf8e9fb07894f9d6bcd73f7fb9428e87c816e5629e4bf7f3ec567fbc091549471b75492dde08217cb334b716b4582b24384586e53388873a78a90ec01bd7c3bace9cfc52161467df16e27c33 +ade18c74bbe60d1d69f4a570f8e5fd8696c26cc9e02829040b6b14cb9c49a4b3263b5bd5e16ec0b29010b4be054c16ab09304e23442af7d7f5fcc60bc6c5634ab6e4aed7ef334b2785e4c7672d59a687278e42d310342db5e5975d716e6d1595 +b7728800bb2039acf228fa3d8028569c426cb85d28b2b5820bbef938d5ca8c4df981d3e01a309e26ca101e8295d0f6990c03b8c239798323575874a4ee5bfe46cfe99b9657189142aacd8f8d1f26cf4c0e73c6397c31ba8f18102b9ea315b638 +8fb14f2a9be193f54977ecd3021663108ea143627b9a9d9faff85d1a86b855f6c437eab435fad3304f245bd7732af07f1173494cdb802fb96e85d2db89e1643206e183f3b228ca8d3f586e71aa9308eaf0223100bf07942fc39e465016d1f775 +ac1e025e53d98fdb3380489dce82d9d4bd3a6c98f0a523b841cb09a6f26ddd4d22efd98776e78d10fd996995fd00e81e08d3c25dd14a54b25a9d483677a24bbb8d1cb41a443b2c71038e6893b1b30f70758424e0f2039a48060191389033ef55 +a4c017311b9e930868132527a9849072b91db04fd36c619ae39c98da9e2174e6201d3c2ff1246c06b1b6815bbf3ea4a1116564f55ee2fe4c4d655e2294c0ded842cba209c255ca3d7b7f82d162f97890dfdeed087aa2f87cbfc61d61815da39d +89516315a3956b455843c2555248bd94dcb19993060fe75fdd51f7aa9c9147ab13997d8a98036a8f04bee5c91d78d2990907e35a52537a8ab3ed15f1a71afdcd38044a5b6e93f662b9d36c16933a881927cacae668c4c06ee6f004c9e3989bad +a1e78a011e210400c68ca76045f7da74119bff3cbe382efd2bd2ac76567c52d68d75536a91999d084043e1ce2d07d02e0b69fb99924101d2543521747536fbc51b0454aa9a4cbbec101121f597863a5c0fee2ca5eab35dff9b9085bef8b2b0d0 +830fd8d083e39153ecab43cabb22e29d7b44a55fba467af4ddd3f069439d2972ef53c3518de788f96b3f4f64963987d0155ba27afc28643af3de8e476ff515a68285728167408f45d99e574680bda6bacdd4322e587e4aa99386e035c0e931ad +b89584da22237e3061d991b1a55a5e55dc637b8b671130d304587729348138ef87885180310efe9f9f6d3580b9d7fdcf0649e8a79d2dec8c25a9f53df0fac5d517db999029cbfdd7c2cbd3e9a5503e5d267d3d8ad752335915c92b850b14bafb +959b8030733799882c5e3735479924b013756e57b893f9792bab4043e2d362d77cf308166d782e3989caa771b8a0c0a01302cb7b5e8ca12e2d6cebd59d4cd173c9dc25f438bac597fab17b4ff44997a489c168e7204b7d7c21d0938f0a2e3b51 +a0a9e5503d9afe0027891dab890c687fd5f5fac5741418490c64d7c15f59533dd603a50163c79402afa61bd02de486761983c94501da17e6bbe78c497f2122210071602f578adc0ebe7a4679f87fe77e09c8c122de69105f13455fea25f08e6f +9811487283ad620cd7c9b303ae2f348d0e6f5ee17b504baaa817ae207adb912a00d3cc36dbf48745eb899e6b6e22f09f0f9ba29d949ecd7350fbbfe87a8c7cdd5d0e687fc807751d07634aaf7c38baf3b24a0670c38fa6ccd7431436fc95525f +8a13aa5071c526e560def7d8583393942f07d88c9d8d26c98738fd65f57af2e3326dbb1edff0f39fe98eda4a13ed4fd71844254b954690154c4804e1c4a53df9dc4643f4b7b09d0860070f6b2318d0d63d28fb56bf5b6ff456a18dfc72fdfbbe +b9c90ff6bff5dd97d90aee27ea1c61c1afe64b054c258b097709561fe00710e9e616773fc4bdedcbf91fbd1a6cf139bf14d20db07297418694c12c6c9b801638eeb537cb3741584a686d69532e3b6c12d8a376837f712032421987f1e770c258 diff --git a/config/src/test/java/org/hyperledger/besu/config/GenesisConfigOptionsTest.java b/config/src/test/java/org/hyperledger/besu/config/GenesisConfigOptionsTest.java index 158d9734a4e..7dcc21a2c7c 100644 --- a/config/src/test/java/org/hyperledger/besu/config/GenesisConfigOptionsTest.java +++ b/config/src/test/java/org/hyperledger/besu/config/GenesisConfigOptionsTest.java @@ -48,13 +48,22 @@ public void shouldNotUseEthHashIfEthHashNotPresent() { public void shouldUseIbft2WhenIbft2InConfig() { final GenesisConfigOptions config = fromConfigOptions(singletonMap("ibft2", emptyMap())); assertThat(config.isIbft2()).isTrue(); + assertThat(config.isPoa()).isTrue(); assertThat(config.getConsensusEngine()).isEqualTo("ibft2"); } + public void shouldUseQbftWhenQbftInConfig() { + final GenesisConfigOptions config = fromConfigOptions(singletonMap("qbft", emptyMap())); + assertThat(config.isQbft()).isTrue(); + assertThat(config.isPoa()).isTrue(); + assertThat(config.getConsensusEngine()).isEqualTo("qbft"); + } + @Test public void shouldUseCliqueWhenCliqueInConfig() { final GenesisConfigOptions config = fromConfigOptions(singletonMap("clique", emptyMap())); assertThat(config.isClique()).isTrue(); + assertThat(config.isPoa()).isTrue(); assertThat(config.getCliqueConfigOptions()).isNotSameAs(CliqueConfigOptions.DEFAULT); assertThat(config.getConsensusEngine()).isEqualTo("clique"); } @@ -63,6 +72,7 @@ public void shouldUseCliqueWhenCliqueInConfig() { public void shouldNotUseCliqueIfCliqueNotPresent() { final GenesisConfigOptions config = fromConfigOptions(emptyMap()); assertThat(config.isClique()).isFalse(); + assertThat(config.isPoa()).isFalse(); assertThat(config.getCliqueConfigOptions()).isSameAs(CliqueConfigOptions.DEFAULT); } @@ -230,6 +240,7 @@ public void shouldSupportEmptyGenesisConfig() { final GenesisConfigOptions config = GenesisConfigFile.fromConfig("{}").getConfigOptions(); assertThat(config.isEthHash()).isFalse(); assertThat(config.isClique()).isFalse(); + assertThat(config.isPoa()).isFalse(); assertThat(config.getHomesteadBlockNumber()).isEmpty(); } @@ -255,23 +266,6 @@ public void shouldNotReturnTerminalTotalDifficultyWhenNotSpecified() { assertThat(new StubGenesisConfigOptions().getTerminalTotalDifficulty()).isNotPresent(); } - @Test - public void isQuorumShouldDefaultToFalse() { - final GenesisConfigOptions config = GenesisConfigFile.fromConfig("{}").getConfigOptions(); - - assertThat(config.isQuorum()).isFalse(); - assertThat(config.getQip714BlockNumber()).isEmpty(); - } - - @Test - public void isQuorumConfigParsedCorrectly() { - final GenesisConfigOptions config = - fromConfigOptions(Map.of("isQuorum", true, "qip714block", 99999L)); - - assertThat(config.isQuorum()).isTrue(); - assertThat(config.getQip714BlockNumber()).hasValue(99999L); - } - @Test public void isZeroBaseFeeShouldDefaultToFalse() { final GenesisConfigOptions config = GenesisConfigFile.fromConfig("{}").getConfigOptions(); diff --git a/config/src/test/resources/valid_config_with_quorum_config.json b/config/src/test/resources/valid_config_with_quorum_config.json deleted file mode 100644 index 2c1db33dfc6..00000000000 --- a/config/src/test/resources/valid_config_with_quorum_config.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "chainId": 4, - "homesteadBlock": 1, - "eip150Block": 2, - "eip158Block": 3, - "byzantiumBlock": 1035301, - "isQuorum": true, - "qip714block": 99999, - "ibft2": { - "blockperiodseconds": 2, - "epochlength": 30000, - "requesttimeoutseconds": 10, - "blockreward": "0x15", - "miningbeneficiary": "0x1234567890123456789012345678901234567890" - }, - "transitions": { - "ibft2": [ - { - "block": 20, - "validators": [ - "0x1234567890123456789012345678901234567890", - "0x9876543210987654321098765432109876543210" - ] - }, - { - "block": 25, - "validators": [ - "0x1234567890123456789012345678901234567890" - ] - } - ] - } -} \ No newline at end of file diff --git a/consensus/clique/build.gradle b/consensus/clique/build.gradle index b6c39a703ae..4c5634f17c2 100644 --- a/consensus/clique/build.gradle +++ b/consensus/clique/build.gradle @@ -47,8 +47,8 @@ dependencies { implementation 'com.google.guava:guava' implementation 'io.vertx:vertx-core' implementation 'com.fasterxml.jackson.core:jackson-databind' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-units' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-units' testImplementation project(path: ':consensus:common', configuration: 'testArtifacts') testImplementation project(path: ':crypto:services', configuration: 'testSupportArtifacts') diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreator.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreator.java index 97bc962e6b7..30bf9b6476d 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreator.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreator.java @@ -33,7 +33,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; import org.hyperledger.besu.ethereum.core.SealableBlockHeader; import org.hyperledger.besu.ethereum.core.Util; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions; @@ -52,7 +52,7 @@ public class CliqueBlockCreator extends AbstractBlockCreator { * @param coinbase the coinbase * @param targetGasLimitSupplier the target gas limit supplier * @param extraDataCalculator the extra data calculator - * @param pendingTransactions the pending transactions + * @param transactionPool the pending transactions * @param protocolContext the protocol context * @param protocolSchedule the protocol schedule * @param nodeKey the node key @@ -65,7 +65,7 @@ public CliqueBlockCreator( final Address coinbase, final Supplier> targetGasLimitSupplier, final ExtraDataCalculator extraDataCalculator, - final PendingTransactions pendingTransactions, + final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, final NodeKey nodeKey, @@ -78,7 +78,7 @@ public CliqueBlockCreator( __ -> Util.publicKeyToAddress(nodeKey.getPublicKey()), targetGasLimitSupplier, extraDataCalculator, - pendingTransactions, + transactionPool, protocolContext, protocolSchedule, minTransactionGasPrice, diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java index d9b7ed0e29b..9f2be2e1e76 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java @@ -28,7 +28,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.Util; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.util.Subscribers; @@ -54,7 +54,7 @@ public class CliqueMinerExecutor extends AbstractMinerExecutor * * @param protocolContext the protocol context * @param protocolSchedule the protocol schedule - * @param pendingTransactions the pending transactions + * @param transactionPool the pending transactions * @param nodeKey the node key * @param miningParams the mining params * @param blockScheduler the block scheduler @@ -63,12 +63,12 @@ public class CliqueMinerExecutor extends AbstractMinerExecutor public CliqueMinerExecutor( final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, - final PendingTransactions pendingTransactions, + final TransactionPool transactionPool, final NodeKey nodeKey, final MiningParameters miningParams, final AbstractBlockScheduler blockScheduler, final EpochManager epochManager) { - super(protocolContext, protocolSchedule, pendingTransactions, miningParams, blockScheduler); + super(protocolContext, protocolSchedule, transactionPool, miningParams, blockScheduler); this.nodeKey = nodeKey; this.localAddress = Util.publicKeyToAddress(nodeKey.getPublicKey()); this.epochManager = epochManager; @@ -85,7 +85,7 @@ public CliqueBlockMiner createMiner( localAddress, // TOOD(tmm): This can be removed (used for voting not coinbase). () -> targetGasLimit.map(AtomicLong::longValue), this::calculateExtraData, - pendingTransactions, + transactionPool, protocolContext, protocolSchedule, nodeKey, diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSigners.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSigners.java index 507fe760c16..9f7b2d9f9d5 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSigners.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSigners.java @@ -19,10 +19,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -63,7 +63,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { addresses -> new JsonRpcSuccessResponse(requestContext.getRequest().getId(), addresses)) .orElse( new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INTERNAL_ERROR)); + requestContext.getRequest().getId(), RpcErrorType.INTERNAL_ERROR)); } private Optional determineBlockHeader(final JsonRpcRequestContext request) { diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersAtHash.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersAtHash.java index 3d02f4213bc..8dd7ac5c23a 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersAtHash.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersAtHash.java @@ -19,10 +19,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -63,7 +63,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { addresses -> new JsonRpcSuccessResponse(requestContext.getRequest().getId(), addresses)) .orElse( new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INTERNAL_ERROR)); + requestContext.getRequest().getId(), RpcErrorType.INTERNAL_ERROR)); } private Optional determineBlockHeader(final JsonRpcRequestContext request) { diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/Propose.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/Propose.java index 2d68dd9c6e1..0e278dee953 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/Propose.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/Propose.java @@ -22,10 +22,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; /** The Propose Json Rpc method. */ public class Propose implements JsonRpcMethod { @@ -53,7 +53,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { final Boolean auth = requestContext.getRequiredParameter(1, Boolean.class); if (address.equals(CliqueBlockInterface.NO_VOTE_SUBJECT)) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_REQUEST); + requestContext.getRequest().getId(), RpcErrorType.INVALID_REQUEST); } if (auth) { diff --git a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreatorTest.java b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreatorTest.java index 76741501dc2..604825bd71c 100644 --- a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreatorTest.java +++ b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreatorTest.java @@ -18,6 +18,7 @@ import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryBlockchain; import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryWorldStateArchive; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -46,8 +47,14 @@ import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.Util; +import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics; import org.hyperledger.besu.ethereum.eth.transactions.sorter.GasPricePendingTransactionsSorter; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; @@ -132,11 +139,7 @@ public void proposerAddressCanBeExtractFromAConstructedBlock() { coinbase, () -> Optional.of(10_000_000L), parent -> extraData, - new GasPricePendingTransactionsSorter( - ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(5).build(), - TestClock.system(ZoneId.systemDefault()), - metricsSystem, - blockchain::getChainHeadHeader), + createTransactionPool(), protocolContext, protocolSchedule, proposerNodeKey, @@ -165,11 +168,7 @@ public void insertsValidVoteIntoConstructedBlock() { coinbase, () -> Optional.of(10_000_000L), parent -> extraData, - new GasPricePendingTransactionsSorter( - ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(5).build(), - TestClock.system(ZoneId.systemDefault()), - metricsSystem, - blockchain::getChainHeadHeader), + createTransactionPool(), protocolContext, protocolSchedule, proposerNodeKey, @@ -203,11 +202,7 @@ public void insertsNoVoteWhenAtEpoch() { coinbase, () -> Optional.of(10_000_000L), parent -> extraData, - new GasPricePendingTransactionsSorter( - ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(5).build(), - TestClock.system(ZoneId.systemDefault()), - metricsSystem, - blockchain::getChainHeadHeader), + createTransactionPool(), protocolContext, protocolSchedule, proposerNodeKey, @@ -220,4 +215,28 @@ public void insertsNoVoteWhenAtEpoch() { assertThat(createdBlock.getHeader().getNonce()).isEqualTo(CliqueBlockInterface.DROP_NONCE); assertThat(createdBlock.getHeader().getCoinbase()).isEqualTo(Address.fromHexString("0")); } + + private TransactionPool createTransactionPool() { + final TransactionPoolConfiguration conf = + ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(5).build(); + final EthContext ethContext = mock(EthContext.class, RETURNS_DEEP_STUBS); + when(ethContext.getEthPeers().subscribeConnect(any())).thenReturn(1L); + final TransactionPool transactionPool = + new TransactionPool( + () -> + new GasPricePendingTransactionsSorter( + conf, + TestClock.system(ZoneId.systemDefault()), + metricsSystem, + blockchain::getChainHeadHeader), + protocolSchedule, + protocolContext, + mock(TransactionBroadcaster.class), + ethContext, + mock(MiningParameters.class), + new TransactionPoolMetrics(metricsSystem), + conf); + transactionPool.setEnabled(); + return transactionPool; + } } diff --git a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java index ab3e45abc59..90b3396211b 100644 --- a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java +++ b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java @@ -16,6 +16,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -38,8 +39,13 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.Util; +import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics; import org.hyperledger.besu.ethereum.eth.transactions.sorter.GasPricePendingTransactionsSorter; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; @@ -65,6 +71,8 @@ public class CliqueMinerExecutorTest { private Address localAddress; private final List
validatorList = Lists.newArrayList(); private ProtocolContext cliqueProtocolContext; + private ProtocolSchedule cliqueProtocolSchedule; + private EthContext cliqueEthContext; private BlockHeaderTestFixture blockHeaderBuilder; private final MetricsSystem metricsSystem = new NoOpMetricsSystem(); private final CliqueBlockInterface blockInterface = new CliqueBlockInterface(); @@ -82,6 +90,10 @@ public void setup() { final CliqueContext cliqueContext = new CliqueContext(validatorProvider, null, blockInterface); cliqueProtocolContext = new ProtocolContext(null, null, cliqueContext, Optional.empty()); + cliqueProtocolSchedule = + CliqueProtocolSchedule.create( + GENESIS_CONFIG_OPTIONS, proposerNodeKey, false, EvmConfiguration.DEFAULT); + cliqueEthContext = mock(EthContext.class, RETURNS_DEEP_STUBS); blockHeaderBuilder = new BlockHeaderTestFixture(); } @@ -92,13 +104,8 @@ public void extraDataCreatedOnEpochBlocksContainsValidators() { final CliqueMinerExecutor executor = new CliqueMinerExecutor( cliqueProtocolContext, - CliqueProtocolSchedule.create( - GENESIS_CONFIG_OPTIONS, proposerNodeKey, false, EvmConfiguration.DEFAULT), - new GasPricePendingTransactionsSorter( - ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build(), - TestClock.system(ZoneId.systemDefault()), - metricsSystem, - CliqueMinerExecutorTest::mockBlockHeader), + cliqueProtocolSchedule, + createTransactionPool(), proposerNodeKey, new MiningParameters.Builder() .coinbase(AddressHelpers.ofValue(1)) @@ -134,13 +141,8 @@ public void extraDataForNonEpochBlocksDoesNotContainValidaors() { final CliqueMinerExecutor executor = new CliqueMinerExecutor( cliqueProtocolContext, - CliqueProtocolSchedule.create( - GENESIS_CONFIG_OPTIONS, proposerNodeKey, false, EvmConfiguration.DEFAULT), - new GasPricePendingTransactionsSorter( - ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build(), - TestClock.system(ZoneId.systemDefault()), - metricsSystem, - CliqueMinerExecutorTest::mockBlockHeader), + cliqueProtocolSchedule, + createTransactionPool(), proposerNodeKey, new MiningParameters.Builder() .coinbase(AddressHelpers.ofValue(1)) @@ -176,13 +178,8 @@ public void shouldUseLatestVanityData() { final CliqueMinerExecutor executor = new CliqueMinerExecutor( cliqueProtocolContext, - CliqueProtocolSchedule.create( - GENESIS_CONFIG_OPTIONS, proposerNodeKey, false, EvmConfiguration.DEFAULT), - new GasPricePendingTransactionsSorter( - ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build(), - TestClock.system(ZoneId.systemDefault()), - metricsSystem, - CliqueMinerExecutorTest::mockBlockHeader), + cliqueProtocolSchedule, + createTransactionPool(), proposerNodeKey, new MiningParameters.Builder() .coinbase(AddressHelpers.ofValue(1)) @@ -206,6 +203,31 @@ public void shouldUseLatestVanityData() { assertThat(cliqueExtraData.getVanityData()).isEqualTo(modifiedVanityData); } + private TransactionPool createTransactionPool() { + final var conf = ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build(); + + when(cliqueEthContext.getEthPeers().subscribeConnect(any())).thenReturn(1L); + + final TransactionPool transactionPool = + new TransactionPool( + () -> + new GasPricePendingTransactionsSorter( + conf, + TestClock.system(ZoneId.systemDefault()), + metricsSystem, + CliqueMinerExecutorTest::mockBlockHeader), + cliqueProtocolSchedule, + cliqueProtocolContext, + mock(TransactionBroadcaster.class), + cliqueEthContext, + mock(MiningParameters.class), + new TransactionPoolMetrics(metricsSystem), + conf); + + transactionPool.setEnabled(); + return transactionPool; + } + private static BlockHeader mockBlockHeader() { final BlockHeader blockHeader = mock(BlockHeader.class); when(blockHeader.getBaseFee()).thenReturn(Optional.empty()); diff --git a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersAtHashTest.java b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersAtHashTest.java index 9629b38c128..ee5dc0f023c 100644 --- a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersAtHashTest.java +++ b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersAtHashTest.java @@ -27,9 +27,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; @@ -130,6 +130,6 @@ public void failsOnInvalidBlockHash() { .thenReturn(Optional.empty()); final JsonRpcErrorResponse response = (JsonRpcErrorResponse) method.response(request); - assertThat(response.getError().name()).isEqualTo(JsonRpcError.INTERNAL_ERROR.name()); + assertThat(response.getErrorType()).isEqualTo(RpcErrorType.INTERNAL_ERROR); } } diff --git a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersTest.java b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersTest.java index cd7decd1075..8cb6fd11039 100644 --- a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersTest.java +++ b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersTest.java @@ -25,9 +25,9 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; @@ -117,6 +117,6 @@ public void failsOnInvalidBlockNumber() { when(blockchainQueries.blockByNumber(4660)).thenReturn(Optional.empty()); final JsonRpcErrorResponse response = (JsonRpcErrorResponse) method.response(request); - assertThat(response.getError().name()).isEqualTo(JsonRpcError.INTERNAL_ERROR.name()); + assertThat(response.getErrorType()).isEqualTo(RpcErrorType.INTERNAL_ERROR); } } diff --git a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/ProposeTest.java b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/ProposeTest.java index c04cb98c2ec..efbc78542c5 100644 --- a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/ProposeTest.java +++ b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/ProposeTest.java @@ -25,11 +25,11 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponseType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.junit.jupiter.api.BeforeEach; @@ -74,7 +74,7 @@ public void testAuthWithAddressZeroResultsInError() { assertThat(validatorProvider.getVoteProviderAtHead().get().getProposals().get(a0)).isNull(); assertThat(response.getType()).isEqualTo(JsonRpcResponseType.ERROR); final JsonRpcErrorResponse errorResponse = (JsonRpcErrorResponse) response; - assertThat(errorResponse.getError()).isEqualTo(JsonRpcError.INVALID_REQUEST); + assertThat(errorResponse.getErrorType()).isEqualTo(RpcErrorType.INVALID_REQUEST); } @Test @@ -101,7 +101,7 @@ public void testDropWithAddressZeroResultsInError() { assertThat(validatorProvider.getVoteProviderAtHead().get().getProposals().get(a0)).isNull(); assertThat(response.getType()).isEqualTo(JsonRpcResponseType.ERROR); final JsonRpcErrorResponse errorResponse = (JsonRpcErrorResponse) response; - assertThat(errorResponse.getError()).isEqualTo(JsonRpcError.INVALID_REQUEST); + assertThat(errorResponse.getErrorType()).isEqualTo(RpcErrorType.INVALID_REQUEST); } @Test diff --git a/consensus/common/build.gradle b/consensus/common/build.gradle index 540cd788315..49c73e7d176 100644 --- a/consensus/common/build.gradle +++ b/consensus/common/build.gradle @@ -44,7 +44,7 @@ dependencies { implementation 'com.fasterxml.jackson.core:jackson-databind' implementation 'com.google.guava:guava' - implementation 'org.apache.tuweni:tuweni-bytes' + implementation 'io.tmio:tuweni-bytes' testImplementation project(':config') testImplementation project(':crypto:algorithms') diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/CombinedProtocolScheduleFactory.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/CombinedProtocolScheduleFactory.java index 9e9a8f90f9e..31768edad4c 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/CombinedProtocolScheduleFactory.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/CombinedProtocolScheduleFactory.java @@ -52,7 +52,9 @@ public BftProtocolSchedule create( Optional.ofNullable(forkSpecs.higher(spec)).map(ForkSpec::getBlock); protocolSchedule.getScheduledProtocolSpecs().stream() .filter(protocolSpecMatchesConsensusBlockRange(spec.getBlock(), endBlock)) - .forEach(s -> combinedProtocolSchedule.putBlockNumberMilestone(s.milestone(), s.spec())); + .forEach( + s -> + combinedProtocolSchedule.putBlockNumberMilestone(s.fork().milestone(), s.spec())); // When moving to a new consensus mechanism we want to use the last milestone but created by // our consensus mechanism's BesuControllerBuilder so any additional rules are applied @@ -67,7 +69,7 @@ public BftProtocolSchedule create( private Predicate protocolSpecMatchesConsensusBlockRange( final long startBlock, final Optional endBlock) { return scheduledProtocolSpec -> - scheduledProtocolSpec.milestone() >= startBlock - && endBlock.map(b -> scheduledProtocolSpec.milestone() < b).orElse(true); + scheduledProtocolSpec.fork().milestone() >= startBlock + && endBlock.map(b -> scheduledProtocolSpec.fork().milestone() < b).orElse(true); } } diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftProtocolSchedule.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftProtocolSchedule.java index 15530b66840..eca88b95841 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftProtocolSchedule.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftProtocolSchedule.java @@ -49,11 +49,12 @@ public ProtocolSpec getByBlockNumber(final long number) { checkArgument( !protocolSpecs.isEmpty(), "At least 1 milestone must be provided to the protocol schedule"); checkArgument( - protocolSpecs.last().milestone() == 0, "There must be a milestone starting from block 0"); + protocolSpecs.last().fork().milestone() == 0, + "There must be a milestone starting from block 0"); // protocolSpecs is sorted in descending block order, so the first one we find that's lower than // the requested level will be the most appropriate spec for (final ScheduledProtocolSpec s : protocolSpecs) { - if (number >= s.milestone()) { + if (number >= s.fork().milestone()) { return s.spec(); } } diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreator.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreator.java index b1b374b69ff..4e5a39f335f 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreator.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreator.java @@ -26,7 +26,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.core.SealableBlockHeader; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import java.util.Optional; @@ -46,7 +46,7 @@ public class BftBlockCreator extends AbstractBlockCreator { * @param localAddress the local address * @param targetGasLimitSupplier the target gas limit supplier * @param extraDataCalculator the extra data calculator - * @param pendingTransactions the pending transactions + * @param transactionPool the pending transactions * @param protocolContext the protocol context * @param protocolSchedule the protocol schedule * @param minTransactionGasPrice the min transaction gas price @@ -59,7 +59,7 @@ public BftBlockCreator( final Address localAddress, final Supplier> targetGasLimitSupplier, final ExtraDataCalculator extraDataCalculator, - final PendingTransactions pendingTransactions, + final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, final Wei minTransactionGasPrice, @@ -71,7 +71,7 @@ public BftBlockCreator( miningBeneficiaryCalculator(localAddress, forksSchedule), targetGasLimitSupplier, extraDataCalculator, - pendingTransactions, + transactionPool, protocolContext, protocolSchedule, minTransactionGasPrice, diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java index a7c6a1bbebe..35c6a33c94e 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java @@ -32,7 +32,7 @@ import org.hyperledger.besu.ethereum.blockcreation.BlockCreator; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.MiningParameters; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.AbstractGasLimitSpecification; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; @@ -53,7 +53,7 @@ public class BftBlockCreatorFactory { /** The Forks schedule. */ protected final ForksSchedule forksSchedule; - private final PendingTransactions pendingTransactions; + private final TransactionPool transactionPool; /** The Protocol context. */ protected final ProtocolContext protocolContext; /** The Protocol schedule. */ @@ -73,7 +73,7 @@ public class BftBlockCreatorFactory { /** * Instantiates a new Bft block creator factory. * - * @param pendingTransactions the pending transactions + * @param transactionPool the pending transactions * @param protocolContext the protocol context * @param protocolSchedule the protocol schedule * @param forksSchedule the forks schedule @@ -82,14 +82,14 @@ public class BftBlockCreatorFactory { * @param bftExtraDataCodec the bft extra data codec */ public BftBlockCreatorFactory( - final PendingTransactions pendingTransactions, + final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, final ForksSchedule forksSchedule, final MiningParameters miningParams, final Address localAddress, final BftExtraDataCodec bftExtraDataCodec) { - this.pendingTransactions = pendingTransactions; + this.transactionPool = transactionPool; this.protocolContext = protocolContext; this.protocolSchedule = protocolSchedule; this.forksSchedule = forksSchedule; @@ -114,7 +114,7 @@ public BlockCreator create(final BlockHeader parentHeader, final int round) { localAddress, () -> targetGasLimit.map(AtomicLong::longValue), ph -> createExtraData(round, ph), - pendingTransactions, + transactionPool, protocolContext, protocolSchedule, minTransactionGasPrice, diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/jsonrpc/AbstractGetSignerMetricsMethod.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/jsonrpc/AbstractGetSignerMetricsMethod.java index 8e14e94108d..3566684ab14 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/jsonrpc/AbstractGetSignerMetricsMethod.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/jsonrpc/AbstractGetSignerMetricsMethod.java @@ -19,10 +19,10 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.SignerMetricResult; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -76,7 +76,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { if (!isValidParameters(fromBlockNumber, toBlockNumber)) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } final Map proposersMap = new HashMap<>(); diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/jsonrpc/AbstractVoteProposerMethod.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/jsonrpc/AbstractVoteProposerMethod.java index b0983797eeb..289fe5b63d9 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/jsonrpc/AbstractVoteProposerMethod.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/jsonrpc/AbstractVoteProposerMethod.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.consensus.common.validator.ValidatorProvider; import org.hyperledger.besu.consensus.common.validator.VoteType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import java.util.Map; import java.util.stream.Collectors; @@ -57,7 +57,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), proposals); } else { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.METHOD_NOT_ENABLED); + requestContext.getRequest().getId(), RpcErrorType.METHOD_NOT_ENABLED); } } } diff --git a/consensus/common/src/test-support/java/org/hyperledger/besu/consensus/common/bft/BftContextBuilder.java b/consensus/common/src/test-support/java/org/hyperledger/besu/consensus/common/bft/BftContextBuilder.java index 4b8367d06fc..890045bf365 100644 --- a/consensus/common/src/test-support/java/org/hyperledger/besu/consensus/common/bft/BftContextBuilder.java +++ b/consensus/common/src/test-support/java/org/hyperledger/besu/consensus/common/bft/BftContextBuilder.java @@ -24,14 +24,17 @@ import java.util.Collection; +import org.mockito.quality.Strictness; + public class BftContextBuilder { public static BftContext setupContextWithValidators(final Collection
validators) { - final BftContext bftContext = mock(BftContext.class, withSettings().lenient()); + final BftContext bftContext = + mock(BftContext.class, withSettings().strictness(Strictness.LENIENT)); final ValidatorProvider mockValidatorProvider = - mock(ValidatorProvider.class, withSettings().lenient()); + mock(ValidatorProvider.class, withSettings().strictness(Strictness.LENIENT)); final BftBlockInterface mockBftBlockInterface = - mock(BftBlockInterface.class, withSettings().lenient()); + mock(BftBlockInterface.class, withSettings().strictness(Strictness.LENIENT)); when(bftContext.getValidatorProvider()).thenReturn(mockValidatorProvider); when(mockValidatorProvider.getValidatorsAfterBlock(any())).thenReturn(validators); when(bftContext.getBlockInterface()).thenReturn(mockBftBlockInterface); @@ -48,11 +51,11 @@ public static T setupContextWithBftExtraData( final Class contextClazz, final Collection
validators, final BftExtraData bftExtraData) { - final T bftContext = mock(contextClazz, withSettings().lenient()); + final T bftContext = mock(contextClazz, withSettings().strictness(Strictness.LENIENT)); final ValidatorProvider mockValidatorProvider = - mock(ValidatorProvider.class, withSettings().lenient()); + mock(ValidatorProvider.class, withSettings().strictness(Strictness.LENIENT)); final BftBlockInterface mockBftBlockInterface = - mock(BftBlockInterface.class, withSettings().lenient()); + mock(BftBlockInterface.class, withSettings().strictness(Strictness.LENIENT)); when(bftContext.getValidatorProvider()).thenReturn(mockValidatorProvider); when(mockValidatorProvider.getValidatorsAfterBlock(any())).thenReturn(validators); when(bftContext.getBlockInterface()).thenReturn(mockBftBlockInterface); @@ -70,9 +73,9 @@ public static T setupContextWithBftExtraDataEncoder( final Class contextClazz, final Collection
validators, final BftExtraDataCodec bftExtraDataCodec) { - final T bftContext = mock(contextClazz, withSettings().lenient()); + final T bftContext = mock(contextClazz, withSettings().strictness(Strictness.LENIENT)); final ValidatorProvider mockValidatorProvider = - mock(ValidatorProvider.class, withSettings().lenient()); + mock(ValidatorProvider.class, withSettings().strictness(Strictness.LENIENT)); when(bftContext.getValidatorProvider()).thenReturn(mockValidatorProvider); when(mockValidatorProvider.getValidatorsAfterBlock(any())).thenReturn(validators); when(bftContext.getBlockInterface()).thenReturn(new BftBlockInterface(bftExtraDataCodec)); diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/jsonrpc/AbstractVoteProposerMethodTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/jsonrpc/AbstractVoteProposerMethodTest.java index 8f7c66d5bed..a59bd556e4d 100644 --- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/jsonrpc/AbstractVoteProposerMethodTest.java +++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/jsonrpc/AbstractVoteProposerMethodTest.java @@ -24,10 +24,10 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import java.util.Optional; @@ -84,7 +84,7 @@ public void methodNotEnabledWhenNoVoteProvider() { new JsonRpcRequestContext( new JsonRpcRequest(JSON_RPC_VERSION, getMethodName(), new Object[] {})); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.METHOD_NOT_ENABLED); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.METHOD_NOT_ENABLED); when(validatorProvider.getVoteProviderAtHead()).thenReturn(Optional.empty()); final JsonRpcResponse response = getMethod().response(request); diff --git a/consensus/ibft/build.gradle b/consensus/ibft/build.gradle index 023d70c1626..dd05944803f 100644 --- a/consensus/ibft/build.gradle +++ b/consensus/ibft/build.gradle @@ -44,8 +44,8 @@ dependencies { implementation 'com.google.guava:guava' implementation 'io.vertx:vertx-core' implementation 'com.fasterxml.jackson.core:jackson-databind' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-units' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-units' integrationTestImplementation project(path: ':config', configuration: 'testSupportArtifacts') integrationTestImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts') diff --git a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java index 7d7778410cb..13fb1d57cf8 100644 --- a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java +++ b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java @@ -17,7 +17,10 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryBlockchain; import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryWorldStateArchive; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import org.hyperledger.besu.config.BftConfigOptions; import org.hyperledger.besu.config.BftFork; @@ -76,7 +79,12 @@ import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.Util; +import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics; import org.hyperledger.besu.ethereum.eth.transactions.sorter.GasPricePendingTransactionsSorter; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.evm.internal.EvmConfiguration; @@ -330,18 +338,33 @@ private static ControllerAndState createControllerAndFinalState( worldStateArchive, new BftContext(validatorProvider, epochManager, blockInterface), Optional.empty()); + final TransactionPoolConfiguration poolConf = + ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build(); final GasPricePendingTransactionsSorter pendingTransactions = new GasPricePendingTransactionsSorter( - ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build(), - clock, - metricsSystem, - blockChain::getChainHeadHeader); + poolConf, clock, metricsSystem, blockChain::getChainHeadHeader); + + final EthContext ethContext = mock(EthContext.class, RETURNS_DEEP_STUBS); + when(ethContext.getEthPeers().subscribeConnect(any())).thenReturn(1L); + + final TransactionPool transactionPool = + new TransactionPool( + () -> pendingTransactions, + protocolSchedule, + protocolContext, + mock(TransactionBroadcaster.class), + ethContext, + miningParams, + new TransactionPoolMetrics(metricsSystem), + poolConf); + + transactionPool.setEnabled(); final Address localAddress = Util.publicKeyToAddress(nodeKey.getPublicKey()); final BftBlockCreatorFactory blockCreatorFactory = new BftBlockCreatorFactory<>( - pendingTransactions, // changed from IbftBesuController + transactionPool, // changed from IbftBesuController protocolContext, protocolSchedule, forksSchedule, diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftExtraDataEncoderTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftExtraDataRLPEncoderTest.java similarity index 99% rename from consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftExtraDataEncoderTest.java rename to consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftExtraDataRLPEncoderTest.java index fe37c8edb23..bc16b70f1d8 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftExtraDataEncoderTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftExtraDataRLPEncoderTest.java @@ -41,7 +41,7 @@ import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.Test; -public class IbftExtraDataEncoderTest { +public class IbftExtraDataRLPEncoderTest { private static final Supplier SIGNATURE_ALGORITHM = Suppliers.memoize(SignatureAlgorithmFactory::getInstance); diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java index 8620b5cfb9f..a6668ad347e 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java @@ -18,6 +18,7 @@ import static org.hyperledger.besu.consensus.common.bft.BftContextBuilder.setupContextWithBftExtraDataEncoder; import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryWorldStateArchive; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -40,8 +41,14 @@ import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; +import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics; import org.hyperledger.besu.ethereum.eth.transactions.sorter.GasPricePendingTransactionsSorter; import org.hyperledger.besu.ethereum.mainnet.BlockHeaderValidator; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; @@ -116,13 +123,32 @@ public BlockHeaderValidator.Builder createBlockHeaderRuleset( setupContextWithBftExtraDataEncoder(initialValidatorList, bftExtraDataEncoder), Optional.empty()); + final TransactionPoolConfiguration poolConf = + ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build(); + final GasPricePendingTransactionsSorter pendingTransactions = new GasPricePendingTransactionsSorter( - ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build(), + poolConf, TestClock.system(ZoneId.systemDefault()), metricsSystem, blockchain::getChainHeadHeader); + final EthContext ethContext = mock(EthContext.class, RETURNS_DEEP_STUBS); + when(ethContext.getEthPeers().subscribeConnect(any())).thenReturn(1L); + + final TransactionPool transactionPool = + new TransactionPool( + () -> pendingTransactions, + protocolSchedule, + protContext, + mock(TransactionBroadcaster.class), + ethContext, + mock(MiningParameters.class), + new TransactionPoolMetrics(metricsSystem), + poolConf); + + transactionPool.setEnabled(); + final BftBlockCreator blockCreator = new BftBlockCreator( forksSchedule, @@ -136,7 +162,7 @@ public BlockHeaderValidator.Builder createBlockHeaderRuleset( Optional.empty(), 0, initialValidatorList)), - pendingTransactions, + transactionPool, protContext, protocolSchedule, Wei.ZERO, diff --git a/consensus/merge/build.gradle b/consensus/merge/build.gradle index 50bf258ab9f..9476f09d9d7 100644 --- a/consensus/merge/build.gradle +++ b/consensus/merge/build.gradle @@ -46,8 +46,8 @@ dependencies { implementation 'com.fasterxml.jackson.core:jackson-databind' implementation 'com.google.guava:guava' implementation 'io.vertx:vertx-core' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-units' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-units' testImplementation project(path: ':consensus:common', configuration: 'testArtifacts') testImplementation project(':crypto:algorithms') diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java index f934e4cd30d..b3e044dfdb4 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java @@ -18,8 +18,8 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.PermissionTransactionFilter; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; -import org.hyperledger.besu.ethereum.core.TransactionFilter; import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; @@ -203,6 +203,13 @@ public void putTimestampMilestone(final long timestamp, final ProtocolSpec proto "Should not use TransitionProtocolSchedule wrapper class to create milestones"); } + @Override + public Optional hardforkFor( + final Predicate predicate) { + return this.transitionUtils.dispatchFunctionAccordingToMergeState( + schedule -> schedule.hardforkFor(predicate)); + } + /** * List milestones. * @@ -216,12 +223,14 @@ public String listMilestones() { /** * Sets transaction filter. * - * @param transactionFilter the transaction filter + * @param permissionTransactionFilter the transaction filter */ @Override - public void setTransactionFilter(final TransactionFilter transactionFilter) { + public void setPermissionTransactionFilter( + final PermissionTransactionFilter permissionTransactionFilter) { transitionUtils.dispatchConsumerAccordingToMergeState( - protocolSchedule -> protocolSchedule.setTransactionFilter(transactionFilter)); + protocolSchedule -> + protocolSchedule.setPermissionTransactionFilter(permissionTransactionFilter)); } /** diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeBlockCreator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeBlockCreator.java index 21922727788..792544f187b 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeBlockCreator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeBlockCreator.java @@ -24,7 +24,7 @@ import org.hyperledger.besu.ethereum.core.SealableBlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Withdrawal; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import java.util.Collections; @@ -51,7 +51,7 @@ class MergeBlockCreator extends AbstractBlockCreator { * @param coinbase the coinbase * @param targetGasLimitSupplier the target gas limit supplier * @param extraDataCalculator the extra data calculator - * @param pendingTransactions the pending transactions + * @param transactionPool the pending transactions * @param protocolContext the protocol context * @param protocolSchedule the protocol schedule * @param minTransactionGasPrice the min transaction gas price @@ -62,7 +62,7 @@ public MergeBlockCreator( final Address coinbase, final Supplier> targetGasLimitSupplier, final ExtraDataCalculator extraDataCalculator, - final PendingTransactions pendingTransactions, + final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, final Wei minTransactionGasPrice, @@ -74,7 +74,7 @@ public MergeBlockCreator( __ -> miningBeneficiary, targetGasLimitSupplier, extraDataCalculator, - pendingTransactions, + transactionPool, protocolContext, protocolSchedule, minTransactionGasPrice, diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java index c1069fc6ce9..d1c7d3ea91a 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java @@ -38,7 +38,7 @@ import org.hyperledger.besu.ethereum.core.Withdrawal; import org.hyperledger.besu.ethereum.eth.sync.backwardsync.BackwardSyncContext; import org.hyperledger.besu.ethereum.eth.sync.backwardsync.BadChainListener; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.AbstractGasLimitSpecification; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; @@ -101,7 +101,7 @@ public class MergeCoordinator implements MergeMiningCoordinator, BadChainListene * @param protocolContext the protocol context * @param protocolSchedule the protocol schedule * @param blockBuilderExecutor the block builder executor - * @param pendingTransactions the pending transactions + * @param transactionPool the pending transactions * @param miningParams the mining params * @param backwardSyncContext the backward sync context * @param depositContractAddress the address of the deposit contract @@ -110,7 +110,7 @@ public MergeCoordinator( final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, final ProposalBuilderExecutor blockBuilderExecutor, - final PendingTransactions pendingTransactions, + final TransactionPool transactionPool, final MiningParameters miningParams, final BackwardSyncContext backwardSyncContext, final Optional
depositContractAddress) { @@ -133,7 +133,7 @@ public MergeCoordinator( address.or(miningParameters::getCoinbase).orElse(Address.ZERO), () -> Optional.of(targetGasLimit.longValue()), parent -> extraData.get(), - pendingTransactions, + transactionPool, protocolContext, protocolSchedule, this.miningParameters.getMinTransactionGasPrice(), @@ -607,33 +607,30 @@ private boolean setNewHead(final MutableBlockchain blockchain, final BlockHeader return true; } - if (newHead.getParentHash().equals(blockchain.getChainHeadHash())) { - LOG.atDebug() - .setMessage( - "Forwarding chain head to the block {} saved from a previous newPayload invocation") - .addArgument(newHead::toLogString) - .log(); - - if (forwardWorldStateTo(newHead)) { - // move chain head forward: + if (moveWorldStateTo(newHead)) { + if (newHead.getParentHash().equals(blockchain.getChainHeadHash())) { + LOG.atDebug() + .setMessage( + "Forwarding chain head to the block {} saved from a previous newPayload invocation") + .addArgument(newHead::toLogString) + .log(); return blockchain.forwardToBlock(newHead); } else { LOG.atDebug() - .setMessage("Failed to move the worldstate forward to hash {}, not moving chain head") + .setMessage("New head {} is a chain reorg, rewind chain head to it") .addArgument(newHead::toLogString) .log(); - return false; + return blockchain.rewindToBlock(newHead.getHash()); } } - LOG.atDebug() - .setMessage("New head {} is a chain reorg, rewind chain head to it") + .setMessage("Failed to move the worldstate forward to hash {}, not moving chain head") .addArgument(newHead::toLogString) .log(); - return blockchain.rewindToBlock(newHead.getHash()); + return false; } - private boolean forwardWorldStateTo(final BlockHeader newHead) { + private boolean moveWorldStateTo(final BlockHeader newHead) { Optional newWorldState = protocolContext .getWorldStateArchive() diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java index d4820dff70b..12e236d37f1 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java @@ -61,8 +61,13 @@ import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.core.Withdrawal; +import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.sync.backwardsync.BackwardSyncContext; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics; import org.hyperledger.besu.ethereum.eth.transactions.sorter.BaseFeePendingTransactionsSorter; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; @@ -91,6 +96,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Spy; @@ -122,6 +128,9 @@ public class MergeCoordinatorTest implements MergeGenesisConfigHelper { @Mock MergeContext mergeContext; @Mock BackwardSyncContext backwardSyncContext; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + EthContext ethContext; + @Mock ProposalBuilderExecutor proposalBuilderExecutor; private final Address coinbase = genesisAllocations(getPosGenesisConfigFile()).findFirst().get(); @@ -152,16 +161,20 @@ public class MergeCoordinatorTest implements MergeGenesisConfigHelper { private final org.hyperledger.besu.metrics.StubMetricsSystem metricsSystem = new StubMetricsSystem(); + private final TransactionPoolConfiguration poolConf = + ImmutableTransactionPoolConfiguration.builder() + .txPoolMaxSize(10) + .txPoolLimitByAccountPercentage(100.0f) + .build(); private final BaseFeePendingTransactionsSorter transactions = new BaseFeePendingTransactionsSorter( - ImmutableTransactionPoolConfiguration.builder() - .txPoolMaxSize(10) - .txPoolLimitByAccountPercentage(100.0f) - .build(), + poolConf, TestClock.system(ZoneId.systemDefault()), metricsSystem, MergeCoordinatorTest::mockBlockHeader); + private TransactionPool transactionPool; + CompletableFuture blockCreationTask = CompletableFuture.completedFuture(null); private final BadBlockManager badBlockManager = spy(new BadBlockManager()); @@ -202,12 +215,26 @@ public void setUp() { MergeConfigOptions.setMergeEnabled(true); + when(ethContext.getEthPeers().subscribeConnect(any())).thenReturn(1L); + this.transactionPool = + new TransactionPool( + () -> transactions, + protocolSchedule, + protocolContext, + mock(TransactionBroadcaster.class), + ethContext, + miningParameters, + new TransactionPoolMetrics(metricsSystem), + poolConf); + + this.transactionPool.setEnabled(); + this.coordinator = new MergeCoordinator( protocolContext, protocolSchedule, proposalBuilderExecutor, - transactions, + transactionPool, miningParameters, backwardSyncContext, Optional.empty()); @@ -254,7 +281,7 @@ public void exceptionDuringBuildingBlockShouldNotBeInvalid() address.or(miningParameters::getCoinbase).orElse(Address.ZERO), () -> Optional.of(30000000L), parent -> Bytes.EMPTY, - transactions, + transactionPool, protocolContext, protocolSchedule, this.miningParameters.getMinTransactionGasPrice(), @@ -659,7 +686,7 @@ public void shouldUseExtraDataFromMiningParameters() { protocolContext, protocolSchedule, proposalBuilderExecutor, - transactions, + transactionPool, miningParameters, backwardSyncContext, Optional.empty()); @@ -943,7 +970,7 @@ public void assertNonGenesisTerminalBlockSatisfiesDescendsFromTerminal() { mockProtocolContext, protocolSchedule, CompletableFuture::runAsync, - transactions, + transactionPool, new MiningParameters.Builder().coinbase(coinbase).build(), mock(BackwardSyncContext.class), Optional.empty()); @@ -1005,7 +1032,7 @@ public void assertMergeAtGenesisSatisifiesTerminalPoW() { mockProtocolContext, protocolSchedule, CompletableFuture::runAsync, - transactions, + transactionPool, new MiningParameters.Builder().coinbase(coinbase).build(), mock(BackwardSyncContext.class), Optional.empty()); @@ -1153,7 +1180,7 @@ MergeCoordinator terminalAncestorMock(final long chainDepth, final boolean hasTe mockProtocolContext, protocolSchedule, CompletableFuture::runAsync, - transactions, + transactionPool, new MiningParameters.Builder().coinbase(coinbase).build(), mock(BackwardSyncContext.class), Optional.empty())); diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java index bd18caa9ea1..d5dbd139c6c 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java @@ -35,7 +35,7 @@ import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.eth.sync.backwardsync.BackwardSyncContext; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.BlockHeaderValidator; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; @@ -60,7 +60,7 @@ @MockitoSettings(strictness = Strictness.LENIENT) public class MergeReorgTest implements MergeGenesisConfigHelper { - @Mock PendingTransactions mockPendingTransactions; + @Mock TransactionPool mockTransactionPool; private MergeCoordinator coordinator; @@ -92,7 +92,7 @@ public void setUp() { protocolContext, mockProtocolSchedule, CompletableFuture::runAsync, - mockPendingTransactions, + mockTransactionPool, new MiningParameters.Builder().coinbase(coinbase).build(), mock(BackwardSyncContext.class), Optional.empty()); diff --git a/consensus/qbft/build.gradle b/consensus/qbft/build.gradle index 54647ef51db..bb3d9a3f894 100644 --- a/consensus/qbft/build.gradle +++ b/consensus/qbft/build.gradle @@ -45,8 +45,8 @@ dependencies { implementation 'com.google.guava:guava' implementation 'io.vertx:vertx-core' implementation 'com.fasterxml.jackson.core:jackson-databind' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-units' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-units' implementation 'org.web3j:abi' integrationTestImplementation project(path: ':config', configuration: 'testSupportArtifacts') diff --git a/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java b/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java index 76c429d2124..eb4e6345207 100644 --- a/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java +++ b/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java @@ -17,7 +17,10 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryBlockchain; import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryWorldStateArchive; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import org.hyperledger.besu.config.BftFork; import org.hyperledger.besu.config.JsonQbftConfigOptions; @@ -90,7 +93,12 @@ import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture; import org.hyperledger.besu.ethereum.core.Util; +import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics; import org.hyperledger.besu.ethereum.eth.transactions.sorter.GasPricePendingTransactionsSorter; import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; import org.hyperledger.besu.ethereum.worldstate.DefaultWorldStateArchive; @@ -122,61 +130,20 @@ import org.apache.tuweni.bytes.Bytes; public class TestContextBuilder { + @SuppressWarnings( + "UnusedVariable") // false positive https://github.com/google/error-prone/issues/2713 + private record ControllerAndState( + BftExecutors bftExecutors, + BftEventHandler eventHandler, + BftFinalState finalState, + EventMultiplexer eventMultiplexer, + MessageFactory messageFactory, + ValidatorProvider validatorProvider) {} private static final MetricsSystem metricsSystem = new NoOpMetricsSystem(); private boolean useValidatorContract; private boolean useLondonMilestone = false; private boolean useZeroBaseFee = false; - - private static class ControllerAndState { - - private final BftExecutors bftExecutors; - private final BftEventHandler eventHandler; - private final BftFinalState finalState; - private final EventMultiplexer eventMultiplexer; - private final MessageFactory messageFactory; - private final ValidatorProvider validatorProvider; - - public ControllerAndState( - final BftExecutors bftExecutors, - final BftEventHandler eventHandler, - final BftFinalState finalState, - final EventMultiplexer eventMultiplexer, - final MessageFactory messageFactory, - final ValidatorProvider validatorProvider) { - this.bftExecutors = bftExecutors; - this.eventHandler = eventHandler; - this.finalState = finalState; - this.eventMultiplexer = eventMultiplexer; - this.messageFactory = messageFactory; - this.validatorProvider = validatorProvider; - } - - public BftExecutors getBftExecutors() { - return bftExecutors; - } - - public BftEventHandler getEventHandler() { - return eventHandler; - } - - public BftFinalState getFinalState() { - return finalState; - } - - public EventMultiplexer getEventMultiplexer() { - return eventMultiplexer; - } - - public MessageFactory getMessageFactory() { - return messageFactory; - } - - public ValidatorProvider getValidatorProvider() { - return validatorProvider; - } - } - public static final int EPOCH_LENGTH = 10_000; public static final int BLOCK_TIMER_SEC = 3; public static final int ROUND_TIMER_SEC = 12; @@ -329,7 +296,7 @@ public TestContext build() { new ValidatorPeer( nodeParams, new MessageFactory(nodeParams.getNodeKey()), - controllerAndState.getEventMultiplexer()), + controllerAndState.eventMultiplexer()), (u, v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); }, @@ -342,12 +309,12 @@ public TestContext build() { return new TestContext( remotePeers, blockChain, - controllerAndState.getBftExecutors(), - controllerAndState.getEventHandler(), - controllerAndState.getFinalState(), - controllerAndState.getEventMultiplexer(), - controllerAndState.getMessageFactory(), - controllerAndState.getValidatorProvider(), + controllerAndState.bftExecutors(), + controllerAndState.eventHandler(), + controllerAndState.finalState(), + controllerAndState.eventMultiplexer(), + controllerAndState.messageFactory(), + controllerAndState.validatorProvider(), BFT_EXTRA_DATA_ENCODER); } @@ -459,17 +426,33 @@ private static ControllerAndState createControllerAndFinalState( new QbftContext(validatorProvider, epochManager, blockInterface, Optional.empty()), Optional.empty()); + final TransactionPoolConfiguration poolConf = + ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build(); + final GasPricePendingTransactionsSorter pendingTransactions = new GasPricePendingTransactionsSorter( - ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build(), - clock, - metricsSystem, - blockChain::getChainHeadHeader); + poolConf, clock, metricsSystem, blockChain::getChainHeadHeader); + + final EthContext ethContext = mock(EthContext.class, RETURNS_DEEP_STUBS); + when(ethContext.getEthPeers().subscribeConnect(any())).thenReturn(1L); + + final TransactionPool transactionPool = + new TransactionPool( + () -> pendingTransactions, + protocolSchedule, + protocolContext, + mock(TransactionBroadcaster.class), + ethContext, + miningParams, + new TransactionPoolMetrics(metricsSystem), + poolConf); + + transactionPool.setEnabled(); final Address localAddress = Util.publicKeyToAddress(nodeKey.getPublicKey()); final BftBlockCreatorFactory blockCreatorFactory = new QbftBlockCreatorFactory( - pendingTransactions, // changed from QbftBesuController + transactionPool, // changed from QbftBesuController protocolContext, protocolSchedule, forksSchedule, diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactory.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactory.java index 47c3a466211..c2007ededf7 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactory.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactory.java @@ -26,7 +26,7 @@ import org.hyperledger.besu.ethereum.blockcreation.BlockCreator; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.MiningParameters; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import java.util.Collections; @@ -39,7 +39,7 @@ public class QbftBlockCreatorFactory extends BftBlockCreatorFactory forksSchedule, @@ -56,7 +56,7 @@ public QbftBlockCreatorFactory( final Address localAddress, final BftExtraDataCodec bftExtraDataCodec) { super( - pendingTransactions, + transactionPool, protocolContext, protocolSchedule, forksSchedule, diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/jsonrpc/methods/QbftDiscardValidatorVote.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/jsonrpc/methods/QbftDiscardValidatorVote.java index 76f95c9f53f..7e9a3b973fd 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/jsonrpc/methods/QbftDiscardValidatorVote.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/jsonrpc/methods/QbftDiscardValidatorVote.java @@ -19,10 +19,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,7 +56,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), true); } else { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.METHOD_NOT_ENABLED); + requestContext.getRequest().getId(), RpcErrorType.METHOD_NOT_ENABLED); } } } diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/jsonrpc/methods/QbftProposeValidatorVote.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/jsonrpc/methods/QbftProposeValidatorVote.java index 98033ca2f6c..160ca144d69 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/jsonrpc/methods/QbftProposeValidatorVote.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/jsonrpc/methods/QbftProposeValidatorVote.java @@ -20,10 +20,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -66,7 +66,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), true); } else { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.METHOD_NOT_ENABLED); + requestContext.getRequest().getId(), RpcErrorType.METHOD_NOT_ENABLED); } } } diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactoryTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactoryTest.java index e9345606963..fa2e8158530 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactoryTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactoryTest.java @@ -31,7 +31,7 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.MiningParameters; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import java.util.Optional; @@ -59,7 +59,7 @@ public void setUp() throws Exception { qbftBlockCreatorFactory = new QbftBlockCreatorFactory( - mock(PendingTransactions.class), + mock(TransactionPool.class), mock(ProtocolContext.class), mock(ProtocolSchedule.class), forksSchedule, diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/jsonrpc/methods/QbftDiscardValidatorVoteTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/jsonrpc/methods/QbftDiscardValidatorVoteTest.java index 4e0c30dea7b..0716fd42d20 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/jsonrpc/methods/QbftDiscardValidatorVoteTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/jsonrpc/methods/QbftDiscardValidatorVoteTest.java @@ -26,10 +26,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import java.util.Optional; @@ -72,7 +72,7 @@ public void exceptionWhenInvalidAddressParameterSupplied() { public void methodNotEnabledWhenNoVoteProvider() { final JsonRpcRequestContext request = requestWithParams(Address.fromHexString("1")); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.METHOD_NOT_ENABLED); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.METHOD_NOT_ENABLED); when(validatorProvider.getVoteProviderAtHead()).thenReturn(Optional.empty()); final JsonRpcResponse response = method.response(request); diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/jsonrpc/methods/QbftProposeValidatorVoteTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/jsonrpc/methods/QbftProposeValidatorVoteTest.java index b9f2f9c2660..fa3f89036eb 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/jsonrpc/methods/QbftProposeValidatorVoteTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/jsonrpc/methods/QbftProposeValidatorVoteTest.java @@ -26,10 +26,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import java.util.Optional; @@ -86,7 +86,7 @@ public void exceptionWhenInvalidBoolParameterSupplied() { public void methodNotEnabledWhenNoVoteProvider() { final JsonRpcRequestContext request = requestWithParams(Address.fromHexString("1")); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.METHOD_NOT_ENABLED); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.METHOD_NOT_ENABLED); when(validatorProvider.getVoteProviderAtHead()).thenReturn(Optional.empty()); final JsonRpcResponse response = method.response(request); diff --git a/crypto/algorithms/build.gradle b/crypto/algorithms/build.gradle index ad5346e2273..dcddb83be34 100644 --- a/crypto/algorithms/build.gradle +++ b/crypto/algorithms/build.gradle @@ -33,8 +33,8 @@ dependencies { api 'org.slf4j:slf4j-api' implementation 'net.java.dev.jna:jna' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-units' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-units' implementation 'org.hyperledger.besu:secp256k1' implementation 'org.hyperledger.besu:secp256r1' implementation 'org.hyperledger.besu:blake2bf' diff --git a/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/SECP256K1.java b/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/SECP256K1.java index 6221ef351b5..8d7ba7924f3 100644 --- a/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/SECP256K1.java +++ b/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/SECP256K1.java @@ -59,10 +59,7 @@ public SECP256K1() { super(CURVE_NAME, SecP256K1Curve.q); // use the native library implementation, if it is available - useNative = LibSecp256k1.CONTEXT != null; - if (!useNative) { - LOG.info("Native secp256k1 not available"); - } + maybeEnableNative(); } @Override @@ -70,6 +67,21 @@ public void disableNative() { useNative = false; } + /** + * Attempt to enable the native library for secp256k1 + * + * @return true if the native library was enabled. + */ + public boolean maybeEnableNative() { + try { + useNative = LibSecp256k1.CONTEXT != null; + } catch (UnsatisfiedLinkError | NoClassDefFoundError e) { + LOG.info("Native secp256k1 not available - {}", e.getMessage()); + useNative = false; + } + return useNative; + } + @Override public boolean isNative() { return useNative; diff --git a/datatypes/build.gradle b/datatypes/build.gradle index 2f4a0e02065..a55bf4e45c5 100644 --- a/datatypes/build.gradle +++ b/datatypes/build.gradle @@ -34,8 +34,8 @@ dependencies { implementation project(':crypto:algorithms') implementation project(':ethereum:rlp') implementation 'com.google.guava:guava' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-units' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-units' testImplementation 'org.assertj:assertj-core' testImplementation 'org.junit.jupiter:junit-jupiter' diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java index c68058e9796..c38ba5303c3 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java @@ -22,7 +22,12 @@ import org.hyperledger.besu.ethereum.rlp.RLPException; import org.hyperledger.besu.ethereum.rlp.RLPInput; +import java.util.concurrent.ExecutionException; + import com.fasterxml.jackson.annotation.JsonCreator; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.DelegatingBytes; @@ -77,6 +82,18 @@ public class Address extends DelegatingBytes { /** The constant ZERO. */ public static final Address ZERO = Address.fromHexString("0x0"); + static LoadingCache hashCache = + CacheBuilder.newBuilder() + .maximumSize(4000) + // .weakKeys() // unless we "intern" all addresses we cannot use weak or soft keys. + .build( + new CacheLoader<>() { + @Override + public Hash load(final Address key) { + return Hash.hash(key); + } + }); + /** * Instantiates a new Address. * @@ -239,4 +256,17 @@ public static Address privateContractAddress( out.endList(); }))); } + + /** + * Returns the hash of the address. Backed by a cache for performance reasons. + * + * @return the hash of the address. + */ + public Hash addressHash() { + try { + return hashCache.get(this); + } catch (ExecutionException e) { + return Hash.hash(this); + } + } } diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Blob.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Blob.java new file mode 100644 index 00000000000..5b089919708 --- /dev/null +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Blob.java @@ -0,0 +1,64 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.datatypes; + +import org.hyperledger.besu.ethereum.rlp.RLPInput; +import org.hyperledger.besu.ethereum.rlp.RLPOutput; + +import org.apache.tuweni.bytes.Bytes; + +/** Arbitrary data for use in the KZG scheme. */ +public class Blob { + + final Bytes data; + + /** + * Create a new Blob. + * + * @param data that represents the blob. + */ + public Blob(final Bytes data) { + this.data = data; + } + + /** + * Read a Blob from an RLPInput. + * + * @param input to read from. + * @return the Blob. + */ + public static Blob readFrom(final RLPInput input) { + final Bytes bytes = input.readBytes(); + return new Blob(bytes); + } + + /** + * Write the Blob to an RLPOutput. + * + * @param out to write to. + */ + public void writeTo(final RLPOutput out) { + out.writeBytes(data); + } + + /** + * Get the data of the Blob. + * + * @return the data. + */ + public Bytes getData() { + return data; + } +} diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlobGas.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlobGas.java new file mode 100644 index 00000000000..134e9cb4145 --- /dev/null +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlobGas.java @@ -0,0 +1,145 @@ +/* + * Copyright contributors to Hyperledger Besu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.datatypes; + +import java.math.BigInteger; + +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.units.bigints.BaseUInt64Value; +import org.apache.tuweni.units.bigints.UInt64; + +/** A particular quantity of BlobGas */ +public final class BlobGas extends BaseUInt64Value implements Quantity { + + /** The constant ZERO. */ + public static final BlobGas ZERO = of(0); + + /** The constant ONE. */ + public static final BlobGas ONE = of(1); + + /** The constant MAX_BLOB_GAS. */ + public static final BlobGas MAX_BLOB_GAS = of(UInt64.MAX_VALUE); + + /** + * Instantiates a new BlobGas. + * + * @param value the value + */ + BlobGas(final UInt64 value) { + super(value, BlobGas::new); + } + + private BlobGas(final long v) { + this(UInt64.valueOf(v)); + } + + private BlobGas(final BigInteger v) { + this(UInt64.valueOf(v)); + } + + private BlobGas(final String hexString) { + this(UInt64.fromHexString(hexString)); + } + + /** + * blob gas of value. + * + * @param value the value + * @return the blob gas + */ + public static BlobGas of(final long value) { + return new BlobGas(value); + } + + /** + * blob gas of value. + * + * @param value the value + * @return the blob gas + */ + public static BlobGas of(final BigInteger value) { + return new BlobGas(value); + } + + /** + * blob gas of value. + * + * @param value the value + * @return the blob gas + */ + public static BlobGas of(final UInt64 value) { + return new BlobGas(value); + } + + /** + * blob gas of value. + * + * @param value the value + * @return the blob gas + */ + public static BlobGas ofNumber(final Number value) { + return new BlobGas((BigInteger) value); + } + + /** + * Wrap blob gas. + * + * @param value the value + * @return the blob gas + */ + public static BlobGas wrap(final Bytes value) { + return new BlobGas(UInt64.fromBytes(value)); + } + + /** + * From hex string to blob gas. + * + * @param str the str + * @return the blob gas + */ + public static BlobGas fromHexString(final String str) { + return new BlobGas(str); + } + + @Override + public Number getValue() { + return getAsBigInteger(); + } + + @Override + public BigInteger getAsBigInteger() { + return toBigInteger(); + } + + @Override + public String toHexString() { + return super.toHexString(); + } + + @Override + public String toShortHexString() { + return super.isZero() ? "0x0" : super.toShortHexString(); + } + + /** + * From quantity to blob gas. + * + * @param quantity the quantity + * @return the blob gas + */ + public static BlobGas fromQuantity(final Quantity quantity) { + return BlobGas.wrap((Bytes) quantity); + } +} diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlobsWithCommitments.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlobsWithCommitments.java new file mode 100644 index 00000000000..ed0a6dcf9a8 --- /dev/null +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlobsWithCommitments.java @@ -0,0 +1,88 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.datatypes; + +import java.security.InvalidParameterException; +import java.util.List; + +/** A class to hold the blobs, commitments, proofs and versioned hashes for a set of blobs. */ +public class BlobsWithCommitments { + private final List kzgCommitments; + private final List blobs; + private final List kzgProofs; + + private final List versionedHashes; + + /** + * A class to hold the blobs, commitments and proofs for a set of blobs. + * + * @param kzgCommitments commitments for the blobs + * @param blobs list of blobs to be committed to + * @param kzgProofs proofs for the commitments + * @param versionedHashes hashes of the commitments + */ + public BlobsWithCommitments( + final List kzgCommitments, + final List blobs, + final List kzgProofs, + final List versionedHashes) { + if (blobs.size() != kzgCommitments.size() + || blobs.size() != kzgProofs.size() + || kzgCommitments.size() != versionedHashes.size()) { + throw new InvalidParameterException( + "There must be an equal number of blobs, commitments and proofs"); + } + this.kzgCommitments = kzgCommitments; + this.blobs = blobs; + this.kzgProofs = kzgProofs; + this.versionedHashes = versionedHashes; + } + + /** + * Get the blobs. + * + * @return the blobs + */ + public List getBlobs() { + return blobs; + } + + /** + * Get the commitments. + * + * @return the commitments + */ + public List getKzgCommitments() { + return kzgCommitments; + } + + /** + * Get the proofs. + * + * @return the proofs + */ + public List getKzgProofs() { + return kzgProofs; + } + + /** + * Get the hashes. + * + * @return the hashes + */ + public List getVersionedHashes() { + return versionedHashes; + } +} diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/DataGas.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/DataGas.java deleted file mode 100644 index 6028403ed0e..00000000000 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/DataGas.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright contributors to Hyperledger Besu - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.datatypes; - -import java.math.BigInteger; - -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.units.bigints.BaseUInt256Value; -import org.apache.tuweni.units.bigints.UInt256; - -/** A particular quantity of DataGas */ -public final class DataGas extends BaseUInt256Value implements Quantity { - - /** The constant ZERO. */ - public static final DataGas ZERO = of(0); - - /** The constant ONE. */ - public static final DataGas ONE = of(1); - - /** The constant MAX_DATA_GAS. */ - public static final DataGas MAX_DATA_GAS = of(UInt256.MAX_VALUE); - - /** - * Instantiates a new DataGas. - * - * @param value the value - */ - DataGas(final UInt256 value) { - super(value, DataGas::new); - } - - private DataGas(final long v) { - this(UInt256.valueOf(v)); - } - - private DataGas(final BigInteger v) { - this(UInt256.valueOf(v)); - } - - private DataGas(final String hexString) { - this(UInt256.fromHexString(hexString)); - } - - /** - * data gas of value. - * - * @param value the value - * @return the data gas - */ - public static DataGas of(final long value) { - return new DataGas(value); - } - - /** - * data gas of value. - * - * @param value the value - * @return the data gas - */ - public static DataGas of(final BigInteger value) { - return new DataGas(value); - } - - /** - * data gas of value. - * - * @param value the value - * @return the data gas - */ - public static DataGas of(final UInt256 value) { - return new DataGas(value); - } - - /** - * data gas of value. - * - * @param value the value - * @return the data gas - */ - public static DataGas ofNumber(final Number value) { - return new DataGas((BigInteger) value); - } - - /** - * Wrap data gas. - * - * @param value the value - * @return the data gas - */ - public static DataGas wrap(final Bytes value) { - return new DataGas(UInt256.fromBytes(value)); - } - - /** - * From hex string to data gas. - * - * @param str the str - * @return the data gas - */ - public static DataGas fromHexString(final String str) { - return new DataGas(str); - } - - @Override - public Number getValue() { - return getAsBigInteger(); - } - - @Override - public BigInteger getAsBigInteger() { - return toBigInteger(); - } - - @Override - public String toHexString() { - return super.toHexString(); - } - - @Override - public String toShortHexString() { - return super.isZero() ? "0x0" : super.toShortHexString(); - } - - /** - * From quantity to data gas. - * - * @param quantity the quantity - * @return the data gas - */ - public static DataGas fromQuantity(final Quantity quantity) { - return DataGas.wrap((Bytes) quantity); - } -} diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Hash.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Hash.java index cb14101acd9..fa0b85c451b 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Hash.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Hash.java @@ -47,7 +47,12 @@ public class Hash extends DelegatingBytes32 { */ public static final Hash EMPTY = hash(Bytes.EMPTY); - private Hash(final Bytes32 bytes) { + /** + * Instantiates a new Hash. + * + * @param bytes raw bytes + */ + protected Hash(final Bytes32 bytes) { super(bytes); } diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/KZGCommitment.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/KZGCommitment.java new file mode 100644 index 00000000000..f64ebf5aead --- /dev/null +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/KZGCommitment.java @@ -0,0 +1,63 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.datatypes; + +import org.hyperledger.besu.ethereum.rlp.RLPInput; +import org.hyperledger.besu.ethereum.rlp.RLPOutput; + +import org.apache.tuweni.bytes.Bytes; + +/** This class contains the data for a KZG commitment. */ +public class KZGCommitment { + final Bytes data; + + /** + * Constructor for a KZG commitment. + * + * @param data The data for the KZG commitment. + */ + public KZGCommitment(final Bytes data) { + this.data = data; + } + + /** + * Reads a KZG commitment from the RLP input. + * + * @param input The RLP input. + * @return The KZG commitment. + */ + public static KZGCommitment readFrom(final RLPInput input) { + final Bytes bytes = input.readBytes(); + return new KZGCommitment(bytes); + } + + /** + * Writes the KZG commitment to the RLP output. + * + * @param out The RLP output. + */ + public void writeTo(final RLPOutput out) { + out.writeBytes(data); + } + + /** + * Gets the data for the KZG commitment. + * + * @return The data for the KZG commitment. + */ + public Bytes getData() { + return data; + } +} diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/KZGProof.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/KZGProof.java new file mode 100644 index 00000000000..3a7a2d0686a --- /dev/null +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/KZGProof.java @@ -0,0 +1,63 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.datatypes; + +import org.hyperledger.besu.ethereum.rlp.RLPInput; +import org.hyperledger.besu.ethereum.rlp.RLPOutput; + +import org.apache.tuweni.bytes.Bytes; + +/** This class contains the data for a KZG proof for a KZG commitment. */ +public class KZGProof { + final Bytes data; + + /** + * Constructor for a KZG proof. + * + * @param data The data for the KZG proof. + */ + public KZGProof(final Bytes data) { + this.data = data; + } + + /** + * Reads a KZG proof from the RLP input. + * + * @param input The RLP input. + * @return The KZG proof. + */ + public static KZGProof readFrom(final RLPInput input) { + final Bytes bytes = input.readBytes(); + return new KZGProof(bytes); + } + + /** + * Writes the KZG proof to the RLP output. + * + * @param out The RLP output. + */ + public void writeTo(final RLPOutput out) { + out.writeBytes(data); + } + + /** + * Gets the data for the KZG proof. + * + * @return The data for the KZG proof. + */ + public Bytes getData() { + return data; + } +} diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Sha256Hash.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Sha256Hash.java new file mode 100644 index 00000000000..9dbfeacc974 --- /dev/null +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Sha256Hash.java @@ -0,0 +1,42 @@ +/* + * Copyright Hyperledger Besu contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hyperledger.besu.datatypes; + +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; + +/** A Sha256Hash is a Hash that has been generated using the SHA-256 algorithm. */ +public class Sha256Hash extends Hash { + + /** + * Construct a Sha256Hash from a Bytes32 value. + * + * @param bytes raw bytes of the hash + */ + private Sha256Hash(final Bytes32 bytes) { + super(bytes); + } + + /** + * Construct a Sha256Hash from a Bytes value. + * + * @param value The value to hash. + * @return The Sha256Hash of the value. + */ + public static Hash sha256(final Bytes value) { + return new Sha256Hash(org.hyperledger.besu.crypto.Hash.sha256(value)); + } +} diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/Transaction.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Transaction.java similarity index 93% rename from plugin-api/src/main/java/org/hyperledger/besu/plugin/data/Transaction.java rename to datatypes/src/main/java/org/hyperledger/besu/datatypes/Transaction.java index 3d7c9f367e0..99eef4715b4 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/Transaction.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Transaction.java @@ -12,12 +12,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.hyperledger.besu.plugin.data; - -import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.datatypes.Quantity; -import org.hyperledger.besu.plugin.Unstable; +package org.hyperledger.besu.datatypes; import java.math.BigInteger; import java.util.Optional; @@ -64,7 +59,6 @@ public interface Transaction { * * @return the quantity of Wei for max fee per gas */ - @Unstable default Optional getMaxPriorityFeePerGas() { return Optional.empty(); } @@ -74,19 +68,17 @@ default Optional getMaxPriorityFeePerGas() { * * @return the quantity of Wei for fee cap. */ - @Unstable default Optional getMaxFeePerGas() { return Optional.empty(); } /** - * A scalar value equal to the max number of Wei to be paid for data gas, as specified in + * A scalar value equal to the max number of Wei to be paid for blob gas, as specified in * EIP-4844. * - * @return the quantity of Wei for fee per data gas. + * @return the quantity of Wei for fee per blob gas. */ - @Unstable - default Optional getMaxFeePerDataGas() { + default Optional getMaxFeePerBlobGas() { return Optional.empty(); } @@ -190,6 +182,5 @@ default Optional getMaxFeePerDataGas() { * * @return the type of the transaction */ - @Unstable TransactionType getType(); } diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionType.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/TransactionType.java similarity index 94% rename from plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionType.java rename to datatypes/src/main/java/org/hyperledger/besu/datatypes/TransactionType.java index 10b8a2a4cc0..b100240058c 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionType.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/TransactionType.java @@ -12,7 +12,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.hyperledger.besu.plugin.data; +package org.hyperledger.besu.datatypes; import java.util.Arrays; import java.util.EnumSet; @@ -69,7 +69,10 @@ public int compareTo(final Byte b) { public static TransactionType of(final int serializedTypeValue) { return Arrays.stream( new TransactionType[] { - TransactionType.FRONTIER, TransactionType.ACCESS_LIST, TransactionType.EIP1559 + TransactionType.FRONTIER, + TransactionType.ACCESS_LIST, + TransactionType.EIP1559, + TransactionType.BLOB }) .filter(transactionType -> transactionType.typeValue == serializedTypeValue) .findFirst() diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/VersionedHash.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/VersionedHash.java new file mode 100644 index 00000000000..21f296e0ae1 --- /dev/null +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/VersionedHash.java @@ -0,0 +1,123 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hyperledger.besu.datatypes; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; + +/** + * A VersionedHash is a Hash that forfeits its most significant byte to indicate the hashing + * algorithm which was used. + */ +public class VersionedHash { + + /** + * The versionedHash value. The first byte is the version id, the remainder is the subsequent + * bytes of the hash. + */ + Bytes32 hashish; + + /** The version id for sha256 hashes. */ + public static final byte SHA256_VERSION_ID = 1; + + /** A default versioned hash, nonsensical but valid. */ + public static final VersionedHash DEFAULT_VERSIONED_HASH = + new VersionedHash(SHA256_VERSION_ID, Hash.ZERO); + + /** + * Construct a VersionedHash from a Bytes32 value. + * + * @param versionId The version id of the hash. 01 for sha256. + * @param hash The hash value being versioned. + */ + public VersionedHash(final byte versionId, final Hash hash) { + if (versionId != SHA256_VERSION_ID) { + throw new IllegalArgumentException("Only supported hash version is 0x01, sha256 hash."); + } + this.hashish = + Bytes32.wrap( + Bytes.concatenate(Bytes.of(SHA256_VERSION_ID), hash.slice(1, hash.size() - 1))); + } + + /** + * Parse a VersionedHash from a Bytes32 value. + * + * @param typedHash raw versioned hash bytes to parse. + */ + public VersionedHash(final Bytes32 typedHash) { + byte versionId = typedHash.get(0); + if (versionId != SHA256_VERSION_ID) { + throw new IllegalArgumentException("Only supported hash version is 0x01, sha256 hash."); + } + this.hashish = typedHash; + } + + /** + * Parse a hexadecimal string representing a versioned hash value. + * + * @param str A hexadecimal string (with or without the leading '0x') representing a valid hash + * value. + * @return The parsed hash. + * @throws NullPointerException if the provided string is {@code null}. + * @throws IllegalArgumentException if the string is either not hexadecimal, or not the valid + * representation of a versioned hash (not 32 bytes or bad version). + */ + @JsonCreator + public static VersionedHash fromHexString(final String str) { + return new VersionedHash(Bytes32.fromHexString(str)); + } + + /** + * Convert it to raw bytes. + * + * @return The hash value. + */ + public Bytes32 toBytes() { + return this.hashish; + } + + /** + * The version id of the hash. + * + * @return the version id. + */ + public byte getVersionId() { + return this.hashish.get(0); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + VersionedHash that = (VersionedHash) o; + return getVersionId() == that.getVersionId() && Objects.equals(this.toBytes(), that.toBytes()); + } + + @Override + public int hashCode() { + return Objects.hash(getVersionId(), hashish); + } + + @JsonValue + @Override + public String toString() { + return this.toBytes().toHexString(); + } +} diff --git a/datatypes/src/test/java/org/hyperledger/besu/datatypes/BlobsWithCommitmentsTest.java b/datatypes/src/test/java/org/hyperledger/besu/datatypes/BlobsWithCommitmentsTest.java new file mode 100644 index 00000000000..fa5d3066d42 --- /dev/null +++ b/datatypes/src/test/java/org/hyperledger/besu/datatypes/BlobsWithCommitmentsTest.java @@ -0,0 +1,40 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hyperledger.besu.datatypes; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.security.InvalidParameterException; +import java.util.List; + +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.Test; + +public class BlobsWithCommitmentsTest { + @Test + public void blobsWithCommitmentsMustHaveSameNumberOfElements() { + String actualMessage = + assertThrows( + InvalidParameterException.class, + () -> + new BlobsWithCommitments( + List.of(new KZGCommitment(Bytes.of(1))), List.of(), List.of(), List.of())) + .getMessage(); + final String expectedMessage = "There must be an equal number of blobs, commitments and proofs"; + assertThat(actualMessage).isEqualTo(expectedMessage); + } +} diff --git a/datatypes/src/test/java/org/hyperledger/besu/datatypes/VersionedHashTest.java b/datatypes/src/test/java/org/hyperledger/besu/datatypes/VersionedHashTest.java new file mode 100644 index 00000000000..ce3b264b3b8 --- /dev/null +++ b/datatypes/src/test/java/org/hyperledger/besu/datatypes/VersionedHashTest.java @@ -0,0 +1,34 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hyperledger.besu.datatypes; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.apache.tuweni.bytes.Bytes32; +import org.junit.jupiter.api.Test; + +class VersionedHashTest { + + @Test + public void throwsOnUnsupportedHashType() { + assertThrows(IllegalArgumentException.class, () -> new VersionedHash((byte) 0, Hash.ZERO)); + } + + @Test + public void throwsOnParsingUnsupportedHashType() { + assertThrows(IllegalArgumentException.class, () -> new VersionedHash(Bytes32.ZERO)); + } +} diff --git a/enclave/build.gradle b/enclave/build.gradle index 103d7f1ab1f..25aeb466d77 100644 --- a/enclave/build.gradle +++ b/enclave/build.gradle @@ -7,7 +7,7 @@ dependencies { implementation 'com.google.guava:guava' implementation 'io.vertx:vertx-core' implementation 'io.vertx:vertx-web' - implementation 'org.apache.tuweni:tuweni-net' + implementation 'io.tmio:tuweni-net' runtimeOnly('org.bouncycastle:bcpkix-jdk18on') diff --git a/ethereum/api/build.gradle b/ethereum/api/build.gradle index 922dfd0ee6b..d6c230ae018 100644 --- a/ethereum/api/build.gradle +++ b/ethereum/api/build.gradle @@ -64,14 +64,20 @@ dependencies { implementation 'io.vertx:vertx-web' implementation 'io.vertx:vertx-codegen' implementation 'com.fasterxml.jackson.core:jackson-databind' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-net' - implementation 'org.apache.tuweni:tuweni-toml' - implementation 'org.apache.tuweni:tuweni-units' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-net' + implementation 'io.tmio:tuweni-toml' + implementation 'io.tmio:tuweni-units' implementation 'org.antlr:antlr4-runtime' implementation 'org.bouncycastle:bcprov-jdk18on' implementation 'org.springframework.security:spring-security-crypto' implementation 'org.xerial.snappy:snappy-java' + implementation 'com.google.guava:guava' + implementation 'io.vertx:vertx-core' + implementation 'com.fasterxml.jackson.core:jackson-databind' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-units' + implementation 'org.web3j:abi' annotationProcessor "org.immutables:value" implementation "org.immutables:value-annotations" @@ -93,19 +99,14 @@ dependencies { testImplementation 'com.squareup.okhttp3:okhttp' testImplementation 'io.vertx:vertx-auth-jwt' testImplementation 'io.vertx:vertx-junit5' - testImplementation 'io.vertx:vertx-unit' testImplementation 'io.vertx:vertx-web-client' - testImplementation 'junit:junit' testImplementation 'org.apache.logging.log4j:log4j-core' testImplementation 'org.assertj:assertj-core' testImplementation 'org.junit.jupiter:junit-jupiter' - testImplementation 'org.junit.jupiter:junit-jupiter-params' - testImplementation 'org.junit.platform:junit-platform-runner' + testImplementation 'org.mockito:mockito-core' testImplementation 'org.mockito:mockito-junit-jupiter' - testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' - testSupportImplementation 'org.bouncycastle:bcpkix-jdk18on' integrationTestImplementation project(':config') @@ -115,7 +116,7 @@ dependencies { integrationTestImplementation project(':testutil') integrationTestImplementation 'org.assertj:assertj-core' - integrationTestImplementation 'org.junit.jupiter:junit-jupiter-api' + integrationTestImplementation 'org.junit.jupiter:junit-jupiter' integrationTestImplementation 'org.mockito:mockito-core' integrationTestImplementation 'org.mockito:mockito-junit-jupiter' integrationTestImplementation 'org.testcontainers:testcontainers' diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java index bd70d2af19f..1527de48d50 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java @@ -38,6 +38,7 @@ import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; @@ -52,7 +53,6 @@ import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; import org.hyperledger.besu.evm.log.LogsBloomFilter; -import org.hyperledger.besu.plugin.data.TransactionType; import java.math.BigInteger; import java.util.ArrayList; @@ -127,7 +127,8 @@ public JsonRpcResponse response( mixHash, nonce, withdrawalsRoot, - null, // ToDo 4844: set with the value of excess_data_gas field + null, // ToDo 4844: set with the value of blob_gas_used field + null, // ToDo 4844: set with the value of excess_blob_gas field depositsRoot, blockHeaderFunctions); @@ -194,7 +195,6 @@ public TransactionResult transaction( .byteValueExact())) .payload(bytes(input)) .sender(address(fromAddress)) - .v(bigInteger(v)) .build(); return new TransactionCompleteResult( @@ -224,10 +224,6 @@ private String removeHexPrefix(final String prefixedHex) { return prefixedHex.startsWith("0x") ? prefixedHex.substring(2) : prefixedHex; } - private BigInteger bigInteger(final String hex) { - return hex == null ? null : new BigInteger(removeHexPrefix(hex), HEX_RADIX); - } - private Wei wei(final String hex) { return Wei.fromHexString(hex); } diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthCallIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthCallIntegrationTest.java index d6559ce893c..fd7145214ba 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthCallIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthCallIntegrationTest.java @@ -24,10 +24,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.testutil.BlockTestUtil; import java.util.Map; @@ -151,7 +151,7 @@ public void shouldReturnErrorWithGasLimitTooLow() { null); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.INTRINSIC_GAS_EXCEEDS_LIMIT); + new JsonRpcErrorResponse(null, RpcErrorType.INTRINSIC_GAS_EXCEEDS_LIMIT); final JsonRpcResponse response = method.response(request); @@ -174,7 +174,7 @@ public void shouldReturnErrorWithGasPriceTooHighAndStrict() { null); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE); + new JsonRpcErrorResponse(null, RpcErrorType.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE); final JsonRpcResponse response = method.response(request); @@ -221,7 +221,7 @@ public void shouldReturnErrorWithGasPriceTooHigh() { null); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE); + new JsonRpcErrorResponse(null, RpcErrorType.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE); final JsonRpcResponse response = method.response(request); @@ -268,7 +268,7 @@ public void shouldReturnErrorWithGasPriceAndEmptyBalance() { null); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE); + new JsonRpcErrorResponse(null, RpcErrorType.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE); final JsonRpcResponse response = method.response(request); diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthEstimateGasIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthEstimateGasIntegrationTest.java index e4e86573bc6..9e589a9ebca 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthEstimateGasIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthEstimateGasIntegrationTest.java @@ -24,10 +24,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.testutil.BlockTestUtil; import java.util.Map; @@ -158,7 +158,7 @@ public void shouldNotIgnoreSenderBalanceAccountWhenStrictModeDisabledAndThrowErr null); final JsonRpcRequestContext request = requestWithParams(callParameter); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE); + new JsonRpcErrorResponse(null, RpcErrorType.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE); final JsonRpcResponse response = method.response(request); assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse); diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetBlockByHashIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetBlockByHashIntegrationTest.java index 84c0983e4be..ad69d0f15a7 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetBlockByHashIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetBlockByHashIntegrationTest.java @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.ethereum.api.jsonrpc.BlockchainImporter; import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseKey; import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseUtils; @@ -27,7 +28,6 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionResult; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.testutil.BlockTestUtil; import java.util.EnumMap; diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetBlockByNumberIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetBlockByNumberIntegrationTest.java index 9943d0988f2..a7c3aa254ea 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetBlockByNumberIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetBlockByNumberIntegrationTest.java @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.ethereum.api.jsonrpc.BlockchainImporter; import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseKey; import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseUtils; @@ -27,7 +28,6 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionResult; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.testutil.BlockTestUtil; import java.util.EnumMap; diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetFilterChangesIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetFilterChangesIntegrationTest.java index fbec4e7c6c6..012c4bcc05b 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetFilterChangesIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetFilterChangesIntegrationTest.java @@ -24,6 +24,7 @@ import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; @@ -31,10 +32,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManagerBuilder; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetFilterChanges; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Block; @@ -56,7 +57,6 @@ import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics; import org.hyperledger.besu.ethereum.eth.transactions.sorter.GasPricePendingTransactionsSorter; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.testutil.TestClock; @@ -136,7 +136,7 @@ public void setUp() { public void shouldReturnErrorResponseIfFilterNotFound() { final JsonRpcRequestContext request = requestWithParams("0"); - final JsonRpcResponse expected = new JsonRpcErrorResponse(null, JsonRpcError.FILTER_NOT_FOUND); + final JsonRpcResponse expected = new JsonRpcErrorResponse(null, RpcErrorType.FILTER_NOT_FOUND); final JsonRpcResponse actual = method.response(request); assertThat(actual).usingRecursiveComparison().isEqualTo(expected); @@ -260,8 +260,8 @@ private boolean filterExists(final String filterId) { return true; } else { assertThat(response).isInstanceOf(JsonRpcErrorResponse.class); - assertThat(((JsonRpcErrorResponse) response).getError()) - .isEqualTo(JsonRpcError.FILTER_NOT_FOUND); + assertThat(((JsonRpcErrorResponse) response).getErrorType()) + .isEqualTo(RpcErrorType.FILTER_NOT_FOUND); return false; } } diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthCallIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthCallIntegrationTest.java index 05698c199f6..170fc38b0ed 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthCallIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthCallIntegrationTest.java @@ -24,10 +24,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.testutil.BlockTestUtil; import java.util.Map; @@ -101,7 +101,7 @@ public void shouldReturnErrorWithGasPriceTooHigh() { null); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE); + new JsonRpcErrorResponse(null, RpcErrorType.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE); final JsonRpcResponse response = method.response(request); @@ -148,7 +148,7 @@ public void shouldReturnErrorWithGasPriceLessThanCurrentBaseFee() { null); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.GAS_PRICE_BELOW_CURRENT_BASE_FEE); + new JsonRpcErrorResponse(null, RpcErrorType.GAS_PRICE_BELOW_CURRENT_BASE_FEE); final JsonRpcResponse response = method.response(request); @@ -219,7 +219,7 @@ public void shouldReturnErrorWithValidMaxFeePerGasLessThanCurrentBaseFee() { null); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.GAS_PRICE_BELOW_CURRENT_BASE_FEE); + new JsonRpcErrorResponse(null, RpcErrorType.GAS_PRICE_BELOW_CURRENT_BASE_FEE); final JsonRpcResponse response = method.response(request); @@ -243,7 +243,7 @@ public void shouldReturnErrorWithValidMaxFeePerGasLessThanMaxPriorityFeePerGas() final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( - null, JsonRpcError.MAX_PRIORITY_FEE_PER_GAS_EXCEEDS_MAX_FEE_PER_GAS); + null, RpcErrorType.MAX_PRIORITY_FEE_PER_GAS_EXCEEDS_MAX_FEE_PER_GAS); final JsonRpcResponse response = method.response(request); @@ -266,7 +266,7 @@ public void shouldReturnErrorWithMaxFeePerGasAndEmptyBalance() { null); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE); + new JsonRpcErrorResponse(null, RpcErrorType.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE); final JsonRpcResponse response = method.response(request); diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthGetFilterChangesIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthGetFilterChangesIntegrationTest.java index 7e7db55e02b..d4d47d9356e 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthGetFilterChangesIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthGetFilterChangesIntegrationTest.java @@ -24,6 +24,7 @@ import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; @@ -31,10 +32,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManagerBuilder; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetFilterChanges; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Block; @@ -56,7 +57,6 @@ import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics; import org.hyperledger.besu.ethereum.eth.transactions.sorter.BaseFeePendingTransactionsSorter; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.testutil.TestClock; @@ -136,7 +136,7 @@ public void setUp() { public void shouldReturnErrorResponseIfFilterNotFound() { final JsonRpcRequestContext request = requestWithParams("0"); - final JsonRpcResponse expected = new JsonRpcErrorResponse(null, JsonRpcError.FILTER_NOT_FOUND); + final JsonRpcResponse expected = new JsonRpcErrorResponse(null, RpcErrorType.FILTER_NOT_FOUND); final JsonRpcResponse actual = method.response(request); assertThat(actual).usingRecursiveComparison().isEqualTo(expected); @@ -260,8 +260,8 @@ private boolean filterExists(final String filterId) { return true; } else { assertThat(response).isInstanceOf(JsonRpcErrorResponse.class); - assertThat(((JsonRpcErrorResponse) response).getError()) - .isEqualTo(JsonRpcError.FILTER_NOT_FOUND); + assertThat(((JsonRpcErrorResponse) response).getErrorType()) + .isEqualTo(RpcErrorType.FILTER_NOT_FOUND); return false; } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetchers.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetchers.java index 6009b4bf21d..fccb0cb0110 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetchers.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetchers.java @@ -113,7 +113,7 @@ DataFetcher> getPendingStateDataFetcher() { return dataFetchingEnvironment -> { final TransactionPool txPool = dataFetchingEnvironment.getGraphQlContext().get(GraphQLContextType.TRANSACTION_POOL); - return Optional.of(new PendingStateAdapter(txPool.getPendingTransactions())); + return Optional.of(new PendingStateAdapter(txPool)); }; } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/PendingStateAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/PendingStateAdapter.java index d6eb3ae64d6..b070b5d6b93 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/PendingStateAdapter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/PendingStateAdapter.java @@ -20,7 +20,7 @@ import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ImmutableTransactionValidationParams; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams; @@ -39,18 +39,18 @@ @SuppressWarnings("unused") // reflected by GraphQL public class PendingStateAdapter extends AdapterBase { - private final PendingTransactions pendingTransactions; + private final TransactionPool transactionPool; - public PendingStateAdapter(final PendingTransactions pendingTransactions) { - this.pendingTransactions = pendingTransactions; + public PendingStateAdapter(final TransactionPool transactionPool) { + this.transactionPool = transactionPool; } public Integer getTransactionCount() { - return pendingTransactions.size(); + return transactionPool.count(); } public List getTransactions() { - return pendingTransactions.getPendingTransactions().stream() + return transactionPool.getPendingTransactions().stream() .map(PendingTransaction::getTransaction) .map(TransactionWithMetadata::new) .map(TransactionAdapter::new) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java index 49c1da5da65..db849fdeb5e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java @@ -17,12 +17,14 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.api.graphql.GraphQLContextType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata; import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import java.util.ArrayList; @@ -46,12 +48,15 @@ private Optional getReceipt( final DataFetchingEnvironment environment) { if (transactionReceiptWithMetadata == null) { final BlockchainQueries query = getBlockchainQueries(environment); + final ProtocolSchedule protocolSchedule = + environment.getGraphQlContext().get(GraphQLContextType.PROTOCOL_SCHEDULE); + final Transaction transaction = transactionWithMetadata.getTransaction(); if (transaction == null) { transactionReceiptWithMetadata = Optional.empty(); } else { transactionReceiptWithMetadata = - query.transactionReceiptByTransactionHash(transaction.getHash()); + query.transactionReceiptByTransactionHash(transaction.getHash(), protocolSchedule); } } return transactionReceiptWithMetadata; @@ -187,6 +192,9 @@ public Optional getCreatedContract(final DataFetchingEnvironment public List getLogs(final DataFetchingEnvironment environment) { final BlockchainQueries query = getBlockchainQueries(environment); + final ProtocolSchedule protocolSchedule = + environment.getGraphQlContext().get(GraphQLContextType.PROTOCOL_SCHEDULE); + final Hash hash = transactionWithMetadata.getTransaction().getHash(); final Optional maybeBlockHeader = @@ -201,7 +209,7 @@ public List getLogs(final DataFetchingEnvironment environment) { } final Optional maybeTransactionReceiptWithMetadata = - query.transactionReceiptByTransactionHash(hash); + query.transactionReceiptByTransactionHash(hash, protocolSchedule); final List results = new ArrayList<>(); if (maybeTransactionReceiptWithMetadata.isPresent()) { final List logs = diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/AbstractJsonRpcExecutor.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/AbstractJsonRpcExecutor.java index 3967c5250fe..95dc88f6a5d 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/AbstractJsonRpcExecutor.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/AbstractJsonRpcExecutor.java @@ -20,9 +20,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.context.ContextKey; import org.hyperledger.besu.ethereum.api.jsonrpc.execution.JsonRpcExecutor; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import java.io.IOException; import java.util.Optional; @@ -94,7 +94,7 @@ protected static JsonRpcResponse executeRequest( } protected static void handleJsonRpcError( - final RoutingContext routingContext, final Object id, final JsonRpcError error) { + final RoutingContext routingContext, final Object id, final RpcErrorType error) { final HttpServerResponse response = routingContext.response(); if (!response.closed()) { response @@ -103,7 +103,7 @@ protected static void handleJsonRpcError( } } - private static HttpResponseStatus statusCodeFromError(final JsonRpcError error) { + private static HttpResponseStatus statusCodeFromError(final RpcErrorType error) { return switch (error) { case INVALID_REQUEST, PARSE_ERROR -> HttpResponseStatus.BAD_REQUEST; default -> HttpResponseStatus.OK; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/AuthenticationHandler.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/AuthenticationHandler.java index fe2b7ebb084..90962e1171a 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/AuthenticationHandler.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/AuthenticationHandler.java @@ -17,8 +17,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.authentication.AuthenticationService; import org.hyperledger.besu.ethereum.api.jsonrpc.authentication.AuthenticationUtils; import org.hyperledger.besu.ethereum.api.jsonrpc.context.ContextKey; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import java.util.Collection; @@ -58,7 +58,7 @@ private static void handleJsonRpcUnauthorizedError(final RoutingContext routingC if (!response.closed()) { response .setStatusCode(HttpResponseStatus.UNAUTHORIZED.code()) - .end(Json.encode(new JsonRpcErrorResponse(null, JsonRpcError.UNAUTHORIZED))); + .end(Json.encode(new JsonRpcErrorResponse(null, RpcErrorType.UNAUTHORIZED))); } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcArrayExecutor.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcArrayExecutor.java index a45ad2a3dc3..5a839d8ad07 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcArrayExecutor.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcArrayExecutor.java @@ -14,16 +14,16 @@ */ package org.hyperledger.besu.ethereum.api.handlers; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INVALID_REQUEST; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INVALID_REQUEST; import org.hyperledger.besu.ethereum.api.jsonrpc.JsonResponseStreamer; import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration; import org.hyperledger.besu.ethereum.api.jsonrpc.context.ContextKey; import org.hyperledger.besu.ethereum.api.jsonrpc.execution.JsonRpcExecutor; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponseType; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import java.io.IOException; @@ -58,7 +58,7 @@ void execute() throws IOException { executeRpcRequestBatch(batchJsonRequest, streamer); } } else { - handleJsonRpcError(ctx, null, JsonRpcError.EXCEEDS_RPC_MAX_BATCH_SIZE); + handleJsonRpcError(ctx, null, RpcErrorType.EXCEEDS_RPC_MAX_BATCH_SIZE); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcExecutorHandler.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcExecutorHandler.java index 3d95f15245a..5e4c4af9c40 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcExecutorHandler.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcExecutorHandler.java @@ -19,7 +19,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration; import org.hyperledger.besu.ethereum.api.jsonrpc.context.ContextKey; import org.hyperledger.besu.ethereum.api.jsonrpc.execution.JsonRpcExecutor; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import java.io.IOException; import java.util.Optional; @@ -61,9 +61,9 @@ public static Handler handler( throw new RuntimeException(e); } }, - () -> handleJsonRpcError(ctx, null, JsonRpcError.PARSE_ERROR)); + () -> handleJsonRpcError(ctx, null, RpcErrorType.PARSE_ERROR)); } catch (final RuntimeException e) { - handleJsonRpcError(ctx, null, JsonRpcError.INTERNAL_ERROR); + handleJsonRpcError(ctx, null, RpcErrorType.INTERNAL_ERROR); } }; } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcObjectExecutor.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcObjectExecutor.java index 2380dcca3bd..d2a2cb37428 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcObjectExecutor.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcObjectExecutor.java @@ -20,10 +20,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration; import org.hyperledger.besu.ethereum.api.jsonrpc.context.ContextKey; import org.hyperledger.besu.ethereum.api.jsonrpc.execution.JsonRpcExecutor; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponseType; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import java.io.IOException; @@ -36,7 +36,7 @@ import io.vertx.ext.web.RoutingContext; public class JsonRpcObjectExecutor extends AbstractJsonRpcExecutor { - private static final ObjectWriter jsonObjectWriter = createObjectWriter(); + private final ObjectWriter jsonObjectWriter = createObjectWriter(); public JsonRpcObjectExecutor( final JsonRpcExecutor jsonRpcExecutor, @@ -64,7 +64,7 @@ String getRpcMethodName(final RoutingContext ctx) { return jsonObject.getString("method"); } - private static void handleJsonObjectResponse( + private void handleJsonObjectResponse( final HttpServerResponse response, final JsonRpcResponse jsonRpcResponse, final RoutingContext ctx) @@ -85,19 +85,22 @@ private static void handleJsonObjectResponse( private static HttpResponseStatus status(final JsonRpcResponse response) { return switch (response.getType()) { case UNAUTHORIZED -> HttpResponseStatus.UNAUTHORIZED; - case ERROR -> statusCodeFromError(((JsonRpcErrorResponse) response).getError()); + case ERROR -> statusCodeFromError(((JsonRpcErrorResponse) response).getErrorType()); default -> HttpResponseStatus.OK; }; } - private static ObjectWriter createObjectWriter() { - return getJsonObjectMapper() - .writerWithDefaultPrettyPrinter() + private ObjectWriter createObjectWriter() { + ObjectWriter writer = + jsonRpcConfiguration.isPrettyJsonEnabled() + ? getJsonObjectMapper().writerWithDefaultPrettyPrinter() + : getJsonObjectMapper().writer(); + return writer .without(JsonGenerator.Feature.FLUSH_PASSED_TO_STREAM) .with(JsonGenerator.Feature.AUTO_CLOSE_TARGET); } - private static HttpResponseStatus statusCodeFromError(final JsonRpcError error) { + private static HttpResponseStatus statusCodeFromError(final RpcErrorType error) { return switch (error) { case INVALID_REQUEST, PARSE_ERROR -> HttpResponseStatus.BAD_REQUEST; default -> HttpResponseStatus.OK; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcParserHandler.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcParserHandler.java index 6a3cef11ca2..b7911176aa2 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcParserHandler.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcParserHandler.java @@ -15,8 +15,8 @@ package org.hyperledger.besu.ethereum.api.handlers; import org.hyperledger.besu.ethereum.api.jsonrpc.context.ContextKey; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import io.netty.handler.codec.http.HttpResponseStatus; import io.vertx.core.Handler; @@ -34,7 +34,7 @@ public static Handler handler() { return ctx -> { final HttpServerResponse response = ctx.response(); if (ctx.getBody() == null) { - errorResponse(response, JsonRpcError.PARSE_ERROR); + errorResponse(response, RpcErrorType.PARSE_ERROR); } else { try { ctx.put(ContextKey.REQUEST_BODY_AS_JSON_OBJECT.name(), ctx.getBodyAsJson()); @@ -42,13 +42,13 @@ public static Handler handler() { try { final JsonArray batchRequest = ctx.getBodyAsJsonArray(); if (batchRequest.isEmpty()) { - errorResponse(response, JsonRpcError.INVALID_REQUEST); + errorResponse(response, RpcErrorType.INVALID_REQUEST); return; } else { ctx.put(ContextKey.REQUEST_BODY_AS_JSON_ARRAY.name(), batchRequest); } } catch (DecodeException | ClassCastException jsonArrayDecodeException) { - errorResponse(response, JsonRpcError.PARSE_ERROR); + errorResponse(response, RpcErrorType.PARSE_ERROR); return; } } @@ -58,7 +58,7 @@ public static Handler handler() { } private static void errorResponse( - final HttpServerResponse response, final JsonRpcError rpcError) { + final HttpServerResponse response, final RpcErrorType rpcError) { if (!response.closed()) { response .setStatusCode(HttpResponseStatus.BAD_REQUEST.code()) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcConfiguration.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcConfiguration.java index cb77d9ce818..2ed9c56d540 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcConfiguration.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcConfiguration.java @@ -38,6 +38,7 @@ public class JsonRpcConfiguration { public static final int DEFAULT_MAX_ACTIVE_CONNECTIONS = 80; public static final int DEFAULT_MAX_BATCH_SIZE = 1024; public static final long DEFAULT_MAX_REQUEST_CONTENT_LENGTH = 5 * 1024 * 1024; // 5MB + public static final boolean DEFAULT_PRETTY_JSON_ENABLED = false; private boolean enabled; private int port; @@ -55,6 +56,7 @@ public class JsonRpcConfiguration { private int maxActiveConnections; private int maxBatchSize; private long maxRequestContentLength; + private boolean prettyJsonEnabled; public static JsonRpcConfiguration createDefault() { final JsonRpcConfiguration config = new JsonRpcConfiguration(); @@ -66,6 +68,7 @@ public static JsonRpcConfiguration createDefault() { config.setMaxActiveConnections(DEFAULT_MAX_ACTIVE_CONNECTIONS); config.setMaxBatchSize(DEFAULT_MAX_BATCH_SIZE); config.setMaxRequestContentLength(DEFAULT_MAX_REQUEST_CONTENT_LENGTH); + config.setPrettyJsonEnabled(DEFAULT_PRETTY_JSON_ENABLED); return config; } @@ -196,6 +199,14 @@ public void setHttpTimeoutSec(final long httpTimeoutSec) { this.httpTimeoutSec = httpTimeoutSec; } + public boolean isPrettyJsonEnabled() { + return prettyJsonEnabled; + } + + public void setPrettyJsonEnabled(final boolean prettyJsonEnabled) { + this.prettyJsonEnabled = prettyJsonEnabled; + } + @Override public String toString() { return MoreObjects.toStringHelper(this) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcEnclaveErrorConverter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcEnclaveErrorConverter.java index 5ee8d5fa29c..08873cd51c2 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcEnclaveErrorConverter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcEnclaveErrorConverter.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import java.util.Arrays; import java.util.List; @@ -22,17 +22,17 @@ public class JsonRpcEnclaveErrorConverter { - public static JsonRpcError convertEnclaveInvalidReason(final String reason) { + public static RpcErrorType convertEnclaveInvalidReason(final String reason) { - final List err = - Arrays.stream(JsonRpcError.values()) + final List err = + Arrays.stream(RpcErrorType.values()) .filter(e -> e.getMessage().equals(reason)) .collect(Collectors.toList()); if (err.size() == 1) { return err.get(0); } else { - return JsonRpcError.ENCLAVE_ERROR; + return RpcErrorType.ENCLAVE_ERROR; } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcErrorConverter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcErrorConverter.java index eae1ca83763..b27c84bf04e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcErrorConverter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcErrorConverter.java @@ -14,71 +14,71 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; public class JsonRpcErrorConverter { - public static JsonRpcError convertTransactionInvalidReason( + public static RpcErrorType convertTransactionInvalidReason( final TransactionInvalidReason reason) { switch (reason) { case NONCE_TOO_LOW: case PRIVATE_NONCE_TOO_LOW: - return JsonRpcError.NONCE_TOO_LOW; + return RpcErrorType.NONCE_TOO_LOW; case NONCE_TOO_HIGH: case PRIVATE_NONCE_TOO_HIGH: - return JsonRpcError.NONCE_TOO_HIGH; + return RpcErrorType.NONCE_TOO_HIGH; case INVALID_SIGNATURE: - return JsonRpcError.INVALID_TRANSACTION_SIGNATURE; + return RpcErrorType.INVALID_TRANSACTION_SIGNATURE; case INTRINSIC_GAS_EXCEEDS_GAS_LIMIT: - return JsonRpcError.INTRINSIC_GAS_EXCEEDS_LIMIT; + return RpcErrorType.INTRINSIC_GAS_EXCEEDS_LIMIT; case UPFRONT_COST_EXCEEDS_BALANCE: - return JsonRpcError.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE; + return RpcErrorType.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE; case EXCEEDS_BLOCK_GAS_LIMIT: - return JsonRpcError.EXCEEDS_BLOCK_GAS_LIMIT; + return RpcErrorType.EXCEEDS_BLOCK_GAS_LIMIT; case WRONG_CHAIN_ID: - return JsonRpcError.WRONG_CHAIN_ID; + return RpcErrorType.WRONG_CHAIN_ID; case REPLAY_PROTECTED_SIGNATURES_NOT_SUPPORTED: - return JsonRpcError.REPLAY_PROTECTED_SIGNATURES_NOT_SUPPORTED; + return RpcErrorType.REPLAY_PROTECTED_SIGNATURES_NOT_SUPPORTED; case REPLAY_PROTECTED_SIGNATURE_REQUIRED: - return JsonRpcError.REPLAY_PROTECTED_SIGNATURE_REQUIRED; + return RpcErrorType.REPLAY_PROTECTED_SIGNATURE_REQUIRED; case TX_SENDER_NOT_AUTHORIZED: - return JsonRpcError.TX_SENDER_NOT_AUTHORIZED; + return RpcErrorType.TX_SENDER_NOT_AUTHORIZED; // Private Transaction Invalid Reasons case PRIVATE_TRANSACTION_INVALID: - return JsonRpcError.PRIVATE_TRANSACTION_INVALID; + return RpcErrorType.PRIVATE_TRANSACTION_INVALID; case PRIVATE_TRANSACTION_FAILED: - return JsonRpcError.PRIVATE_TRANSACTION_FAILED; + return RpcErrorType.PRIVATE_TRANSACTION_FAILED; case PRIVATE_UNIMPLEMENTED_TRANSACTION_TYPE: - return JsonRpcError.UNSUPPORTED_PRIVATE_TRANSACTION_TYPE; + return RpcErrorType.UNSUPPORTED_PRIVATE_TRANSACTION_TYPE; case CHAIN_HEAD_WORLD_STATE_NOT_AVAILABLE: - return JsonRpcError.CHAIN_HEAD_WORLD_STATE_NOT_AVAILABLE; + return RpcErrorType.CHAIN_HEAD_WORLD_STATE_NOT_AVAILABLE; case GAS_PRICE_TOO_LOW: - return JsonRpcError.GAS_PRICE_TOO_LOW; + return RpcErrorType.GAS_PRICE_TOO_LOW; case GAS_PRICE_BELOW_CURRENT_BASE_FEE: - return JsonRpcError.GAS_PRICE_BELOW_CURRENT_BASE_FEE; + return RpcErrorType.GAS_PRICE_BELOW_CURRENT_BASE_FEE; case TX_FEECAP_EXCEEDED: - return JsonRpcError.TX_FEECAP_EXCEEDED; + return RpcErrorType.TX_FEECAP_EXCEEDED; case MAX_PRIORITY_FEE_PER_GAS_EXCEEDS_MAX_FEE_PER_GAS: - return JsonRpcError.MAX_PRIORITY_FEE_PER_GAS_EXCEEDS_MAX_FEE_PER_GAS; + return RpcErrorType.MAX_PRIORITY_FEE_PER_GAS_EXCEEDS_MAX_FEE_PER_GAS; case OFFCHAIN_PRIVACY_GROUP_DOES_NOT_EXIST: - return JsonRpcError.OFFCHAIN_PRIVACY_GROUP_DOES_NOT_EXIST; + return RpcErrorType.OFFCHAIN_PRIVACY_GROUP_DOES_NOT_EXIST; case INVALID_TRANSACTION_FORMAT: - return JsonRpcError.INVALID_TRANSACTION_TYPE; + return RpcErrorType.INVALID_TRANSACTION_TYPE; case TRANSACTION_ALREADY_KNOWN: - return JsonRpcError.ETH_SEND_TX_ALREADY_KNOWN; + return RpcErrorType.ETH_SEND_TX_ALREADY_KNOWN; case TRANSACTION_REPLACEMENT_UNDERPRICED: - return JsonRpcError.ETH_SEND_TX_REPLACEMENT_UNDERPRICED; + return RpcErrorType.ETH_SEND_TX_REPLACEMENT_UNDERPRICED; case NONCE_TOO_FAR_IN_FUTURE_FOR_SENDER: - return JsonRpcError.NONCE_TOO_FAR_IN_FUTURE_FOR_SENDER; + return RpcErrorType.NONCE_TOO_FAR_IN_FUTURE_FOR_SENDER; case LOWER_NONCE_INVALID_TRANSACTION_EXISTS: - return JsonRpcError.LOWER_NONCE_INVALID_TRANSACTION_EXISTS; - case TOTAL_DATA_GAS_TOO_HIGH: - return JsonRpcError.TOTAL_DATA_GAS_TOO_HIGH; + return RpcErrorType.LOWER_NONCE_INVALID_TRANSACTION_EXISTS; + case TOTAL_BLOB_GAS_TOO_HIGH: + return RpcErrorType.TOTAL_BLOB_GAS_TOO_HIGH; case TX_POOL_DISABLED: - return JsonRpcError.TX_POOL_DISABLED; + return RpcErrorType.TX_POOL_DISABLED; default: - return JsonRpcError.INTERNAL_ERROR; + return RpcErrorType.INTERNAL_ERROR; } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/LatestNonceProvider.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/LatestNonceProvider.java index dae8662caa0..c84c303a473 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/LatestNonceProvider.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/LatestNonceProvider.java @@ -16,7 +16,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.util.NonceProvider; import java.util.OptionalLong; @@ -24,17 +24,17 @@ public class LatestNonceProvider implements NonceProvider { private final BlockchainQueries blockchainQueries; - private final PendingTransactions pendingTransactions; + private final TransactionPool transactionPool; public LatestNonceProvider( - final BlockchainQueries blockchainQueries, final PendingTransactions pendingTransactions) { + final BlockchainQueries blockchainQueries, final TransactionPool transactionPool) { this.blockchainQueries = blockchainQueries; - this.pendingTransactions = pendingTransactions; + this.transactionPool = transactionPool; } @Override public long getNonce(final Address address) { - final OptionalLong pendingNonce = pendingTransactions.getNextNonceForSender(address); + final OptionalLong pendingNonce = transactionPool.getNextNonceForSender(address); return pendingNonce.orElseGet( () -> blockchainQueries.getTransactionCount(address, blockchainQueries.headBlockNumber())); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java index 9c7871b6a27..5b510cb8e71 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java @@ -14,8 +14,8 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc; -import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; public enum RpcMethod { ADMIN_ADD_PEER("admin_addPeer"), @@ -52,8 +52,10 @@ public enum RpcMethod { DEBUG_GET_RAW_TRANSACTION("debug_getRawTransaction"), ENGINE_GET_PAYLOAD_V1("engine_getPayloadV1"), ENGINE_GET_PAYLOAD_V2("engine_getPayloadV2"), + ENGINE_GET_PAYLOAD_V3("engine_getPayloadV3"), ENGINE_NEW_PAYLOAD_V1("engine_newPayloadV1"), ENGINE_NEW_PAYLOAD_V2("engine_newPayloadV2"), + ENGINE_NEW_PAYLOAD_V3("engine_newPayloadV3"), ENGINE_FORKCHOICE_UPDATED_V1("engine_forkchoiceUpdatedV1"), ENGINE_FORKCHOICE_UPDATED_V2("engine_forkchoiceUpdatedV2"), ENGINE_EXCHANGE_TRANSITION_CONFIGURATION("engine_exchangeTransitionConfigurationV1"), @@ -190,7 +192,7 @@ public String getMethodName() { } static { - allMethodNames = new ArrayList<>(); + allMethodNames = new HashSet<>(); for (RpcMethod m : RpcMethod.values()) { allMethodNames.add(m.getMethodName()); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/AuthenticatedJsonRpcProcessor.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/AuthenticatedJsonRpcProcessor.java index 306d9d4552b..1d731fe2a08 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/AuthenticatedJsonRpcProcessor.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/AuthenticatedJsonRpcProcessor.java @@ -18,9 +18,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestId; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcUnauthorizedResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import java.util.Collection; @@ -50,6 +50,6 @@ public JsonRpcResponse process( if (authenticationService.isPermitted(request.getUser(), method, noAuthRpcApis)) { return rpcProcessor.process(id, method, metricSpan, request); } - return new JsonRpcUnauthorizedResponse(id, JsonRpcError.UNAUTHORIZED); + return new JsonRpcUnauthorizedResponse(id, RpcErrorType.UNAUTHORIZED); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/BaseJsonRpcProcessor.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/BaseJsonRpcProcessor.java index 25423f016fc..3d823886484 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/BaseJsonRpcProcessor.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/BaseJsonRpcProcessor.java @@ -18,10 +18,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestId; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcUnauthorizedResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.privacy.MultiTenancyValidationException; import io.opentelemetry.api.trace.Span; @@ -44,13 +44,13 @@ public JsonRpcResponse process( return method.response(request); } catch (final InvalidJsonRpcParameters e) { LOG.debug("Invalid Params for method: {}", method.getName(), e); - return new JsonRpcErrorResponse(id, JsonRpcError.INVALID_PARAMS); + return new JsonRpcErrorResponse(id, RpcErrorType.INVALID_PARAMS); } catch (final MultiTenancyValidationException e) { - return new JsonRpcUnauthorizedResponse(id, JsonRpcError.UNAUTHORIZED); + return new JsonRpcUnauthorizedResponse(id, RpcErrorType.UNAUTHORIZED); } catch (final RuntimeException e) { final JsonArray params = JsonObject.mapFrom(request.getRequest()).getJsonArray("params"); LOG.error(String.format("Error processing method: %s %s", method.getName(), params), e); - return new JsonRpcErrorResponse(id, JsonRpcError.INTERNAL_ERROR); + return new JsonRpcErrorResponse(id, RpcErrorType.INTERNAL_ERROR); } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/JsonRpcExecutor.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/JsonRpcExecutor.java index 8d088caec29..6fedcc70ca4 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/JsonRpcExecutor.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/JsonRpcExecutor.java @@ -14,17 +14,17 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.execution; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INVALID_REQUEST; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INVALID_REQUEST; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestId; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcNoResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import java.util.Map; import java.util.Optional; @@ -81,7 +81,7 @@ public JsonRpcResponse execute( } else { span = Span.getInvalid(); } - final Optional unavailableMethod = validateMethodAvailability(requestBody); + final Optional unavailableMethod = validateMethodAvailability(requestBody); if (unavailableMethod.isPresent()) { span.setStatus(StatusCode.ERROR, "method unavailable"); return new JsonRpcErrorResponse(id, unavailableMethod.get()); @@ -101,7 +101,7 @@ public JsonRpcResponse execute( } } - private Optional validateMethodAvailability(final JsonRpcRequest request) { + private Optional validateMethodAvailability(final JsonRpcRequest request) { final String name = request.getMethod(); if (LOG.isDebugEnabled()) { @@ -113,10 +113,10 @@ private Optional validateMethodAvailability(final JsonRpcRequest r if (method == null) { if (!RpcMethod.rpcMethodExists(name)) { - return Optional.of(JsonRpcError.METHOD_NOT_FOUND); + return Optional.of(RpcErrorType.METHOD_NOT_FOUND); } if (!rpcMethods.containsKey(name)) { - return Optional.of(JsonRpcError.METHOD_NOT_ENABLED); + return Optional.of(RpcErrorType.METHOD_NOT_ENABLED); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/TracedJsonRpcProcessor.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/TracedJsonRpcProcessor.java index 5ef2181e248..ecde766f8b3 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/TracedJsonRpcProcessor.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/TracedJsonRpcProcessor.java @@ -41,7 +41,7 @@ public JsonRpcResponse process( JsonRpcResponse jsonRpcResponse = rpcProcessor.process(id, method, metricSpan, request); if (JsonRpcResponseType.ERROR == jsonRpcResponse.getType()) { JsonRpcErrorResponse errorResponse = (JsonRpcErrorResponse) jsonRpcResponse; - switch (errorResponse.getError()) { + switch (errorResponse.getErrorType()) { case INVALID_PARAMS: metricSpan.setStatus(StatusCode.ERROR, "Invalid Params"); break; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/DebugReplayBlock.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/DebugReplayBlock.java index ab14cb9412c..fc8c3d0656e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/DebugReplayBlock.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/DebugReplayBlock.java @@ -14,8 +14,8 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INTERNAL_ERROR; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.UNKNOWN_BLOCK; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INTERNAL_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.UNKNOWN_BLOCK; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/JsonRpcRequest.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/JsonRpcRequest.java index a8d161f8992..db7fe131054 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/JsonRpcRequest.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/JsonRpcRequest.java @@ -18,6 +18,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; import java.util.Arrays; +import java.util.List; import java.util.Objects; import java.util.Optional; @@ -137,6 +138,10 @@ public Optional getOptionalParameter(final int index, final Class para return parameterAccessor.optional(params, index, paramClass); } + public Optional> getOptionalList(final int index, final Class paramClass) { + return parameterAccessor.optionalList(params, index, paramClass); + } + @Override public String toString() { return "JsonRpcRequest{" diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/JsonRpcRequestContext.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/JsonRpcRequestContext.java index d8e5bede312..b489259eb82 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/JsonRpcRequestContext.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/JsonRpcRequestContext.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal; +import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.function.Supplier; @@ -68,6 +69,10 @@ public Optional getOptionalParameter(final int index, final Class para return jsonRpcRequest.getOptionalParameter(index, paramClass); } + public Optional> getOptionalList(final int index, final Class listOf) { + return jsonRpcRequest.getOptionalList(index, listOf); + } + @Override public boolean equals(final Object o) { if (this == o) { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractBlockParameterMethod.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractBlockParameterMethod.java index e5340d5bf62..dd8256d8c80 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractBlockParameterMethod.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractBlockParameterMethod.java @@ -16,10 +16,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -77,7 +77,7 @@ private Object posRelatedResult( .map(header -> resultByBlockNumber(request, header.getNumber())) .orElseGet( () -> - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.UNKNOWN_BLOCK)); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.UNKNOWN_BLOCK)); } protected Object findResultByParamType(final JsonRpcRequestContext request) { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractBlockParameterOrBlockHashMethod.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractBlockParameterOrBlockHashMethod.java index ebb3cd2af61..8110bf6c2c4 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractBlockParameterOrBlockHashMethod.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractBlockParameterOrBlockHashMethod.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameterOrBlockHash; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -86,7 +86,7 @@ private Object posRelatedResult( .map(header -> resultByBlockHash(request, header.getBlockHash())) .orElseGet( () -> - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.UNKNOWN_BLOCK)); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.UNKNOWN_BLOCK)); } protected Object handleParamTypes(final JsonRpcRequestContext requestContext) { @@ -106,10 +106,10 @@ protected Object handleParamTypes(final JsonRpcRequestContext requestContext) { final OptionalLong blockNumber = blockParameterOrBlockHash.getNumber(); if (blockNumber.isEmpty() || blockNumber.getAsLong() < 0) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } else if (blockNumber.getAsLong() > getBlockchainQueries().headBlockNumber()) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.BLOCK_NOT_FOUND); + requestContext.getRequest().getId(), RpcErrorType.BLOCK_NOT_FOUND); } result = @@ -123,7 +123,7 @@ protected Object handleParamTypes(final JsonRpcRequestContext requestContext) { Optional blockHash = blockParameterOrBlockHash.getHash(); if (blockHash.isEmpty()) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } // return error if block hash does not find a block @@ -131,13 +131,13 @@ protected Object handleParamTypes(final JsonRpcRequestContext requestContext) { getBlockchainQueries().getBlockHeaderByHash(blockHash.get()); if (maybeBlockHeader.isEmpty()) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.BLOCK_NOT_FOUND); + requestContext.getRequest().getId(), RpcErrorType.BLOCK_NOT_FOUND); } if (Boolean.TRUE.equals(blockParameterOrBlockHash.getRequireCanonical()) && !getBlockchainQueries().blockIsOnCanonicalChain(blockHash.get())) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.JSON_RPC_NOT_CANONICAL_ERROR); + requestContext.getRequest().getId(), RpcErrorType.JSON_RPC_NOT_CANONICAL_ERROR); } result = resultByBlockHash(requestContext, blockHash.get()); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractEstimateGas.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractEstimateGas.java index c8308061e90..ddfd522c8f7 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractEstimateGas.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractEstimateGas.java @@ -21,6 +21,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; @@ -96,24 +97,29 @@ protected JsonCallParameter validateAndGetCallParams(final JsonRpcRequestContext protected JsonRpcErrorResponse errorResponse( final JsonRpcRequestContext request, final TransactionSimulatorResult result) { - final JsonRpcError jsonRpcError; final ValidationResult validationResult = result.getValidationResult(); if (validationResult != null && !validationResult.isValid()) { - jsonRpcError = + return errorResponse( + request, JsonRpcErrorConverter.convertTransactionInvalidReason( - validationResult.getInvalidReason()); + validationResult.getInvalidReason())); } else { final TransactionProcessingResult resultTrx = result.getResult(); if (resultTrx != null && resultTrx.getRevertReason().isPresent()) { - jsonRpcError = JsonRpcError.REVERT_ERROR; - jsonRpcError.setData(resultTrx.getRevertReason().get().toHexString()); - } else { - jsonRpcError = JsonRpcError.INTERNAL_ERROR; + return errorResponse( + request, + new JsonRpcError( + RpcErrorType.REVERT_ERROR, resultTrx.getRevertReason().get().toHexString())); } + return errorResponse(request, RpcErrorType.INTERNAL_ERROR); } - return errorResponse(request, jsonRpcError); + } + + protected JsonRpcErrorResponse errorResponse( + final JsonRpcRequestContext request, final RpcErrorType rpcErrorType) { + return errorResponse(request, new JsonRpcError(rpcErrorType)); } protected JsonRpcErrorResponse errorResponse( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminChangeLogLevel.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminChangeLogLevel.java index 8a6dc7168f4..45381303319 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminChangeLogLevel.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminChangeLogLevel.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.util.LogConfigurator; import java.util.Arrays; @@ -47,7 +47,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { final String logLevel = requestContext.getRequiredParameter(0, String.class); if (!VALID_PARAMS.contains(logLevel)) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } final Optional optionalLogFilters = requestContext.getOptionalParameter(1, String[].class); @@ -58,7 +58,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { return new JsonRpcSuccessResponse(requestContext.getRequest().getId()); } catch (InvalidJsonRpcParameters invalidJsonRpcParameters) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminLogsRemoveCache.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminLogsRemoveCache.java index 70a4c1db0f0..01cfb02a1e8 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminLogsRemoveCache.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminLogsRemoveCache.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.query.cache.TransactionLogBloomCacher; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -81,7 +81,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { if (stopBlock < startBlock) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } final TransactionLogBloomCacher transactionLogBloomCacher = diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminModifyPeer.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminModifyPeer.java index 8cb11b9dcb5..7ad3c9286b9 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminModifyPeer.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminModifyPeer.java @@ -16,9 +16,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork; import org.hyperledger.besu.ethereum.p2p.network.exceptions.P2PDisabledException; import org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration; @@ -40,35 +40,35 @@ protected AdminModifyPeer( public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { if (requestContext.getRequest().getParamLength() != 1) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } try { final String enodeString = requestContext.getRequiredParameter(0, String.class); return performOperation(requestContext.getRequest().getId(), enodeString); } catch (final InvalidJsonRpcParameters e) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } catch (final IllegalArgumentException e) { if (e.getMessage() .endsWith( "Invalid node ID: node ID must have exactly 128 hexadecimal characters and should not include any '0x' hex prefix.")) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ENODE_ID_INVALID); + requestContext.getRequest().getId(), RpcErrorType.ENODE_ID_INVALID); } else { if (e.getMessage().endsWith("Invalid ip address.")) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.DNS_NOT_ENABLED); + requestContext.getRequest().getId(), RpcErrorType.DNS_NOT_ENABLED); } else if (e.getMessage().endsWith("dns-update-enabled flag is false.")) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.CANT_RESOLVE_PEER_ENODE_DNS); + requestContext.getRequest().getId(), RpcErrorType.CANT_RESOLVE_PEER_ENODE_DNS); } else { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.PARSE_ERROR); + requestContext.getRequest().getId(), RpcErrorType.PARSE_ERROR); } } } catch (final P2PDisabledException e) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.P2P_DISABLED); + requestContext.getRequest().getId(), RpcErrorType.P2P_DISABLED); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminNodeInfo.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminNodeInfo.java index 21ffd34e1d1..8515f9ba1bb 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminNodeInfo.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminNodeInfo.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.ChainHead; import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork; @@ -75,12 +75,12 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { if (!peerNetwork.isP2pEnabled()) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.P2P_DISABLED); + requestContext.getRequest().getId(), RpcErrorType.P2P_DISABLED); } final Optional maybeEnode = peerNetwork.getLocalEnode(); if (maybeEnode.isEmpty()) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.P2P_NETWORK_NOT_RUNNING); + requestContext.getRequest().getId(), RpcErrorType.P2P_NETWORK_NOT_RUNNING); } final EnodeURL enode = maybeEnode.get(); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminPeers.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminPeers.java index f0762f211b7..0fc0a2d8fb6 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminPeers.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminPeers.java @@ -16,10 +16,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.PeerResult; import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.p2p.network.exceptions.P2PDisabledException; @@ -47,7 +47,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { ethPeers.streamAllPeers().map(PeerResult::fromEthPeer).collect(Collectors.toList())); } catch (P2PDisabledException e) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.P2P_DISABLED); + requestContext.getRequest().getId(), RpcErrorType.P2P_DISABLED); } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugAccountAt.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugAccountAt.java index a6cde35bb4a..89a897df37d 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugAccountAt.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugAccountAt.java @@ -23,8 +23,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTracer; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.Tracer; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.ImmutableDebugAccountAtResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; @@ -79,13 +79,13 @@ protected Object resultByBlockHash( blockchainQueries.get().blockByHash(blockHash); if (block.isEmpty()) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.BLOCK_NOT_FOUND); + requestContext.getRequest().getId(), RpcErrorType.BLOCK_NOT_FOUND); } List transactions = block.get().getTransactions(); if (transactions.isEmpty() || txIndex < 0 || txIndex > block.get().getTransactions().size()) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } return Tracer.processTracing( @@ -113,7 +113,7 @@ protected Object resultByBlockHash( if (transactionTrace.isEmpty()) { return Optional.of( new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.TRANSACTION_NOT_FOUND)); + requestContext.getRequest().getId(), RpcErrorType.TRANSACTION_NOT_FOUND)); } Optional account = @@ -125,7 +125,7 @@ protected Object resultByBlockHash( if (account.isEmpty()) { return Optional.of( new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.NO_ACCOUNT_FOUND)); + requestContext.getRequest().getId(), RpcErrorType.NO_ACCOUNT_FOUND)); } return Optional.of( @@ -137,7 +137,7 @@ protected Object resultByBlockHash( }) .orElse( new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.WORLD_STATE_UNAVAILABLE)); + requestContext.getRequest().getId(), RpcErrorType.WORLD_STATE_UNAVAILABLE)); } protected ImmutableDebugAccountAtResult debugAccountAtResult( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugGetRawBlock.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugGetRawBlock.java index 8af0812a299..0dc79dfd419 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugGetRawBlock.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugGetRawBlock.java @@ -17,8 +17,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.rlp.RLP; @@ -51,6 +51,6 @@ protected Object resultByBlockNumber( .orElseGet( () -> new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.BLOCK_NOT_FOUND)); + request.getRequest().getId(), RpcErrorType.BLOCK_NOT_FOUND)); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugGetRawHeader.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugGetRawHeader.java index 9fd1fe83bfe..cd283d67c81 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugGetRawHeader.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugGetRawHeader.java @@ -17,8 +17,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.rlp.RLP; @@ -50,6 +50,6 @@ protected Object resultByBlockNumber( .orElseGet( () -> new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.BLOCK_NOT_FOUND)); + request.getRequest().getId(), RpcErrorType.BLOCK_NOT_FOUND)); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugSetHead.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugSetHead.java index 7cf9526775f..b3d70344318 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugSetHead.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugSetHead.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.UNKNOWN_BLOCK; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.UNKNOWN_BLOCK; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.ProtocolContext; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStandardTraceBadBlockToFile.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStandardTraceBadBlockToFile.java index 65e486a9ca3..0c3299a8d68 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStandardTraceBadBlockToFile.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStandardTraceBadBlockToFile.java @@ -19,10 +19,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.TransactionTraceParams; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTracer; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -73,6 +73,6 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { traceBlock(block, transactionTraceParams))) .orElse( new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.BLOCK_NOT_FOUND)); + requestContext.getRequest().getId(), RpcErrorType.BLOCK_NOT_FOUND)); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStandardTraceBlockToFile.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStandardTraceBlockToFile.java index d9cab6769e4..306f4c449ed 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStandardTraceBlockToFile.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStandardTraceBlockToFile.java @@ -22,10 +22,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.TransactionTraceParams; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.Tracer; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTracer; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Block; @@ -75,7 +75,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { traceBlock(block, transactionTraceParams))) .orElse( new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.BLOCK_NOT_FOUND)); + requestContext.getRequest().getId(), RpcErrorType.BLOCK_NOT_FOUND)); } protected List traceBlock( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlock.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlock.java index 762728edbe4..270f176c7a8 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlock.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlock.java @@ -20,10 +20,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTrace; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTracer; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.Tracer; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.DebugTraceTransactionResult; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Block; @@ -71,7 +71,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { } catch (final RLPException e) { LOG.debug("Failed to parse block RLP", e); return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } final TraceOptions traceOptions = requestContext @@ -95,7 +95,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), results); } else { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.PARENT_BLOCK_NOT_FOUND); + requestContext.getRequest().getId(), RpcErrorType.PARENT_BLOCK_NOT_FOUND); } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java index 71737fbab9e..569563ca932 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java @@ -14,8 +14,8 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.BLOCK_NOT_FOUND; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INTERNAL_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.BLOCK_NOT_FOUND; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INTERNAL_ERROR; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; @@ -28,6 +28,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.mainnet.ImmutableTransactionValidationParams; @@ -92,8 +93,8 @@ protected Object resultByBlockHeader( result.getOutput().toString()) : errorResponse(request, result)), reason -> - new JsonRpcErrorResponse( - request.getRequest().getId(), + errorResponse( + request, JsonRpcErrorConverter.convertTransactionInvalidReason( reason)))), header) @@ -107,24 +108,24 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { private JsonRpcErrorResponse errorResponse( final JsonRpcRequestContext request, final TransactionSimulatorResult result) { - final JsonRpcError jsonRpcError; final ValidationResult validationResult = result.getValidationResult(); if (validationResult != null && !validationResult.isValid()) { - jsonRpcError = + return errorResponse( + request, JsonRpcErrorConverter.convertTransactionInvalidReason( - validationResult.getInvalidReason()); + validationResult.getInvalidReason())); } else { final TransactionProcessingResult resultTrx = result.getResult(); if (resultTrx != null && resultTrx.getRevertReason().isPresent()) { - jsonRpcError = JsonRpcError.REVERT_ERROR; - jsonRpcError.setData(resultTrx.getRevertReason().get().toHexString()); - } else { - jsonRpcError = JsonRpcError.INTERNAL_ERROR; + return errorResponse( + request, + new JsonRpcError( + RpcErrorType.REVERT_ERROR, resultTrx.getRevertReason().get().toHexString())); } + return errorResponse(request, RpcErrorType.INTERNAL_ERROR); } - return errorResponse(request, jsonRpcError); } private JsonRpcErrorResponse errorResponse( @@ -132,6 +133,11 @@ private JsonRpcErrorResponse errorResponse( return new JsonRpcErrorResponse(request.getRequest().getId(), jsonRpcError); } + private JsonRpcErrorResponse errorResponse( + final JsonRpcRequestContext request, final RpcErrorType rpcErrorType) { + return errorResponse(request, new JsonRpcError(rpcErrorType)); + } + private TransactionValidationParams buildTransactionValidationParams( final BlockHeader header, final JsonCallParameter callParams) { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCoinbase.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCoinbase.java index 3a2544e8c9a..0f92fa2b5b0 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCoinbase.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCoinbase.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; import java.util.Optional; @@ -46,6 +46,6 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { requestContext.getRequest().getId(), coinbase.get().toString()); } return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.COINBASE_NOT_SPECIFIED); + requestContext.getRequest().getId(), RpcErrorType.COINBASE_NOT_SPECIFIED); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCreateAccessList.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCreateAccessList.java index 8877d08653d..f4b4a150e69 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCreateAccessList.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCreateAccessList.java @@ -18,9 +18,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.CreateAccessListResult; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -53,7 +53,7 @@ public String getName() { public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { final JsonCallParameter jsonCallParameter = validateAndGetCallParams(requestContext); final BlockHeader blockHeader = blockHeader(); - final Optional jsonRpcError = validateBlockHeader(blockHeader); + final Optional jsonRpcError = validateBlockHeader(blockHeader); if (jsonRpcError.isPresent()) { return errorResponse(requestContext, jsonRpcError.get()); } @@ -70,14 +70,14 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { } } - private Optional validateBlockHeader(final BlockHeader blockHeader) { + private Optional validateBlockHeader(final BlockHeader blockHeader) { if (blockHeader == null) { - return Optional.of(JsonRpcError.INTERNAL_ERROR); + return Optional.of(RpcErrorType.INTERNAL_ERROR); } if (!blockchainQueries .getWorldStateArchive() .isWorldStateAvailable(blockHeader.getStateRoot(), blockHeader.getHash())) { - return Optional.of(JsonRpcError.WORLD_STATE_UNAVAILABLE); + return Optional.of(RpcErrorType.WORLD_STATE_UNAVAILABLE); } return Optional.empty(); } @@ -87,7 +87,7 @@ private JsonRpcResponse createResponse( return result .getResult() .map(createResponse(requestContext, result.getTracer())) - .orElse(errorResponse(requestContext, JsonRpcError.INTERNAL_ERROR)); + .orElse(errorResponse(requestContext, RpcErrorType.INTERNAL_ERROR)); } private TransactionValidationParams transactionValidationParams( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGas.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGas.java index b4b13dbf932..ea69ad9d381 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGas.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGas.java @@ -17,9 +17,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -50,12 +50,12 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { final BlockHeader blockHeader = blockHeader(); if (blockHeader == null) { - return errorResponse(requestContext, JsonRpcError.INTERNAL_ERROR); + return errorResponse(requestContext, RpcErrorType.INTERNAL_ERROR); } if (!blockchainQueries .getWorldStateArchive() .isWorldStateAvailable(blockHeader.getStateRoot(), blockHeader.getHash())) { - return errorResponse(requestContext, JsonRpcError.WORLD_STATE_UNAVAILABLE); + return errorResponse(requestContext, RpcErrorType.WORLD_STATE_UNAVAILABLE); } final CallParameter modifiedCallParams = @@ -70,7 +70,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { blockHeader, modifiedCallParams, operationTracer, isAllowExceedingBalance); if (gasUsed.isEmpty()) { - return errorResponse(requestContext, JsonRpcError.INTERNAL_ERROR); + return errorResponse(requestContext, RpcErrorType.INTERNAL_ERROR); } // if the transaction is invalid or doesn't have enough gas with the max it never will! diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthFeeHistory.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthFeeHistory.java index 45df084c74e..d505568bd4e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthFeeHistory.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthFeeHistory.java @@ -21,10 +21,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UnsignedIntParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.FeeHistory; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.ImmutableFeeHistory; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -69,7 +69,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext request) { final int blockCount = request.getRequiredParameter(0, UnsignedIntParameter.class).getValue(); if (blockCount < 1 || blockCount > 1024) { - return new JsonRpcErrorResponse(requestId, JsonRpcError.INVALID_PARAMS); + return new JsonRpcErrorResponse(requestId, RpcErrorType.INVALID_PARAMS); } final BlockParameter highestBlock = request.getRequiredParameter(1, BlockParameter.class); final Optional> maybeRewardPercentiles = @@ -84,7 +84,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext request) { chainHeadBlockNumber /* both latest and pending use the head block until we have pending block support */); if (resolvedHighestBlockNumber > chainHeadBlockNumber) { - return new JsonRpcErrorResponse(requestId, JsonRpcError.INVALID_PARAMS); + return new JsonRpcErrorResponse(requestId, RpcErrorType.INVALID_PARAMS); } final long oldestBlock = Math.max(0, resolvedHighestBlockNumber - (blockCount - 1)); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChanges.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChanges.java index 74a0fc91fa9..fa9031efe53 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChanges.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChanges.java @@ -18,10 +18,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult; import org.hyperledger.besu.ethereum.core.LogWithMetadata; @@ -66,6 +66,6 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { // Filter was not found. return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.FILTER_NOT_FOUND); + requestContext.getRequest().getId(), RpcErrorType.FILTER_NOT_FOUND); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogs.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogs.java index 462106fbd97..2e928c3b548 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogs.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogs.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult; import org.hyperledger.besu.ethereum.core.LogWithMetadata; @@ -49,6 +49,6 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { } return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.LOGS_FILTER_NOT_FOUND); + requestContext.getRequest().getId(), RpcErrorType.LOGS_FILTER_NOT_FOUND); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetLogs.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetLogs.java index 506aa7549e7..fdf0f4935f5 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetLogs.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetLogs.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.LogWithMetadata; @@ -57,7 +57,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { if (!filter.isValid()) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } final AtomicReference ex = new AtomicReference<>(); @@ -111,10 +111,10 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { .log(); if (ex.get() instanceof IllegalArgumentException) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.EXCEEDS_RPC_MAX_BLOCK_RANGE); + requestContext.getRequest().getId(), RpcErrorType.EXCEEDS_RPC_MAX_BLOCK_RANGE); } return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } return new JsonRpcSuccessResponse( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetMinerDataByBlockHash.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetMinerDataByBlockHash.java index 424f0f772ee..1d3d647e3f2 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetMinerDataByBlockHash.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetMinerDataByBlockHash.java @@ -86,7 +86,8 @@ public static MinerDataResult createMinerDataResult( .map( t -> blockchainQueries - .transactionReceiptByTransactionHash(t.getTransaction().getHash()) + .transactionReceiptByTransactionHash( + t.getTransaction().getHash(), protocolSchedule) .map( receipt -> receipt diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetProof.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetProof.java index 6075f2be28b..c929903bc40 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetProof.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetProof.java @@ -19,10 +19,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameterOrBlockHash; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.proof.GetProofResult; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.proof.WorldStateProof; @@ -77,11 +77,11 @@ protected Object resultByBlockHash( Optional.of( new JsonRpcErrorResponse( requestContext.getRequest().getId(), - JsonRpcError.NO_ACCOUNT_FOUND))); + RpcErrorType.NO_ACCOUNT_FOUND))); }) .orElse( new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.WORLD_STATE_UNAVAILABLE)); + requestContext.getRequest().getId(), RpcErrorType.WORLD_STATE_UNAVAILABLE)); } @Override diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByHash.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByHash.java index 49346f187b4..2c854239e7b 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByHash.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByHash.java @@ -17,26 +17,26 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionCompleteResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionPendingResult; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import java.util.Optional; public class EthGetTransactionByHash implements JsonRpcMethod { private final BlockchainQueries blockchain; - private final PendingTransactions pendingTransactions; + private final TransactionPool transactionPool; public EthGetTransactionByHash( - final BlockchainQueries blockchain, final PendingTransactions pendingTransactions) { + final BlockchainQueries blockchain, final TransactionPool transactionPool) { this.blockchain = blockchain; - this.pendingTransactions = pendingTransactions; + this.transactionPool = transactionPool; } @Override @@ -48,7 +48,7 @@ public String getName() { public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { if (requestContext.getRequest().getParamLength() != 1) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } final Hash hash = requestContext.getRequiredParameter(0, Hash.class); final JsonRpcSuccessResponse jsonRpcSuccessResponse = @@ -58,7 +58,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { private Object getResult(final Hash hash) { final Optional transactionPendingResult = - pendingTransactions.getTransactionByHash(hash).map(TransactionPendingResult::new); + transactionPool.getTransactionByHash(hash).map(TransactionPendingResult::new); return transactionPendingResult.orElseGet( () -> blockchain.transactionByHash(hash).map(TransactionCompleteResult::new).orElse(null)); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionCount.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionCount.java index 51a551f49b3..053588e89a4 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionCount.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionCount.java @@ -21,25 +21,25 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameterOrBlockHash; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import java.util.function.Supplier; import com.google.common.base.Suppliers; public class EthGetTransactionCount extends AbstractBlockParameterOrBlockHashMethod { - private final Supplier pendingTransactions; + private final Supplier transactionPoolSupplier; public EthGetTransactionCount( - final BlockchainQueries blockchain, final PendingTransactions pendingTransactions) { - this(Suppliers.ofInstance(blockchain), Suppliers.ofInstance(pendingTransactions)); + final BlockchainQueries blockchain, final TransactionPool transactionPoolSupplier) { + this(Suppliers.ofInstance(blockchain), Suppliers.ofInstance(transactionPoolSupplier)); } public EthGetTransactionCount( final Supplier blockchain, - final Supplier pendingTransactions) { + final Supplier transactionPoolSupplier) { super(blockchain); - this.pendingTransactions = pendingTransactions; + this.transactionPoolSupplier = transactionPoolSupplier; } @Override @@ -56,7 +56,8 @@ protected BlockParameterOrBlockHash blockParameterOrBlockHash( @Override protected Object pendingResult(final JsonRpcRequestContext request) { final Address address = request.getRequiredParameter(0, Address.class); - final long pendingNonce = pendingTransactions.get().getNextNonceForSender(address).orElse(0); + final long pendingNonce = + transactionPoolSupplier.get().getNextNonceForSender(address).orElse(0); final long latestNonce = getBlockchainQueries() .getTransactionCount( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceipt.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceipt.java index d85abb1a96a..78c5f3b6504 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceipt.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceipt.java @@ -24,14 +24,19 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionReceiptStatusResult; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.TransactionReceiptType; public class EthGetTransactionReceipt implements JsonRpcMethod { private final BlockchainQueries blockchainQueries; - public EthGetTransactionReceipt(final BlockchainQueries blockchainQueries) { + private final ProtocolSchedule protocolSchedule; + + public EthGetTransactionReceipt( + final BlockchainQueries blockchainQueries, final ProtocolSchedule protocolSchedule) { this.blockchainQueries = blockchainQueries; + this.protocolSchedule = protocolSchedule; } @Override @@ -44,7 +49,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { final Hash hash = requestContext.getRequiredParameter(0, Hash.class); final TransactionReceiptResult result = blockchainQueries - .transactionReceiptByTransactionHash(hash) + .transactionReceiptByTransactionHash(hash, protocolSchedule) .map(this::getResult) .orElse(null); return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), result); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetWork.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetWork.java index 165779a806a..5c9a413eb3a 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetWork.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetWork.java @@ -16,10 +16,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator; @@ -66,7 +66,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { return new JsonRpcSuccessResponse(requestId, response); } else { LOG.trace("Mining is not operational, eth_getWork request cannot be processed"); - return new JsonRpcErrorResponse(requestId, JsonRpcError.NO_MINING_WORK_FOUND); + return new JsonRpcErrorResponse(requestId, RpcErrorType.NO_MINING_WORK_FOUND); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthNewFilter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthNewFilter.java index 26a3c7a6c63..e2e4576d433 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthNewFilter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthNewFilter.java @@ -18,10 +18,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; public class EthNewFilter implements JsonRpcMethod { @@ -42,7 +42,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { if (!filter.isValid()) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } final String logFilterId = diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendRawTransaction.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendRawTransaction.java index 3a7113001c6..82cf4410a51 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendRawTransaction.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendRawTransaction.java @@ -19,10 +19,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcRequestException; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.util.DomainObjectDecodeUtils; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; @@ -62,7 +62,7 @@ public String getName() { public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { if (requestContext.getRequest().getParamLength() != 1) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } final String rawTransaction = requestContext.getRequiredParameter(0, String.class); @@ -73,15 +73,15 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { } catch (final RLPException e) { LOG.debug("RLPException: {} caused by {}", e.getMessage(), e.getCause()); return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } catch (final InvalidJsonRpcRequestException i) { LOG.debug("InvalidJsonRpcRequestException: {} caused by {}", i.getMessage(), i.getCause()); return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } catch (final IllegalArgumentException ill) { LOG.debug("IllegalArgumentException: {} caused by {}", ill.getMessage(), ill.getCause()); return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } final ValidationResult validationResult = diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendTransaction.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendTransaction.java index bd30527d7d1..040093c51fd 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendTransaction.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendTransaction.java @@ -16,9 +16,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; public class EthSendTransaction implements JsonRpcMethod { @@ -30,6 +30,6 @@ public String getName() { @Override public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ETH_SEND_TX_NOT_AVAILABLE); + requestContext.getRequest().getId(), RpcErrorType.ETH_SEND_TX_NOT_AVAILABLE); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSubmitWork.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSubmitWork.java index 95e4de2b640..370643f203a 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSubmitWork.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSubmitWork.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; import org.hyperledger.besu.ethereum.mainnet.PoWSolution; import org.hyperledger.besu.ethereum.mainnet.PoWSolverInputs; @@ -60,7 +60,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { } else { LOG.trace("Mining is not operational, eth_submitWork request cannot be processed"); return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.NO_MINING_WORK_FOUND); + requestContext.getRequest().getId(), RpcErrorType.NO_MINING_WORK_FOUND); } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecuteTransactionStep.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecuteTransactionStep.java index e88f0e85b9f..6ccdb85cd0d 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecuteTransactionStep.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecuteTransactionStep.java @@ -14,7 +14,9 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; -import org.hyperledger.besu.datatypes.DataGas; +import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent; + +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -86,11 +88,13 @@ public TransactionTrace apply(final TransactionTrace transactionTrace) { BlockHeader header = block.getHeader(); final Optional maybeParentHeader = blockchain.getBlockHeader(header.getParentHash()); - final Wei dataGasPrice = + final Wei blobGasPrice = protocolSpec .getFeeMarket() - .dataPrice( - maybeParentHeader.flatMap(BlockHeader::getExcessDataGas).orElse(DataGas.ZERO)); + .blobGasPricePerGas( + maybeParentHeader + .map(parent -> calculateExcessBlobGasForParent(protocolSpec, parent)) + .orElse(BlobGas.ZERO)); final BlockHashLookup blockHashLookup = new CachingBlockHashLookup(header, blockchain); result = transactionProcessor.processTransaction( @@ -102,7 +106,7 @@ public TransactionTrace apply(final TransactionTrace transactionTrace) { tracer, blockHashLookup, false, - dataGasPrice); + blobGasPrice); traceFrames = tracer.copyTraceFrames(); tracer.reset(); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java index 9e22bc1b999..ab6f7acfb61 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java @@ -18,9 +18,9 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineCallListener; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -91,17 +91,17 @@ public final JsonRpcResponse response(final JsonRpcRequestContext request) { .log(); } return new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.INVALID_REQUEST); + request.getRequest().getId(), RpcErrorType.INVALID_REQUEST); }) .result())); try { return cf.get(); } catch (InterruptedException e) { LOG.error("Failed to get execution engine response", e); - return new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.TIMEOUT_ERROR); + return new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.TIMEOUT_ERROR); } catch (ExecutionException e) { LOG.error("Failed to get execution engine response", e); - return new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INTERNAL_ERROR); + return new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INTERNAL_ERROR); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/NetEnode.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/NetEnode.java index f1c5665d249..67ce3f83b0b 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/NetEnode.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/NetEnode.java @@ -16,10 +16,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork; import org.hyperledger.besu.plugin.data.EnodeURL; @@ -54,11 +54,11 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { } private JsonRpcErrorResponse p2pDisabledResponse(final JsonRpcRequestContext requestContext) { - return new JsonRpcErrorResponse(requestContext.getRequest().getId(), JsonRpcError.P2P_DISABLED); + return new JsonRpcErrorResponse(requestContext.getRequest().getId(), RpcErrorType.P2P_DISABLED); } private JsonRpcErrorResponse enodeUrlNotAvailable(final JsonRpcRequestContext requestContext) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.P2P_NETWORK_NOT_RUNNING); + requestContext.getRequest().getId(), RpcErrorType.P2P_NETWORK_NOT_RUNNING); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/NetPeerCount.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/NetPeerCount.java index 315c38b93c7..7816ecfe7f7 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/NetPeerCount.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/NetPeerCount.java @@ -16,10 +16,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork; import org.hyperledger.besu.ethereum.p2p.network.exceptions.P2PDisabledException; @@ -43,7 +43,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { requestContext.getRequest().getId(), Quantity.create(p2pNetwork.getPeerCount())); } catch (final P2PDisabledException e) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.P2P_DISABLED); + requestContext.getRequest().getId(), RpcErrorType.P2P_DISABLED); } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/PluginJsonRpcMethod.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/PluginJsonRpcMethod.java index 0366e078d68..46f9986b1c2 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/PluginJsonRpcMethod.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/PluginJsonRpcMethod.java @@ -14,8 +14,8 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INTERNAL_ERROR; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.PLUGIN_INTERNAL_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INTERNAL_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.PLUGIN_INTERNAL_ERROR; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; @@ -53,13 +53,13 @@ public JsonRpcResponse response(final JsonRpcRequestContext request) { final Object result = function.apply(() -> request.getRequest().getParams()); return new JsonRpcSuccessResponse(request.getRequest().getId(), result); } catch (final PluginRpcEndpointException ex) { - final JsonRpcError error = PLUGIN_INTERNAL_ERROR; - error.setData(ex.getMessage()); + final JsonRpcError error = new JsonRpcError(PLUGIN_INTERNAL_ERROR, ex.getMessage()); LOG.error("Error calling plugin JSON-RPC endpoint", ex); return new JsonRpcErrorResponse(request.getRequest().getId(), error); } catch (final Exception ex) { LOG.error("Error calling plugin JSON-RPC endpoint", ex); - return new JsonRpcErrorResponse(request.getRequest().getId(), INTERNAL_ERROR); + return new JsonRpcErrorResponse( + request.getRequest().getId(), new JsonRpcError(INTERNAL_ERROR)); } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/PluginsReloadConfiguration.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/PluginsReloadConfiguration.java index 15f3b63074e..34e9276c829 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/PluginsReloadConfiguration.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/PluginsReloadConfiguration.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.plugin.BesuPlugin; import java.util.Map; @@ -52,13 +52,13 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { "Plugin cannot be reloaded because no plugin has been registered with specified name: {}.", pluginName); return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.PLUGIN_NOT_FOUND); + requestContext.getRequest().getId(), RpcErrorType.PLUGIN_NOT_FOUND); } reloadPluginConfig(namedPlugins.get(pluginName)); return new JsonRpcSuccessResponse(requestContext.getRequest().getId()); } catch (InvalidJsonRpcParameters invalidJsonRpcParameters) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceCall.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceCall.java index c29aba8d30a..c6f7f24052f 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceCall.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceCall.java @@ -14,8 +14,8 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.BLOCK_NOT_FOUND; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INTERNAL_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.BLOCK_NOT_FOUND; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INTERNAL_ERROR; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceCallMany.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceCallMany.java index ded4ff2b08e..e3dfb245bb8 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceCallMany.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceCallMany.java @@ -14,8 +14,8 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.BLOCK_NOT_FOUND; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INTERNAL_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.BLOCK_NOT_FOUND; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INTERNAL_ERROR; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; @@ -24,8 +24,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.TraceCallManyParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.TraceTypeParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -79,7 +79,7 @@ protected Object resultByBlockNumber( if (requestContext.getRequest().getParamLength() != 2) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } final TraceCallManyParameter[] transactionsAndTraceTypeParameters; @@ -96,7 +96,7 @@ protected Object resultByBlockNumber( } catch (final Exception e) { LOG.error("Error parsing trace_callMany parameters: {}", e.getLocalizedMessage()); return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } final Optional maybeBlockHeader = diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceGet.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceGet.java index 62f8ed55685..f6289e2ce2d 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceGet.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceGet.java @@ -18,10 +18,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTracer; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; @@ -51,7 +51,7 @@ public String getName() { public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { if (requestContext.getRequest().getParamLength() != 2) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } final Hash transactionHash = requestContext.getRequiredParameter(0, Hash.class); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceRawTransaction.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceRawTransaction.java index db06b293c5e..8d1f8f6506e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceRawTransaction.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceRawTransaction.java @@ -14,16 +14,16 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INTERNAL_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INTERNAL_ERROR; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.TraceTypeParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.util.DomainObjectDecodeUtils; import org.hyperledger.besu.ethereum.core.Block; @@ -67,7 +67,7 @@ protected Object resultByBlockNumber( public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { if (requestContext.getRequest().getParamLength() != 2) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } final var rawTransaction = requestContext.getRequiredParameter(0, String.class); @@ -85,7 +85,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { LOG.trace("rawTx decoded to transaction {}", transaction); } catch (final RLPException | IllegalArgumentException e) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } final Set traceTypes = traceTypeParameter.getTraceTypes(); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuPendingTransactions.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuPendingTransactions.java index d1cf49fd0d2..067daa7a11e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuPendingTransactions.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuPendingTransactions.java @@ -23,7 +23,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.transaction.pool.PendingTransactionFilter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.transaction.pool.PendingTransactionFilter.Filter; import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import java.util.Collection; import java.util.Collections; @@ -34,10 +34,10 @@ public class TxPoolBesuPendingTransactions implements JsonRpcMethod { final PendingTransactionFilter pendingTransactionFilter; - private final PendingTransactions pendingTransactions; + private final TransactionPool transactionPool; - public TxPoolBesuPendingTransactions(final PendingTransactions pendingTransactions) { - this.pendingTransactions = pendingTransactions; + public TxPoolBesuPendingTransactions(final TransactionPool transactionPool) { + this.transactionPool = transactionPool; this.pendingTransactionFilter = new PendingTransactionFilter(); } @@ -57,8 +57,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { .orElse(Collections.emptyList()); final Collection pendingTransactionsFiltered = - pendingTransactionFilter.reduce( - pendingTransactions.getPendingTransactions(), filters, limit); + pendingTransactionFilter.reduce(transactionPool.getPendingTransactions(), filters, limit); return new JsonRpcSuccessResponse( requestContext.getRequest().getId(), diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuStatistics.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuStatistics.java index 1950d771ce2..6448da4a2f9 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuStatistics.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuStatistics.java @@ -20,16 +20,16 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.PendingTransactionsStatisticsResult; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import java.util.Collection; public class TxPoolBesuStatistics implements JsonRpcMethod { - private final PendingTransactions pendingTransactions; + private final TransactionPool transactionPool; - public TxPoolBesuStatistics(final PendingTransactions pendingTransactions) { - this.pendingTransactions = pendingTransactions; + public TxPoolBesuStatistics(final TransactionPool transactionPool) { + this.transactionPool = transactionPool; } @Override @@ -44,11 +44,11 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { private PendingTransactionsStatisticsResult statistics() { final Collection pendingTransaction = - pendingTransactions.getPendingTransactions(); + transactionPool.getPendingTransactions(); final long localCount = pendingTransaction.stream().filter(PendingTransaction::isReceivedFromLocalSource).count(); final long remoteCount = pendingTransaction.size() - localCount; return new PendingTransactionsStatisticsResult( - pendingTransactions.maxSize(), localCount, remoteCount); + transactionPool.maxSize(), localCount, remoteCount); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuTransactions.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuTransactions.java index 346241635f8..ad23f7724d0 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuTransactions.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuTransactions.java @@ -19,14 +19,14 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.PendingTransactionsResult; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; public class TxPoolBesuTransactions implements JsonRpcMethod { - private final PendingTransactions pendingTransactions; + private final TransactionPool transactionPool; - public TxPoolBesuTransactions(final PendingTransactions pendingTransactions) { - this.pendingTransactions = pendingTransactions; + public TxPoolBesuTransactions(final TransactionPool transactionPool) { + this.transactionPool = transactionPool; } @Override @@ -39,7 +39,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { final JsonRpcSuccessResponse jsonRpcSuccessResponse = new JsonRpcSuccessResponse( requestContext.getRequest().getId(), - new PendingTransactionsResult(pendingTransactions.getPendingTransactions())); + new PendingTransactionsResult(transactionPool.getPendingTransactions())); return jsonRpcSuccessResponse; } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/Web3Sha3.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/Web3Sha3.java index 2fb34ef1780..b1d137bb6b7 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/Web3Sha3.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/Web3Sha3.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.crypto.Hash; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.apache.tuweni.bytes.Bytes; @@ -38,14 +38,14 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { if (requestContext.getRequest().getParamLength() != 1) { // Do we want custom messages for each different type of invalid params? return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } final String data = requestContext.getRequiredParameter(0, String.class); if (!data.isEmpty() && !data.startsWith("0x")) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } try { @@ -54,7 +54,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { requestContext.getRequest().getId(), Hash.keccak256(byteData).toString()); } catch (final IllegalArgumentException err) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java index a856e7b1874..89002bf4534 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java @@ -30,10 +30,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EngineForkchoiceUpdatedParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePayloadAttributesParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineUpdateForkchoiceResult; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Withdrawal; @@ -113,7 +113,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) if (!isValidForkchoiceState( forkChoice.getSafeBlockHash(), forkChoice.getFinalizedBlockHash(), newHead)) { logForkchoiceUpdatedCall(INVALID, forkChoice); - return new JsonRpcErrorResponse(requestId, JsonRpcError.INVALID_FORKCHOICE_STATE); + return new JsonRpcErrorResponse(requestId, RpcErrorType.INVALID_FORKCHOICE_STATE); } // TODO: post-merge cleanup, this should be unnecessary after merge @@ -310,8 +310,8 @@ protected boolean requireTerminalPoWBlockValidation() { return false; } - protected JsonRpcError getInvalidPayloadError() { - return JsonRpcError.INVALID_PARAMS; + protected RpcErrorType getInvalidPayloadError() { + return RpcErrorType.INVALID_PARAMS; } // fcU calls are synchronous, no need to make volatile diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayload.java index d5eb2c04778..d2f7fdcd381 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayload.java @@ -20,9 +20,9 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockWithReceipts; @@ -63,7 +63,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext request) { LOG.atDebug().setMessage("assembledBlock {}").addArgument(() -> proposal).log(); return createResponse(request, payloadId, proposal); } - return new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.UNKNOWN_PAYLOAD); + return new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.UNKNOWN_PAYLOAD); } protected void logProposal( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java index ba463759a69..0cb3f9a4814 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java @@ -22,10 +22,12 @@ import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.VALID; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.DepositsValidatorProvider.getDepositsValidator; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.WithdrawalsValidatorProvider.getWithdrawalsValidator; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INVALID_PARAMS; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INVALID_PARAMS; import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.BlockProcessingResult; import org.hyperledger.besu.ethereum.ProtocolContext; @@ -38,6 +40,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EnginePayloadStatusResult; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; @@ -52,10 +55,14 @@ import org.hyperledger.besu.ethereum.mainnet.BodyValidation; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; +import org.hyperledger.besu.ethereum.mainnet.ValidationResult; +import org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator; import org.hyperledger.besu.ethereum.rlp.RLPException; import org.hyperledger.besu.ethereum.trie.MerkleTrieException; import org.hyperledger.besu.plugin.services.exception.StorageException; +import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -65,6 +72,7 @@ import io.vertx.core.Vertx; import io.vertx.core.json.Json; import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -97,7 +105,26 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) final EnginePayloadParameter blockParam = requestContext.getRequiredParameter(0, EnginePayloadParameter.class); - Object reqId = requestContext.getRequest().getId(); + final Optional> maybeVersionedHashParam = + requestContext.getOptionalList(1, String.class); + + final Object reqId = requestContext.getRequest().getId(); + + final ValidationResult forkValidationResult = + validateForkSupported(reqId, blockParam); + if (!forkValidationResult.isValid()) { + return new JsonRpcErrorResponse(reqId, forkValidationResult); + } + + final Optional> maybeVersionedHashes; + try { + maybeVersionedHashes = extractVersionedHashes(maybeVersionedHashParam); + } catch (RuntimeException ex) { + return respondWithInvalid(reqId, blockParam, null, INVALID, "Invalid versionedHash"); + } + + final Optional maybeParentHeader = + protocolContext.getBlockchain().getBlockHeader(blockParam.getParentHash()); LOG.atTrace() .setMessage("blockparam: {}") @@ -111,7 +138,8 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) if (!getWithdrawalsValidator( protocolSchedule, blockParam.getTimestamp(), blockParam.getBlockNumber()) .validateWithdrawals(maybeWithdrawals)) { - return new JsonRpcErrorResponse(reqId, INVALID_PARAMS); + return new JsonRpcErrorResponse( + reqId, new JsonRpcError(INVALID_PARAMS, "Invalid withdrawals")); } final Optional> maybeDeposits = @@ -120,7 +148,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) if (!getDepositsValidator( protocolSchedule, blockParam.getTimestamp(), blockParam.getBlockNumber()) .validateDepositParameter(maybeDeposits)) { - return new JsonRpcErrorResponse(reqId, INVALID_PARAMS); + return new JsonRpcErrorResponse(reqId, new JsonRpcError(INVALID_PARAMS, "Invalid deposits")); } if (mergeContext.get().isSyncing()) { @@ -172,7 +200,10 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) blockParam.getPrevRandao(), 0, maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null), - null, + blockParam.getBlobGasUsed() == null ? null : blockParam.getBlobGasUsed(), + blockParam.getExcessBlobGas() == null + ? null + : BlobGas.fromHexString(blockParam.getExcessBlobGas()), maybeDeposits.map(BodyValidation::depositsRoot).orElse(null), headerFunctions); @@ -184,8 +215,30 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) "Computed block hash %s does not match block hash parameter %s", newBlockHeader.getBlockHash(), blockParam.getBlockHash()); LOG.debug(errorMessage); - return respondWithInvalid(reqId, blockParam, null, getInvalidBlockHashStatus(), errorMessage); + return respondWithInvalid( + reqId, + blockParam, + mergeCoordinator.getLatestValidAncestor(blockParam.getParentHash()).orElse(null), + getInvalidBlockHashStatus(), + errorMessage); } + + ValidationResult blobValidationResult = + validateBlobs( + transactions, + newBlockHeader, + maybeParentHeader, + maybeVersionedHashes, + protocolSchedule.getByBlockHeader(newBlockHeader)); + if (!blobValidationResult.isValid()) { + return respondWithInvalid( + reqId, + blockParam, + null, + getInvalidBlockHashStatus(), + blobValidationResult.getErrorMessage()); + } + // do we already have this payload if (protocolContext.getBlockchain().getBlockByHash(newBlockHeader.getBlockHash()).isPresent()) { LOG.debug("block already present"); @@ -202,8 +255,6 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) "Block already present in bad block manager."); } - final Optional maybeParentHeader = - protocolContext.getBlockchain().getBlockHeader(blockParam.getParentHash()); if (maybeParentHeader.isPresent() && (blockParam.getTimestamp() <= maybeParentHeader.get().getTimestamp())) { return respondWithInvalid( @@ -225,7 +276,6 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) .addArgument(block::toLogString) .log(); mergeCoordinator.appendNewPayloadToSync(block); - return respondWith(reqId, blockParam, null, SYNCING); } @@ -261,7 +311,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) if (executionResult.causedBy().isPresent()) { Throwable causedBy = executionResult.causedBy().get(); if (causedBy instanceof StorageException || causedBy instanceof MerkleTrieException) { - JsonRpcError error = JsonRpcError.INTERNAL_ERROR; + RpcErrorType error = RpcErrorType.INTERNAL_ERROR; JsonRpcErrorResponse response = new JsonRpcErrorResponse(reqId, error); return response; } @@ -341,6 +391,98 @@ protected EngineStatus getInvalidBlockHashStatus() { return INVALID; } + protected ValidationResult validateForkSupported( + final Object id, final EnginePayloadParameter payloadParameter) { + return ValidationResult.valid(); + } + + protected ValidationResult validateBlobs( + final List transactions, + final BlockHeader header, + final Optional maybeParentHeader, + final Optional> maybeVersionedHashes, + final ProtocolSpec protocolSpec) { + + var blobTransactions = + transactions.stream().filter(transaction -> transaction.getType().supportsBlob()).toList(); + + final List transactionVersionedHashes = new ArrayList<>(); + for (Transaction transaction : blobTransactions) { + var versionedHashes = transaction.getVersionedHashes(); + // blob transactions must have at least one blob + if (versionedHashes.isEmpty()) { + return ValidationResult.invalid( + RpcErrorType.INVALID_PARAMS, "There must be at least one blob"); + } + transactionVersionedHashes.addAll(versionedHashes.get()); + } + + if (maybeVersionedHashes.isEmpty() && !transactionVersionedHashes.isEmpty()) { + return ValidationResult.invalid( + RpcErrorType.INVALID_PARAMS, "Payload must contain versioned hashes for transactions"); + } + + // Validate versionedHashesParam + if (maybeVersionedHashes.isPresent() + && !maybeVersionedHashes.get().equals(transactionVersionedHashes)) { + return ValidationResult.invalid( + RpcErrorType.INVALID_PARAMS, + "Versioned hashes from blob transactions do not match expected values"); + } + + // Validate excessBlobGas + if (maybeParentHeader.isPresent()) { + if (!validateExcessBlobGas(header, maybeParentHeader.get(), protocolSpec)) { + return ValidationResult.invalid( + RpcErrorType.INVALID_PARAMS, + "Payload excessBlobGas does not match calculated excessBlobGas"); + } + } + + // Validate blobGasUsed + if (header.getBlobGasUsed().isPresent() && maybeVersionedHashes.isPresent()) { + if (!validateBlobGasUsed(header, maybeVersionedHashes.get(), protocolSpec)) { + return ValidationResult.invalid( + RpcErrorType.INVALID_PARAMS, + "Payload BlobGasUsed does not match calculated BlobGasUsed"); + } + } + return ValidationResult.valid(); + } + + private boolean validateExcessBlobGas( + final BlockHeader header, final BlockHeader parentHeader, final ProtocolSpec protocolSpec) { + BlobGas calculatedBlobGas = + ExcessBlobGasCalculator.calculateExcessBlobGasForParent(protocolSpec, parentHeader); + return header.getExcessBlobGas().orElse(BlobGas.ZERO).equals(calculatedBlobGas); + } + + private boolean validateBlobGasUsed( + final BlockHeader header, + final List maybeVersionedHashes, + final ProtocolSpec protocolSpec) { + var calculatedBlobGas = + protocolSpec.getGasCalculator().blobGasCost(maybeVersionedHashes.size()); + return header.getBlobGasUsed().orElse(0L).equals(calculatedBlobGas); + } + + private Optional> extractVersionedHashes( + final Optional> maybeVersionedHashParam) { + return maybeVersionedHashParam.map( + versionedHashes -> + versionedHashes.stream() + .map(Bytes32::fromHexString) + .map( + hash -> { + try { + return new VersionedHash(hash); + } catch (InvalidParameterException e) { + throw new RuntimeException(e); + } + }) + .collect(Collectors.toList())); + } + private void logImportedBlockInfo(final Block block, final double timeInS) { final StringBuilder message = new StringBuilder(); message.append("Imported #%,d / %d tx"); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV1.java index cdfccca3c14..a5b9eeb9ed2 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV1.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV1.java @@ -17,7 +17,7 @@ import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import io.vertx.core.Vertx; @@ -44,7 +44,7 @@ protected boolean requireTerminalPoWBlockValidation() { } @Override - protected JsonRpcError getInvalidPayloadError() { - return JsonRpcError.INVALID_PAYLOAD_ATTRIBUTES; + protected RpcErrorType getInvalidPayloadError() { + return RpcErrorType.INVALID_PAYLOAD_ATTRIBUTES; } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1.java index acbc1f72aef..dbbbeaec66c 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1.java @@ -19,10 +19,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetPayloadBodiesResultV1; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -69,7 +69,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext request) { .log(); if (blockHashes.length > getMaxRequestBlocks()) { - return new JsonRpcErrorResponse(reqId, JsonRpcError.INVALID_RANGE_REQUEST_TOO_LARGE); + return new JsonRpcErrorResponse(reqId, RpcErrorType.INVALID_RANGE_REQUEST_TOO_LARGE); } final Blockchain blockchain = protocolContext.getBlockchain(); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByRangeV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByRangeV1.java index adbb3384d84..94576978097 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByRangeV1.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByRangeV1.java @@ -19,10 +19,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UnsignedLongParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetPayloadBodiesResultV1; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -70,11 +70,11 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext request) { .log(); if (startBlockNumber < 1 || count < 1) { - return new JsonRpcErrorResponse(reqId, JsonRpcError.INVALID_PARAMS); + return new JsonRpcErrorResponse(reqId, RpcErrorType.INVALID_PARAMS); } if (count > getMaxRequestBlocks()) { - return new JsonRpcErrorResponse(reqId, JsonRpcError.INVALID_RANGE_REQUEST_TOO_LARGE); + return new JsonRpcErrorResponse(reqId, RpcErrorType.INVALID_RANGE_REQUEST_TOO_LARGE); } final Blockchain blockchain = protocolContext.getBlockchain(); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3.java new file mode 100644 index 00000000000..64911f6b1cb --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3.java @@ -0,0 +1,91 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; + +import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; +import org.hyperledger.besu.consensus.merge.blockcreation.PayloadIdentifier; +import org.hyperledger.besu.ethereum.ProtocolContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; +import org.hyperledger.besu.ethereum.core.BlockWithReceipts; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; + +import java.util.Optional; + +import io.vertx.core.Vertx; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EngineGetPayloadV3 extends AbstractEngineGetPayload { + + private static final Logger LOG = LoggerFactory.getLogger(EngineGetPayloadV3.class); + private final Optional shanghai; + private final Optional cancun; + + public EngineGetPayloadV3( + final Vertx vertx, + final ProtocolContext protocolContext, + final MergeMiningCoordinator mergeMiningCoordinator, + final BlockResultFactory blockResultFactory, + final EngineCallListener engineCallListener, + final ProtocolSchedule schedule) { + super(vertx, protocolContext, mergeMiningCoordinator, blockResultFactory, engineCallListener); + this.shanghai = schedule.hardforkFor(s -> s.fork().name().equalsIgnoreCase("Shanghai")); + this.cancun = schedule.hardforkFor(s -> s.fork().name().equalsIgnoreCase("Cancun")); + } + + @Override + public String getName() { + return RpcMethod.ENGINE_GET_PAYLOAD_V3.getMethodName(); + } + + @Override + protected JsonRpcResponse createResponse( + final JsonRpcRequestContext request, + final PayloadIdentifier payloadId, + final BlockWithReceipts blockWithReceipts) { + + try { + long builtAt = blockWithReceipts.getHeader().getTimestamp(); + + if (this.shanghai.isPresent() && builtAt < this.shanghai.get().milestone()) { + return new JsonRpcSuccessResponse( + request.getRequest().getId(), + blockResultFactory.payloadTransactionCompleteV1(blockWithReceipts.getBlock())); + } else if (this.shanghai.isPresent() + && builtAt >= this.shanghai.get().milestone() + && this.cancun.isPresent() + && builtAt < this.cancun.get().milestone()) { + return new JsonRpcSuccessResponse( + request.getRequest().getId(), + blockResultFactory.payloadTransactionCompleteV2(blockWithReceipts)); + } else { + return new JsonRpcSuccessResponse( + request.getRequest().getId(), + blockResultFactory.payloadTransactionCompleteV3(blockWithReceipts)); + } + + } catch (ClassCastException e) { + LOG.error("configuration error, can't call V3 endpoint with non-default protocol schedule"); + return new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INTERNAL_ERROR); + } + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV1.java index 532df18e198..d7019543c02 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV1.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV1.java @@ -17,10 +17,19 @@ import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.INVALID_BLOCK_HASH; import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; +import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; +import org.hyperledger.besu.ethereum.mainnet.ValidationResult; + +import java.util.List; +import java.util.Optional; import io.vertx.core.Vertx; @@ -50,4 +59,14 @@ protected boolean requireTerminalPoWBlockValidation() { protected EngineStatus getInvalidBlockHashStatus() { return INVALID_BLOCK_HASH; } + + @Override + protected ValidationResult validateBlobs( + final List transactions, + final BlockHeader header, + final Optional maybeParentHeader, + final Optional> maybeVersionedHashParam, + final ProtocolSpec protocolSpec) { + return ValidationResult.valid(); + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2.java index 3642aee5e65..c2a69349235 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2.java @@ -15,10 +15,19 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; +import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; +import org.hyperledger.besu.ethereum.mainnet.ValidationResult; + +import java.util.List; +import java.util.Optional; import io.vertx.core.Vertx; @@ -38,4 +47,14 @@ public EngineNewPayloadV2( public String getName() { return RpcMethod.ENGINE_NEW_PAYLOAD_V2.getMethodName(); } + + @Override + protected ValidationResult validateBlobs( + final List transactions, + final BlockHeader header, + final Optional maybeParentHeader, + final Optional> maybeVersionedHashParam, + final ProtocolSpec protocolSpec) { + return ValidationResult.valid(); + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3.java new file mode 100644 index 00000000000..d83b1f578a2 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3.java @@ -0,0 +1,65 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; + +import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; +import org.hyperledger.besu.ethereum.ProtocolContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePayloadParameter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; +import org.hyperledger.besu.ethereum.eth.manager.EthPeers; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ValidationResult; + +import io.vertx.core.Vertx; + +public class EngineNewPayloadV3 extends AbstractEngineNewPayload { + + private final ProtocolSchedule timestampSchedule; + + public EngineNewPayloadV3( + final Vertx vertx, + final ProtocolSchedule timestampSchedule, + final ProtocolContext protocolContext, + final MergeMiningCoordinator mergeCoordinator, + final EthPeers ethPeers, + final EngineCallListener engineCallListener) { + super( + vertx, timestampSchedule, protocolContext, mergeCoordinator, ethPeers, engineCallListener); + this.timestampSchedule = timestampSchedule; + } + + @Override + public String getName() { + return RpcMethod.ENGINE_NEW_PAYLOAD_V3.getMethodName(); + } + + @Override + protected ValidationResult validateForkSupported( + final Object reqId, final EnginePayloadParameter payloadParameter) { + var cancun = timestampSchedule.hardforkFor(s -> s.fork().name().equalsIgnoreCase("Cancun")); + + if (cancun.isPresent() && payloadParameter.getTimestamp() >= cancun.get().milestone()) { + if (payloadParameter.getBlobGasUsed() == null + || payloadParameter.getExcessBlobGas() == null) { + return ValidationResult.invalid(RpcErrorType.INVALID_PARAMS, "Missing blob gas fields"); + } else { + return ValidationResult.valid(); + } + } else { + return ValidationResult.invalid(RpcErrorType.UNSUPPORTED_FORK, "Fork not supported"); + } + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java index fe8f377d91b..2e763aa5499 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java @@ -26,10 +26,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePreparePayloadParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EnginePreparePayloadResult; import org.hyperledger.besu.ethereum.core.Withdrawal; @@ -80,7 +80,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) payloadIdentifier -> new JsonRpcSuccessResponse( requestId, new EnginePreparePayloadResult(VALID, payloadIdentifier))) - .orElseGet(() -> new JsonRpcErrorResponse(requestId, JsonRpcError.INVALID_PARAMS)); + .orElseGet(() -> new JsonRpcErrorResponse(requestId, RpcErrorType.INVALID_PARAMS)); } @VisibleForTesting diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerChangeTargetGasLimit.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerChangeTargetGasLimit.java index 3b9819805b4..1c530c14cf6 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerChangeTargetGasLimit.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerChangeTargetGasLimit.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; public class MinerChangeTargetGasLimit implements JsonRpcMethod { @@ -43,11 +43,11 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { return new JsonRpcSuccessResponse(requestContext.getRequest().getId()); } catch (final IllegalArgumentException invalidJsonRpcParameters) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } catch (final UnsupportedOperationException unsupportedOperationException) { return new JsonRpcErrorResponse( requestContext.getRequest().getId(), - JsonRpcError.TARGET_GAS_LIMIT_MODIFICATION_UNSUPPORTED); + RpcErrorType.TARGET_GAS_LIMIT_MODIFICATION_UNSUPPORTED); } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerSetCoinbase.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerSetCoinbase.java index ba3e3b09ac7..eda085d77c4 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerSetCoinbase.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerSetCoinbase.java @@ -18,10 +18,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; public class MinerSetCoinbase implements JsonRpcMethod { @@ -45,7 +45,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), true); } catch (final UnsupportedOperationException ex) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_REQUEST); + requestContext.getRequest().getId(), RpcErrorType.INVALID_REQUEST); } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStart.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStart.java index 2b71eef24ad..ca8c341823e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStart.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStart.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.blockcreation.CoinbaseNotSetException; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; @@ -44,7 +44,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { enabled = miningCoordinator.enable(); } catch (final CoinbaseNotSetException e) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.COINBASE_NOT_SET); + requestContext.getRequest().getId(), RpcErrorType.COINBASE_NOT_SET); } return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), enabled); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddAccountsToAllowlist.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddAccountsToAllowlist.java index 8f5c69650d2..21898c79ede 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddAccountsToAllowlist.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddAccountsToAllowlist.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.permissioning.AccountLocalConfigPermissioningController; import org.hyperledger.besu.ethereum.permissioning.AllowlistOperationResult; @@ -53,22 +53,22 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { switch (addResult) { case ERROR_EMPTY_ENTRY: return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ACCOUNT_ALLOWLIST_EMPTY_ENTRY); + requestContext.getRequest().getId(), RpcErrorType.ACCOUNT_ALLOWLIST_EMPTY_ENTRY); case ERROR_INVALID_ENTRY: return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ACCOUNT_ALLOWLIST_INVALID_ENTRY); + requestContext.getRequest().getId(), RpcErrorType.ACCOUNT_ALLOWLIST_INVALID_ENTRY); case ERROR_EXISTING_ENTRY: return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ACCOUNT_ALLOWLIST_EXISTING_ENTRY); + requestContext.getRequest().getId(), RpcErrorType.ACCOUNT_ALLOWLIST_EXISTING_ENTRY); case ERROR_DUPLICATED_ENTRY: return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ACCOUNT_ALLOWLIST_DUPLICATED_ENTRY); + requestContext.getRequest().getId(), RpcErrorType.ACCOUNT_ALLOWLIST_DUPLICATED_ENTRY); case ERROR_ALLOWLIST_PERSIST_FAIL: return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ALLOWLIST_PERSIST_FAILURE); + requestContext.getRequest().getId(), RpcErrorType.ALLOWLIST_PERSIST_FAILURE); case ERROR_ALLOWLIST_FILE_SYNC: return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ALLOWLIST_FILE_SYNC); + requestContext.getRequest().getId(), RpcErrorType.ALLOWLIST_FILE_SYNC); case SUCCESS: return new JsonRpcSuccessResponse(requestContext.getRequest().getId()); default: @@ -77,7 +77,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { } } else { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ACCOUNT_ALLOWLIST_NOT_ENABLED); + requestContext.getRequest().getId(), RpcErrorType.ACCOUNT_ALLOWLIST_NOT_ENABLED); } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddNodesToAllowlist.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddNodesToAllowlist.java index b6c3390eaec..9659f5a776e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddNodesToAllowlist.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddNodesToAllowlist.java @@ -18,10 +18,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.StringListParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.p2p.network.exceptions.P2PDisabledException; import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController; import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController.NodesAllowlistResult; @@ -61,37 +61,37 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { return new JsonRpcSuccessResponse(requestContext.getRequest().getId()); case ERROR_EMPTY_ENTRY: return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_EMPTY_ENTRY); + requestContext.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_EMPTY_ENTRY); case ERROR_EXISTING_ENTRY: return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_EXISTING_ENTRY); + requestContext.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_EXISTING_ENTRY); case ERROR_DUPLICATED_ENTRY: return new JsonRpcErrorResponse( requestContext.getRequest().getId(), - JsonRpcError.NODE_ALLOWLIST_DUPLICATED_ENTRY); + RpcErrorType.NODE_ALLOWLIST_DUPLICATED_ENTRY); case ERROR_ALLOWLIST_PERSIST_FAIL: return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ALLOWLIST_PERSIST_FAILURE); + requestContext.getRequest().getId(), RpcErrorType.ALLOWLIST_PERSIST_FAILURE); case ERROR_ALLOWLIST_FILE_SYNC: return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ALLOWLIST_FILE_SYNC); + requestContext.getRequest().getId(), RpcErrorType.ALLOWLIST_FILE_SYNC); default: throw new Exception(); } } catch (IllegalArgumentException e) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_INVALID_ENTRY); + requestContext.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_INVALID_ENTRY); } catch (Exception e) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INTERNAL_ERROR); + requestContext.getRequest().getId(), RpcErrorType.INTERNAL_ERROR); } } else { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_NOT_ENABLED); + requestContext.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_NOT_ENABLED); } } catch (P2PDisabledException e) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.P2P_DISABLED); + requestContext.getRequest().getId(), RpcErrorType.P2P_DISABLED); } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetAccountsAllowlist.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetAccountsAllowlist.java index 06bf7c2d09b..1afa5ce787d 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetAccountsAllowlist.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetAccountsAllowlist.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.permissioning.AccountLocalConfigPermissioningController; import java.util.Optional; @@ -46,7 +46,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { requestContext.getRequest().getId(), allowlistController.get().getAccountAllowlist()); } else { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ACCOUNT_ALLOWLIST_NOT_ENABLED); + requestContext.getRequest().getId(), RpcErrorType.ACCOUNT_ALLOWLIST_NOT_ENABLED); } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetNodesAllowlist.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetNodesAllowlist.java index 728dd1d526e..5dd579e32b1 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetNodesAllowlist.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetNodesAllowlist.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.p2p.network.exceptions.P2PDisabledException; import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController; @@ -52,11 +52,11 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), enodeList); } else { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_NOT_ENABLED); + requestContext.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_NOT_ENABLED); } } catch (P2PDisabledException e) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.P2P_DISABLED); + requestContext.getRequest().getId(), RpcErrorType.P2P_DISABLED); } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermReloadPermissionsFromFile.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermReloadPermissionsFromFile.java index f53334e8585..076fea42fce 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermReloadPermissionsFromFile.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermReloadPermissionsFromFile.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.permissioning.AccountLocalConfigPermissioningController; import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController; @@ -47,7 +47,7 @@ public String getName() { public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { if (!accountAllowlistController.isPresent() && !nodesAllowlistController.isPresent()) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.PERMISSIONING_NOT_ENABLED); + requestContext.getRequest().getId(), RpcErrorType.PERMISSIONING_NOT_ENABLED); } try { @@ -56,7 +56,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { return new JsonRpcSuccessResponse(requestContext.getRequest().getId()); } catch (Exception e) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ALLOWLIST_RELOAD_ERROR); + requestContext.getRequest().getId(), RpcErrorType.ALLOWLIST_RELOAD_ERROR); } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveAccountsFromAllowlist.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveAccountsFromAllowlist.java index ce7ed0355f7..aefd69141d5 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveAccountsFromAllowlist.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveAccountsFromAllowlist.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.permissioning.AccountLocalConfigPermissioningController; import org.hyperledger.besu.ethereum.permissioning.AllowlistOperationResult; @@ -52,22 +52,22 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { switch (removeResult) { case ERROR_EMPTY_ENTRY: return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ACCOUNT_ALLOWLIST_EMPTY_ENTRY); + requestContext.getRequest().getId(), RpcErrorType.ACCOUNT_ALLOWLIST_EMPTY_ENTRY); case ERROR_INVALID_ENTRY: return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ACCOUNT_ALLOWLIST_INVALID_ENTRY); + requestContext.getRequest().getId(), RpcErrorType.ACCOUNT_ALLOWLIST_INVALID_ENTRY); case ERROR_ABSENT_ENTRY: return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ACCOUNT_ALLOWLIST_ABSENT_ENTRY); + requestContext.getRequest().getId(), RpcErrorType.ACCOUNT_ALLOWLIST_ABSENT_ENTRY); case ERROR_DUPLICATED_ENTRY: return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ACCOUNT_ALLOWLIST_DUPLICATED_ENTRY); + requestContext.getRequest().getId(), RpcErrorType.ACCOUNT_ALLOWLIST_DUPLICATED_ENTRY); case ERROR_ALLOWLIST_PERSIST_FAIL: return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ALLOWLIST_PERSIST_FAILURE); + requestContext.getRequest().getId(), RpcErrorType.ALLOWLIST_PERSIST_FAILURE); case ERROR_ALLOWLIST_FILE_SYNC: return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ALLOWLIST_FILE_SYNC); + requestContext.getRequest().getId(), RpcErrorType.ALLOWLIST_FILE_SYNC); case SUCCESS: return new JsonRpcSuccessResponse(requestContext.getRequest().getId()); default: @@ -76,7 +76,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { } } else { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ACCOUNT_ALLOWLIST_NOT_ENABLED); + requestContext.getRequest().getId(), RpcErrorType.ACCOUNT_ALLOWLIST_NOT_ENABLED); } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromAllowlist.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromAllowlist.java index f693d9fe0aa..876376fab15 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromAllowlist.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromAllowlist.java @@ -18,10 +18,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.StringListParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.p2p.network.exceptions.P2PDisabledException; import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController; import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController.NodesAllowlistResult; @@ -60,41 +60,41 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { return new JsonRpcSuccessResponse(requestContext.getRequest().getId()); case ERROR_EMPTY_ENTRY: return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_EMPTY_ENTRY); + requestContext.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_EMPTY_ENTRY); case ERROR_ABSENT_ENTRY: return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_MISSING_ENTRY); + requestContext.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_MISSING_ENTRY); case ERROR_DUPLICATED_ENTRY: return new JsonRpcErrorResponse( requestContext.getRequest().getId(), - JsonRpcError.NODE_ALLOWLIST_DUPLICATED_ENTRY); + RpcErrorType.NODE_ALLOWLIST_DUPLICATED_ENTRY); case ERROR_ALLOWLIST_PERSIST_FAIL: return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ALLOWLIST_PERSIST_FAILURE); + requestContext.getRequest().getId(), RpcErrorType.ALLOWLIST_PERSIST_FAILURE); case ERROR_ALLOWLIST_FILE_SYNC: return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ALLOWLIST_FILE_SYNC); + requestContext.getRequest().getId(), RpcErrorType.ALLOWLIST_FILE_SYNC); case ERROR_FIXED_NODE_CANNOT_BE_REMOVED: return new JsonRpcErrorResponse( requestContext.getRequest().getId(), - JsonRpcError.NODE_ALLOWLIST_FIXED_NODE_CANNOT_BE_REMOVED); + RpcErrorType.NODE_ALLOWLIST_FIXED_NODE_CANNOT_BE_REMOVED); default: throw new Exception(); } } catch (IllegalArgumentException e) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_INVALID_ENTRY); + requestContext.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_INVALID_ENTRY); } catch (Exception e) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INTERNAL_ERROR); + requestContext.getRequest().getId(), RpcErrorType.INTERNAL_ERROR); } } else { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_NOT_ENABLED); + requestContext.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_NOT_ENABLED); } } catch (P2PDisabledException e) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.P2P_DISABLED); + requestContext.getRequest().getId(), RpcErrorType.P2P_DISABLED); } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadParameter.java index 13197d92b93..b991cd094f1 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadParameter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadParameter.java @@ -47,6 +47,9 @@ public class EnginePayloadParameter { private final LogsBloomFilter logsBloom; private final List transactions; private final List withdrawals; + private final Long blobGasUsed; + private final String excessBlobGas; + private final List versionedHashes; private final List deposits; @JsonCreator @@ -66,6 +69,9 @@ public EnginePayloadParameter( @JsonProperty("prevRandao") final String prevRandao, @JsonProperty("transactions") final List transactions, @JsonProperty("withdrawals") final List withdrawals, + @JsonProperty("blobGasUsed") final UnsignedLongParameter blobGasUsed, + @JsonProperty("excessBlobGas") final String excessBlobGas, + @JsonProperty("versionedHashes") final List versionedHashes, @JsonProperty("deposits") final List deposits) { this.blockHash = blockHash; this.parentHash = parentHash; @@ -82,6 +88,9 @@ public EnginePayloadParameter( this.prevRandao = Bytes32.fromHexString(prevRandao); this.transactions = transactions; this.withdrawals = withdrawals; + this.blobGasUsed = blobGasUsed == null ? null : blobGasUsed.getValue(); + this.excessBlobGas = excessBlobGas; + this.versionedHashes = versionedHashes; this.deposits = deposits; } @@ -145,7 +154,19 @@ public List getWithdrawals() { return withdrawals; } + public Long getBlobGasUsed() { + return blobGasUsed; + } + + public String getExcessBlobGas() { + return excessBlobGas; + } + public List getDeposits() { return deposits; } + + public List getVersionedHashes() { + return versionedHashes; + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonRpcParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonRpcParameter.java index b025ec1d579..6e10b7a2316 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonRpcParameter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonRpcParameter.java @@ -16,9 +16,11 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; +import java.util.List; import java.util.Optional; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; @@ -84,4 +86,26 @@ public Optional optional( return Optional.of(param); } + + public Optional> optionalList( + final Object[] params, final int index, final Class listClass) { + if (params == null || params.length <= index || params[index] == null) { + return Optional.empty(); + } + Object rawParam = params[index]; + if (List.class.isAssignableFrom(rawParam.getClass())) { + try { + String listJson = mapper.writeValueAsString(rawParam); + List returnedList = mapper.readValue(listJson, new TypeReference>() {}); + return Optional.of(returnedList); + } catch (JsonProcessingException e) { + throw new InvalidJsonRpcParameters( + String.format( + "Invalid json rpc parameter at index %d. Supplied value was: '%s' of type: '%s' - expected type: '%s'", + index, rawParam, rawParam.getClass().getName(), listClass.getName()), + e); + } + } + return Optional.empty(); + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/UnsignedLongParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/UnsignedLongParameter.java index 603ae288c70..039592d28c2 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/UnsignedLongParameter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/UnsignedLongParameter.java @@ -24,6 +24,7 @@ public class UnsignedLongParameter { @JsonCreator public UnsignedLongParameter(final String value) { + checkArgument(value != null); this.value = Long.decode(value); checkArgument(this.value >= 0); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/DisabledPrivacyRpcMethod.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/DisabledPrivacyRpcMethod.java index 2b2f5d8454e..d51d32a1d4b 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/DisabledPrivacyRpcMethod.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/DisabledPrivacyRpcMethod.java @@ -16,9 +16,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; public class DisabledPrivacyRpcMethod implements JsonRpcMethod { @@ -36,6 +36,6 @@ public DisabledPrivacyRpcMethod(final String methodName) { @Override public final JsonRpcResponse response(final JsonRpcRequestContext requestContext) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.PRIVACY_NOT_ENABLED); + requestContext.getRequest().getId(), RpcErrorType.PRIVACY_NOT_ENABLED); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/MultiTenancyRpcMethodDecorator.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/MultiTenancyRpcMethodDecorator.java index 09ae469dfde..823c8b13cfa 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/MultiTenancyRpcMethodDecorator.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/MultiTenancyRpcMethodDecorator.java @@ -16,10 +16,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcUnauthorizedResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import java.util.Optional; @@ -46,10 +46,10 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { final Object id = requestContext.getRequest().getId(); if (user.isEmpty()) { LOG.error("Request does not contain an authorization token"); - return new JsonRpcUnauthorizedResponse(id, JsonRpcError.UNAUTHORIZED); + return new JsonRpcUnauthorizedResponse(id, RpcErrorType.UNAUTHORIZED); } else if (MultiTenancyUserUtil.privacyUserId(user).isEmpty()) { LOG.error("Request token does not contain an enclave public key"); - return new JsonRpcErrorResponse(id, JsonRpcError.INVALID_REQUEST); + return new JsonRpcErrorResponse(id, RpcErrorType.INVALID_REQUEST); } else { return rpcMethod.response(requestContext); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/PrivGetFilterChanges.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/PrivGetFilterChanges.java index cffa17d12f8..57b13cc423e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/PrivGetFilterChanges.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/PrivGetFilterChanges.java @@ -18,10 +18,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult; import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.privacy.MultiTenancyPrivacyController; @@ -63,7 +63,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { } return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.FILTER_NOT_FOUND); + requestContext.getRequest().getId(), RpcErrorType.FILTER_NOT_FOUND); } private void checkIfPrivacyGroupMatchesAuthenticatedPrivacyUserId( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/PrivGetFilterLogs.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/PrivGetFilterLogs.java index 768cd29f661..c687d66a1ab 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/PrivGetFilterLogs.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/PrivGetFilterLogs.java @@ -18,10 +18,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult; import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.privacy.MultiTenancyPrivacyController; @@ -64,7 +64,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext request) { } return new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.LOGS_FILTER_NOT_FOUND); + request.getRequest().getId(), RpcErrorType.LOGS_FILTER_NOT_FOUND); } private void checkIfPrivacyGroupMatchesAuthenticatedPrivacyUserId( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/AbstractEeaSendRawTransaction.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/AbstractEeaSendRawTransaction.java index e02099eb368..7ca3e943993 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/AbstractEeaSendRawTransaction.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/AbstractEeaSendRawTransaction.java @@ -16,18 +16,19 @@ import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcEnclaveErrorConverter.convertEnclaveInvalidReason; import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcErrorConverter.convertTransactionInvalidReason; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.DECODE_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.DECODE_ERROR; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; @@ -36,7 +37,6 @@ import org.hyperledger.besu.ethereum.rlp.RLPException; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; import org.hyperledger.besu.ethereum.util.NonceProvider; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.plugin.services.privacy.PrivateMarkerTransactionFactory; import java.util.Optional; @@ -112,7 +112,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { JsonRpcErrorResponse getJsonRpcErrorResponse( final Object id, final TransactionInvalidReason errorReason) { if (errorReason.equals(TransactionInvalidReason.INTRINSIC_GAS_EXCEEDS_GAS_LIMIT)) { - return new JsonRpcErrorResponse(id, JsonRpcError.PMT_FAILED_INTRINSIC_GAS_EXCEEDS_LIMIT); + return new JsonRpcErrorResponse(id, RpcErrorType.PMT_FAILED_INTRINSIC_GAS_EXCEEDS_LIMIT); } return new JsonRpcErrorResponse(id, convertTransactionInvalidReason(errorReason)); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/JsonRpcErrorResponseException.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/JsonRpcErrorResponseException.java index e781d06f145..79d006f48e6 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/JsonRpcErrorResponseException.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/JsonRpcErrorResponseException.java @@ -14,18 +14,18 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.eea; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; public class JsonRpcErrorResponseException extends RuntimeException { - private final JsonRpcError jsonRpcError; + private final RpcErrorType jsonRpcError; - public JsonRpcErrorResponseException(final JsonRpcError error) { + public JsonRpcErrorResponseException(final RpcErrorType error) { super(); this.jsonRpcError = error; } - public JsonRpcError getJsonRpcError() { + public RpcErrorType getJsonRpcError() { return jsonRpcError; } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/RestrictedFlexibleEeaSendRawTransaction.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/RestrictedFlexibleEeaSendRawTransaction.java index 8a5d4f07a32..3fa12563c03 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/RestrictedFlexibleEeaSendRawTransaction.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/RestrictedFlexibleEeaSendRawTransaction.java @@ -19,7 +19,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.enclave.types.PrivacyGroup; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; @@ -71,7 +71,7 @@ protected Transaction createPrivateMarkerTransaction( final Optional user) { final Optional maybePrivacyGroupId = privateTransaction.getPrivacyGroupId(); if (maybePrivacyGroupId.isEmpty()) { - throw new JsonRpcErrorResponseException(JsonRpcError.FLEXIBLE_PRIVACY_GROUP_ID_NOT_AVAILABLE); + throw new JsonRpcErrorResponseException(RpcErrorType.FLEXIBLE_PRIVACY_GROUP_ID_NOT_AVAILABLE); } final Bytes privacyGroupId = maybePrivacyGroupId.get(); @@ -83,7 +83,7 @@ protected Transaction createPrivateMarkerTransaction( final boolean isGroupAdditionTransaction = FlexibleUtil.isGroupAdditionTransaction(privateTransaction); if (maybePrivacyGroup.isEmpty() && !isGroupAdditionTransaction) { - throw new JsonRpcErrorResponseException(JsonRpcError.FLEXIBLE_PRIVACY_GROUP_DOES_NOT_EXIST); + throw new JsonRpcErrorResponseException(RpcErrorType.FLEXIBLE_PRIVACY_GROUP_DOES_NOT_EXIST); } if (isGroupAdditionTransaction) { @@ -104,7 +104,7 @@ protected Transaction createPrivateMarkerTransaction( } if (!maybePrivacyGroup.get().getMembers().contains(privacyUserId)) { - throw new JsonRpcErrorResponseException(JsonRpcError.FLEXIBLE_PRIVACY_GROUP_DOES_NOT_EXIST); + throw new JsonRpcErrorResponseException(RpcErrorType.FLEXIBLE_PRIVACY_GROUP_DOES_NOT_EXIST); } final String pmtPayload = diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/RestrictedOffchainEeaSendRawTransaction.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/RestrictedOffchainEeaSendRawTransaction.java index 4f7754cd6ac..34b46973913 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/RestrictedOffchainEeaSendRawTransaction.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/RestrictedOffchainEeaSendRawTransaction.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.eea; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.PRIVATE_FROM_DOES_NOT_MATCH_ENCLAVE_PUBLIC_KEY; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.PRIVATE_FROM_DOES_NOT_MATCH_ENCLAVE_PUBLIC_KEY; import static org.hyperledger.besu.ethereum.core.PrivacyParameters.DEFAULT_PRIVACY; import org.hyperledger.besu.datatypes.Address; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCall.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCall.java index 59fec4fb073..31469530b09 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCall.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCall.java @@ -26,6 +26,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.privacy.PrivacyController; import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; @@ -90,15 +91,11 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { private JsonRpcError errorResponse( final TransactionProcessingResult result, final TransactionInvalidReason reason) { - final JsonRpcError jsonRpcError; if (result.getRevertReason().isPresent() && result.getRevertReason().get().size() >= 4) { - jsonRpcError = JsonRpcError.REVERT_ERROR; - jsonRpcError.setData(result.getRevertReason().get().toHexString()); - } else { - jsonRpcError = JsonRpcErrorConverter.convertTransactionInvalidReason(reason); + return new JsonRpcError( + RpcErrorType.REVERT_ERROR, result.getRevertReason().get().toHexString()); } - - return jsonRpcError; + return new JsonRpcError(JsonRpcErrorConverter.convertTransactionInvalidReason(reason)); } private JsonCallParameter validateAndGetCallParams(final JsonRpcRequestContext request) { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDebugGetStateRoot.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDebugGetStateRoot.java index e7f9ec8f102..6ccc9630f96 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDebugGetStateRoot.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDebugGetStateRoot.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.FIND_PRIVACY_GROUP_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.FIND_PRIVACY_GROUP_ERROR; import org.hyperledger.besu.enclave.EnclaveClientException; import org.hyperledger.besu.enclave.types.PrivacyGroup; @@ -23,10 +23,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.AbstractBlockParameterMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.privacy.MultiTenancyValidationException; import org.hyperledger.besu.ethereum.privacy.PrivacyController; @@ -80,18 +80,18 @@ protected Object resultByBlockNumber( requestContext.getRequest().getId(), FIND_PRIVACY_GROUP_ERROR); } catch (final EnclaveClientException e) { final Pattern pattern = Pattern.compile("^Privacy group.*not found$"); - if (e.getMessage().equals(JsonRpcError.ENCLAVE_PRIVACY_GROUP_MISSING.getMessage()) + if (e.getMessage().equals(RpcErrorType.ENCLAVE_PRIVACY_GROUP_MISSING.getMessage()) || pattern.matcher(e.getMessage()).find()) { LOG.error("Failed to retrieve privacy group"); return new JsonRpcErrorResponse( requestContext.getRequest().getId(), FIND_PRIVACY_GROUP_ERROR); } else { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.ENCLAVE_ERROR); + requestContext.getRequest().getId(), RpcErrorType.ENCLAVE_ERROR); } } catch (final Exception e) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } if (privacyGroup.isEmpty()) { @@ -108,7 +108,7 @@ protected Object resultByBlockNumber( requestContext.getRequest().getId(), stateRootHash.toString())) .orElse( new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INTERNAL_ERROR)); + requestContext.getRequest().getId(), RpcErrorType.INTERNAL_ERROR)); } @Override diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDeletePrivacyGroup.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDeletePrivacyGroup.java index ed9bab3c5ab..db0c11ea5af 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDeletePrivacyGroup.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDeletePrivacyGroup.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.DELETE_PRIVACY_GROUP_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.DELETE_PRIVACY_GROUP_ERROR; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransaction.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransaction.java index b225fbf467c..62a087dade7 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransaction.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransaction.java @@ -16,19 +16,19 @@ import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcEnclaveErrorConverter.convertEnclaveInvalidReason; import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcErrorConverter.convertTransactionInvalidReason; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.DECODE_ERROR; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.ENCLAVE_ERROR; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.PRIVATE_FROM_DOES_NOT_MATCH_ENCLAVE_PUBLIC_KEY; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.DECODE_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.ENCLAVE_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.PRIVATE_FROM_DOES_NOT_MATCH_ENCLAVE_PUBLIC_KEY; import org.hyperledger.besu.enclave.types.PrivacyGroup; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.privacy.FlexibleUtil; import org.hyperledger.besu.ethereum.privacy.MultiTenancyValidationException; @@ -85,7 +85,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { final Optional maybePrivacyGroupId = privateTransaction.getPrivacyGroupId(); if (flexiblePrivacyGroupsEnabled && maybePrivacyGroupId.isEmpty()) { - return new JsonRpcErrorResponse(id, JsonRpcError.FLEXIBLE_PRIVACY_GROUP_ID_NOT_AVAILABLE); + return new JsonRpcErrorResponse(id, RpcErrorType.FLEXIBLE_PRIVACY_GROUP_ID_NOT_AVAILABLE); } Optional maybePrivacyGroup = @@ -110,7 +110,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { maybePrivacyGroup.get().addMembers(participantsFromParameter); } if (maybePrivacyGroup.isEmpty()) { - return new JsonRpcErrorResponse(id, JsonRpcError.FLEXIBLE_PRIVACY_GROUP_DOES_NOT_EXIST); + return new JsonRpcErrorResponse(id, RpcErrorType.FLEXIBLE_PRIVACY_GROUP_DOES_NOT_EXIST); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivFindPrivacyGroup.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivFindPrivacyGroup.java index b836008927f..c09e21dc2a2 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivFindPrivacyGroup.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivFindPrivacyGroup.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.FIND_PRIVACY_GROUP_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.FIND_PRIVACY_GROUP_ERROR; import org.hyperledger.besu.enclave.types.PrivacyGroup; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetEeaTransactionCount.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetEeaTransactionCount.java index 84c94868479..3ec2d87b6aa 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetEeaTransactionCount.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetEeaTransactionCount.java @@ -14,18 +14,18 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.GET_PRIVATE_TRANSACTION_NONCE_ERROR; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.PRIVATE_FROM_DOES_NOT_MATCH_ENCLAVE_PUBLIC_KEY; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.GET_PRIVATE_TRANSACTION_NONCE_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.PRIVATE_FROM_DOES_NOT_MATCH_ENCLAVE_PUBLIC_KEY; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.privacy.MultiTenancyValidationException; import org.hyperledger.besu.ethereum.privacy.PrivacyController; @@ -62,7 +62,7 @@ public String getName() { public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { if (requestContext.getRequest().getParamLength() != 3) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } final Address address = requestContext.getRequiredParameter(0, Address.class); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetLogs.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetLogs.java index dfde7bfbdfc..5e89386cda9 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetLogs.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetLogs.java @@ -20,10 +20,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.query.PrivacyQueries; @@ -66,7 +66,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { if (!filter.isValid()) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } final List matchingLogs = diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionCount.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionCount.java index 824daacfc9b..31cac2b8b3d 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionCount.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionCount.java @@ -14,17 +14,17 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.GET_PRIVATE_TRANSACTION_NONCE_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.GET_PRIVATE_TRANSACTION_NONCE_ERROR; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.privacy.MultiTenancyValidationException; import org.hyperledger.besu.ethereum.privacy.PrivacyController; @@ -53,7 +53,7 @@ public String getName() { public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { if (requestContext.getRequest().getParamLength() != 2) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } final Address address = requestContext.getRequiredParameter(0, Address.class); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceipt.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceipt.java index 000983a0ccb..f9bc4241048 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceipt.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceipt.java @@ -22,9 +22,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.PrivateTransactionReceiptResult; import org.hyperledger.besu.ethereum.privacy.ExecutedPrivateTransaction; @@ -159,7 +159,7 @@ private Optional findPrivateReceiptByPrivat private JsonRpcResponse handleEnclaveException( final JsonRpcRequestContext requestContext, final EnclaveClientException e) { - final JsonRpcError jsonRpcError = + final RpcErrorType jsonRpcError = JsonRpcEnclaveErrorConverter.convertEnclaveInvalidReason(e.getMessage()); switch (jsonRpcError) { case ENCLAVE_PAYLOAD_NOT_FOUND: diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivNewFilter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivNewFilter.java index 8c797540cb8..830e7e7e934 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivNewFilter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivNewFilter.java @@ -20,10 +20,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.privacy.MultiTenancyPrivacyController; import org.hyperledger.besu.ethereum.privacy.PrivacyController; @@ -60,7 +60,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext request) { } if (!filter.isValid()) { - return new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + return new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } final String logFilterId = diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/privx/PrivxFindFlexiblePrivacyGroup.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/privx/PrivxFindFlexiblePrivacyGroup.java index 263ed2ab485..0275626addd 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/privx/PrivxFindFlexiblePrivacyGroup.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/privx/PrivxFindFlexiblePrivacyGroup.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.privx; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.FIND_FLEXIBLE_PRIVACY_GROUP_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.FIND_FLEXIBLE_PRIVACY_GROUP_ERROR; import org.hyperledger.besu.enclave.types.PrivacyGroup; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java index 252771a7ed9..9444c9ee963 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java @@ -14,7 +14,9 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor; -import org.hyperledger.besu.datatypes.DataGas; +import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent; + +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.Tracer.TraceableState; @@ -49,21 +51,21 @@ public Optional block( block.getHeader(), block.getBody(), (body, header, blockchain, transactionProcessor, protocolSpec) -> { - final Wei dataGasPrice = + final Wei blobGasPrice = protocolSpec .getFeeMarket() - .dataPrice( + .blobGasPricePerGas( blockchain .getBlockHeader(header.getParentHash()) - .flatMap(BlockHeader::getExcessDataGas) - .orElse(DataGas.ZERO)); + .map(parent -> calculateExcessBlobGasForParent(protocolSpec, parent)) + .orElse(BlobGas.ZERO)); final List transactionTraces = body.getTransactions().stream() .map( transaction -> action.performAction( - transaction, header, blockchain, transactionProcessor, dataGasPrice)) + transaction, header, blockchain, transactionProcessor, blobGasPrice)) .toList(); return Optional.of(new BlockTrace(transactionTraces)); }); @@ -83,20 +85,20 @@ public Optional beforeTransactionInBlock( blockHash, (body, header, blockchain, transactionProcessor, protocolSpec) -> { final BlockHashLookup blockHashLookup = new CachingBlockHashLookup(header, blockchain); - final Wei dataGasPrice = + final Wei blobGasPrice = protocolSpec .getFeeMarket() - .dataPrice( + .blobGasPricePerGas( blockchain .getBlockHeader(header.getParentHash()) - .flatMap(BlockHeader::getExcessDataGas) - .orElse(DataGas.ZERO)); + .map(parent -> calculateExcessBlobGasForParent(protocolSpec, parent)) + .orElse(BlobGas.ZERO)); for (final Transaction transaction : body.getTransactions()) { if (transaction.getHash().equals(transactionHash)) { return Optional.of( action.performAction( - transaction, header, blockchain, transactionProcessor, dataGasPrice)); + transaction, header, blockchain, transactionProcessor, blobGasPrice)); } else { transactionProcessor.processTransaction( blockchain, @@ -107,7 +109,7 @@ public Optional beforeTransactionInBlock( blockHashLookup, false, TransactionValidationParams.blockReplay(), - dataGasPrice); + blobGasPrice); } } return Optional.empty(); @@ -123,7 +125,7 @@ public Optional afterTransactionInBlock( mutableWorldState, blockHash, transactionHash, - (transaction, blockHeader, blockchain, transactionProcessor, dataGasPrice) -> { + (transaction, blockHeader, blockchain, transactionProcessor, blobGasPrice) -> { final ProtocolSpec spec = protocolSchedule.getByBlockHeader(blockHeader); transactionProcessor.processTransaction( blockchain, @@ -134,9 +136,9 @@ public Optional afterTransactionInBlock( new CachingBlockHashLookup(blockHeader, blockchain), false, TransactionValidationParams.blockReplay(), - dataGasPrice); + blobGasPrice); return action.performAction( - transaction, blockHeader, blockchain, transactionProcessor, dataGasPrice); + transaction, blockHeader, blockchain, transactionProcessor, blobGasPrice); }); } @@ -197,6 +199,6 @@ T performAction( BlockHeader blockHeader, Blockchain blockchain, MainnetTransactionProcessor transactionProcessor, - Wei dataGasPrice); + Wei blobGasPrice); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockTracer.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockTracer.java index bfccaac9e2b..d7386453ff2 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockTracer.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockTracer.java @@ -54,7 +54,7 @@ public Optional trace( private BlockReplay.TransactionAction prepareReplayAction( final MutableWorldState mutableWorldState, final DebugOperationTracer tracer) { - return (transaction, header, blockchain, transactionProcessor, dataGasPrice) -> { + return (transaction, header, blockchain, transactionProcessor, blobGasPrice) -> { // if we have no prior updater, it must be the first TX, so use the block's initial state if (chainedUpdater == null) { chainedUpdater = mutableWorldState.updater(); @@ -73,7 +73,7 @@ private BlockReplay.TransactionAction prepareReplayAction( tracer, new CachingBlockHashLookup(header, blockchain), false, - dataGasPrice); + blobGasPrice); final List traceFrames = tracer.copyTraceFrames(); tracer.reset(); return new TransactionTrace(transaction, result, traceFrames); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java index 6375b7befed..71628c88969 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java @@ -15,8 +15,9 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor; import static java.util.function.Predicate.isEqual; +import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent; -import org.hyperledger.besu.datatypes.DataGas; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.TransactionTraceParams; @@ -73,7 +74,7 @@ public Optional traceTransaction( mutableWorldState, blockHash, transactionHash, - (transaction, header, blockchain, transactionProcessor, dataGasPrice) -> { + (transaction, header, blockchain, transactionProcessor, blobGasPrice) -> { final TransactionProcessingResult result = processTransaction( header, @@ -82,7 +83,7 @@ public Optional traceTransaction( transaction, transactionProcessor, tracer, - dataGasPrice); + blobGasPrice); return new TransactionTrace(transaction, result, tracer.getTraceFrames()); }); return transactionTrace; @@ -115,14 +116,14 @@ public List traceTransactionToFile( (body, header, blockchain, transactionProcessor, protocolSpec) -> { WorldUpdater stackedUpdater = mutableWorldState.updater().updater(); final List traces = new ArrayList<>(); - final Wei dataGasPrice = + final Wei blobGasPrice = protocolSpec .getFeeMarket() - .dataPrice( + .blobGasPricePerGas( blockchain .getBlockHeader(header.getParentHash()) - .flatMap(BlockHeader::getExcessDataGas) - .orElse(DataGas.ZERO)); + .map(parent -> calculateExcessBlobGasForParent(protocolSpec, parent)) + .orElse(BlobGas.ZERO)); for (int i = 0; i < body.getTransactions().size(); i++) { ((StackedUpdater) stackedUpdater).markTransactionBoundary(); final Transaction transaction = body.getTransactions().get(i); @@ -139,7 +140,7 @@ public List traceTransactionToFile( transaction, transactionProcessor, new StandardJsonTracer(out, showMemory, true, true), - dataGasPrice); + blobGasPrice); out.println( summaryTrace( transaction, timer.stop().elapsed(TimeUnit.NANOSECONDS), result)); @@ -156,7 +157,7 @@ public List traceTransactionToFile( transaction, transactionProcessor, OperationTracer.NO_TRACING, - dataGasPrice); + blobGasPrice); } } return Optional.of(traces); @@ -187,7 +188,7 @@ private TransactionProcessingResult processTransaction( final Transaction transaction, final MainnetTransactionProcessor transactionProcessor, final OperationTracer tracer, - final Wei dataGasPrice) { + final Wei blobGasPrice) { return transactionProcessor.processTransaction( blockchain, worldUpdater, @@ -198,7 +199,7 @@ private TransactionProcessingResult processTransaction( new CachingBlockHashLookup(header, blockchain), false, ImmutableTransactionValidationParams.builder().isAllowFutureNonce(true).build(), - dataGasPrice); + blobGasPrice); } public static String summaryTrace( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcError.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcError.java index 9554f6020fc..73c8a20519f 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcError.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcError.java @@ -14,222 +14,48 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.response; +import java.util.Objects; + import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.tuweni.bytes.Bytes; @JsonInclude(value = JsonInclude.Include.NON_NULL) @JsonFormat(shape = JsonFormat.Shape.OBJECT) -public enum JsonRpcError { - // Standard errors - PARSE_ERROR(-32700, "Parse error"), - INVALID_REQUEST(-32600, "Invalid Request"), - METHOD_NOT_FOUND(-32601, "Method not found"), - INVALID_PARAMS(-32602, "Invalid params"), - INTERNAL_ERROR(-32603, "Internal error"), - TIMEOUT_ERROR(-32603, "Timeout expired"), - METHOD_NOT_ENABLED(-32604, "Method not enabled"), - - // Resource unavailable error - TX_POOL_DISABLED(-32002, "Transaction pool not enabled"), - - // eth_getBlockByNumber specific error message - UNKNOWN_BLOCK(-39001, "Unknown block"), - - // eth_sendTransaction specific error message - ETH_SEND_TX_NOT_AVAILABLE( - -32604, - "The method eth_sendTransaction is not supported. Use eth_sendRawTransaction to send a signed transaction to Besu."), - ETH_SEND_TX_ALREADY_KNOWN(-32000, "Known transaction"), - ETH_SEND_TX_REPLACEMENT_UNDERPRICED(-32000, "Replacement transaction underpriced"), - // P2P related errors - P2P_DISABLED(-32000, "P2P has been disabled. This functionality is not available"), - P2P_NETWORK_NOT_RUNNING(-32000, "P2P network is not running"), - - // Filter & Subscription Errors - FILTER_NOT_FOUND(-32000, "Filter not found"), - LOGS_FILTER_NOT_FOUND(-32000, "Logs filter not found"), - SUBSCRIPTION_NOT_FOUND(-32000, "Subscription not found"), - NO_MINING_WORK_FOUND(-32000, "No mining work available yet"), - - // Transaction validation failures - NONCE_TOO_LOW(-32001, "Nonce too low"), - INVALID_TRANSACTION_SIGNATURE(-32002, "Invalid signature"), - INVALID_TRANSACTION_TYPE(-32602, "Invalid transaction type"), - INTRINSIC_GAS_EXCEEDS_LIMIT(-32003, "Intrinsic gas exceeds gas limit"), - TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE(-32004, "Upfront cost exceeds account balance"), - EXCEEDS_BLOCK_GAS_LIMIT(-32005, "Transaction gas limit exceeds block gas limit"), - EXCEEDS_RPC_MAX_BLOCK_RANGE(-32005, "Requested range exceeds maximum RPC range limit"), - EXCEEDS_RPC_MAX_BATCH_SIZE(-32005, "Number of requests exceeds max batch size"), - NONCE_TOO_HIGH(-32006, "Nonce too high"), - TX_SENDER_NOT_AUTHORIZED(-32007, "Sender account not authorized to send transactions"), - CHAIN_HEAD_WORLD_STATE_NOT_AVAILABLE(-32008, "Initial sync is still in progress"), - GAS_PRICE_TOO_LOW(-32009, "Gas price below configured minimum gas price"), - GAS_PRICE_BELOW_CURRENT_BASE_FEE(-32009, "Gas price below current base fee"), - WRONG_CHAIN_ID(-32000, "Wrong chainId"), - REPLAY_PROTECTED_SIGNATURES_NOT_SUPPORTED(-32000, "ChainId not supported"), - REPLAY_PROTECTED_SIGNATURE_REQUIRED(-32000, "ChainId is required"), - TX_FEECAP_EXCEEDED(-32000, "Transaction fee cap exceeded"), - REVERT_ERROR(-32000, "Execution reverted"), - TRANSACTION_NOT_FOUND(-32000, "Transaction not found"), - MAX_PRIORITY_FEE_PER_GAS_EXCEEDS_MAX_FEE_PER_GAS( - -32000, "Max priority fee per gas exceeds max fee per gas"), - NONCE_TOO_FAR_IN_FUTURE_FOR_SENDER( - -32000, "Transaction nonce is too distant from current sender nonce"), - LOWER_NONCE_INVALID_TRANSACTION_EXISTS( - -32000, "An invalid transaction with a lower nonce exists"), - TOTAL_DATA_GAS_TOO_HIGH(-32000, "Total data gas too high"), - - // Execution engine failures - UNKNOWN_PAYLOAD(-32001, "Payload does not exist / is not available"), - INVALID_TERMINAL_BLOCK(-32002, "Terminal block doesn't satisfy terminal block conditions"), - INVALID_FORKCHOICE_STATE(-38002, "Invalid forkchoice state"), - INVALID_PAYLOAD_ATTRIBUTES(-38003, "Invalid payload attributes"), - INVALID_RANGE_REQUEST_TOO_LARGE(-38004, "Too large request"), - // Miner failures - COINBASE_NOT_SET(-32010, "Coinbase not set. Unable to start mining without a coinbase"), - NO_HASHES_PER_SECOND(-32011, "No hashes being generated by the current node"), - TARGET_GAS_LIMIT_MODIFICATION_UNSUPPORTED( - -32011, "The node is not attempting to target a gas limit so the target can't be changed"), - - // Wallet errors - COINBASE_NOT_SPECIFIED(-32000, "Coinbase must be explicitly specified"), - - // Account errors - NO_ACCOUNT_FOUND(-32000, "Account not found"), - - // Worldstate errors - WORLD_STATE_UNAVAILABLE(-32000, "World state unavailable"), - - // Debug failures - BLOCK_NOT_FOUND(-32000, "Block not found"), - PARENT_BLOCK_NOT_FOUND(-32000, "Parent block not found"), - - // Permissioning/Account allowlist errors - ACCOUNT_ALLOWLIST_NOT_ENABLED(-32000, "Account allowlist has not been enabled"), - ACCOUNT_ALLOWLIST_EMPTY_ENTRY(-32000, "Request contains an empty list of accounts"), - ACCOUNT_ALLOWLIST_INVALID_ENTRY(-32000, "Request contains an invalid account"), - ACCOUNT_ALLOWLIST_DUPLICATED_ENTRY(-32000, "Request contains duplicate accounts"), - ACCOUNT_ALLOWLIST_EXISTING_ENTRY(-32000, "Cannot add an existing account to allowlist"), - ACCOUNT_ALLOWLIST_ABSENT_ENTRY(-32000, "Cannot remove an absent account from allowlist"), - - // Permissioning/Node allowlist errors - NODE_ALLOWLIST_NOT_ENABLED(-32000, "Node allowlist has not been enabled"), - NODE_ALLOWLIST_EMPTY_ENTRY(-32000, "Request contains an empty list of nodes"), - NODE_ALLOWLIST_INVALID_ENTRY(-32000, "Request contains an invalid node"), - NODE_ALLOWLIST_DUPLICATED_ENTRY(-32000, "Request contains duplicate nodes"), - NODE_ALLOWLIST_EXISTING_ENTRY(-32000, "Cannot add an existing node to allowlist"), - NODE_ALLOWLIST_MISSING_ENTRY(-32000, "Cannot remove an absent node from allowlist"), - NODE_ALLOWLIST_FIXED_NODE_CANNOT_BE_REMOVED( - -32000, "Cannot remove a fixed node (bootnode or static node) from allowlist"), - - // Permissioning/persistence errors - ALLOWLIST_PERSIST_FAILURE( - -32000, "Unable to persist changes to allowlist configuration file. Changes reverted"), - ALLOWLIST_FILE_SYNC( - -32000, - "The permissioning allowlist configuration file is out of sync. The changes have been applied, but not persisted to disk"), - ALLOWLIST_RELOAD_ERROR( - -32000, - "Error reloading permissions file. Please use perm_getAccountsAllowlist and perm_getNodesAllowlist to review the current state of the allowlists"), - PERMISSIONING_NOT_ENABLED(-32000, "Node/Account allowlist has not been enabled"), - NON_PERMITTED_NODE_CANNOT_BE_ADDED_AS_A_PEER(-32000, "Cannot add a non-permitted node as a peer"), - - // Permissioning/Authorization errors - UNAUTHORIZED(-40100, "Unauthorized"), - - // Private transaction errors - ENCLAVE_ERROR(-50100, "Error communicating with enclave"), - UNSUPPORTED_PRIVATE_TRANSACTION_TYPE(-50100, "Unsupported private transaction type"), - PRIVACY_NOT_ENABLED(-50100, "Privacy is not enabled"), - CREATE_PRIVACY_GROUP_ERROR(-50100, "Error creating privacy group"), - DECODE_ERROR(-50100, "Unable to decode the private signed raw transaction"), - DELETE_PRIVACY_GROUP_ERROR(-50100, "Error deleting privacy group"), - FIND_PRIVACY_GROUP_ERROR(-50100, "Error finding privacy group"), - FIND_FLEXIBLE_PRIVACY_GROUP_ERROR(-50100, "Error finding flexible privacy group"), - GET_PRIVATE_TRANSACTION_NONCE_ERROR(-50100, "Unable to determine nonce for account in group."), - OFFCHAIN_PRIVACY_GROUP_DOES_NOT_EXIST(-50100, "Offchain Privacy group does not exist."), - FLEXIBLE_PRIVACY_GROUP_DOES_NOT_EXIST(-50100, "Flexible Privacy group does not exist."), - FLEXIBLE_PRIVACY_GROUP_NOT_ENABLED(-50100, "Flexible privacy groups not enabled."), - OFFCHAIN_PRIVACY_GROUP_NOT_ENABLED( - -50100, "Offchain privacy group can't be used with Flexible privacy groups enabled."), - FLEXIBLE_PRIVACY_GROUP_ID_NOT_AVAILABLE( - -50100, "Private transactions to flexible privacy groups must use privacyGroupId"), - PMT_FAILED_INTRINSIC_GAS_EXCEEDS_LIMIT( - -50100, - "Privacy Marker Transaction failed due to intrinsic gas exceeding the limit. Gas limit used from the Private Transaction."), - PRIVATE_FROM_DOES_NOT_MATCH_ENCLAVE_PUBLIC_KEY( - -50100, "Private from does not match enclave public key"), - VALUE_NOT_ZERO(-50100, "We cannot transfer ether in a private transaction yet."), - PRIVATE_TRANSACTION_INVALID(-50100, "Private transaction invalid"), - PRIVATE_TRANSACTION_FAILED(-50100, "Private transaction failed"), - - CANT_CONNECT_TO_LOCAL_PEER(-32100, "Cannot add local node as peer."), - CANT_RESOLVE_PEER_ENODE_DNS(-32100, "Cannot resolve enode DNS hostname"), - DNS_NOT_ENABLED(-32100, "Enode DNS support is disabled"), - - // Invalid input errors - ENODE_ID_INVALID( - -32000, - "Invalid node ID: node ID must have exactly 128 hexadecimal characters and should not include any '0x' hex prefix."), - JSON_RPC_NOT_CANONICAL_ERROR(-32000, "Invalid input"), - - // Enclave errors - NODE_MISSING_PEER_URL(-50200, "NodeMissingPeerUrl"), - NODE_PUSHING_TO_PEER(-50200, "NodePushingToPeer"), - NODE_PROPAGATING_TO_ALL_PEERS(-50200, "NodePropagatingToAllPeers"), - NO_SENDER_KEY(-50200, "NoSenderKey"), - INVALID_PAYLOAD(-50200, "InvalidPayload"), - ENCLAVE_CREATE_KEY_PAIR(-50200, "EnclaveCreateKeyPair"), - ENCLAVE_DECODE_PUBLIC_KEY(-50200, "EnclaveDecodePublicKey"), - ENCLAVE_DECRYPT_WRONG_PRIVATE_KEY(-50200, "EnclaveDecryptWrongPrivateKey"), - ENCLAVE_ENCRYPT_COMBINE_KEYS(-50200, "EnclaveEncryptCombineKeys"), - ENCLAVE_MISSING_PRIVATE_KEY_PASSWORD(-50200, "EnclaveMissingPrivateKeyPasswords"), - ENCLAVE_NO_MATCHING_PRIVATE_KEY(-50200, "EnclaveNoMatchingPrivateKey"), - ENCLAVE_NOT_PAYLOAD_OWNER(-50200, "EnclaveNotPayloadOwner"), - ENCLAVE_UNSUPPORTED_PRIVATE_KEY_TYPE(-50200, "EnclaveUnsupportedPrivateKeyType"), - ENCLAVE_STORAGE_DECRYPT(-50200, "EnclaveStorageDecrypt"), - ENCLAVE_PRIVACY_GROUP_CREATION(-50200, "EnclavePrivacyGroupIdCreation"), - ENCLAVE_PAYLOAD_NOT_FOUND(-50200, "EnclavePayloadNotFound"), - CREATE_GROUP_INCLUDE_SELF(-50200, "CreatePrivacyGroupShouldIncludeSelf"), - - // Tessera error codes - TESSERA_NODE_MISSING_PEER_URL(-50200, "Recipient not found for key:"), - TESSERA_CREATE_GROUP_INCLUDE_SELF( - -50200, "The list of members in a privacy group should include self"), - - /** Storing privacy group issue */ - ENCLAVE_UNABLE_STORE_PRIVACY_GROUP(-50200, "PrivacyGroupNotStored"), - ENCLAVE_UNABLE_DELETE_PRIVACY_GROUP(-50200, "PrivacyGroupNotDeleted"), - ENCLAVE_UNABLE_PUSH_DELETE_PRIVACY_GROUP(-50200, "PrivacyGroupNotPushed"), - ENCLAVE_PRIVACY_GROUP_MISSING(-50200, "PrivacyGroupNotFound"), - ENCLAVE_PRIVACY_QUERY_ERROR(-50200, "PrivacyGroupQueryError"), - ENCLAVE_KEYS_CANNOT_DECRYPT_PAYLOAD(-50200, "EnclaveKeysCannotDecryptPayload"), - METHOD_UNIMPLEMENTED(-50200, "MethodUnimplemented"), - - /** Plugins error */ - PLUGIN_NOT_FOUND(-60000, "Plugin not found"), - PLUGIN_INTERNAL_ERROR(-32603, "Plugin internal error"), - - // Retesteth Errors - - BLOCK_RLP_IMPORT_ERROR(-32000, "Could not decode RLP for Block"), - BLOCK_IMPORT_ERROR(-32000, "Could not import Block"); - +public class JsonRpcError { private final int code; private final String message; - private String data; + private final String data; + private String reason; - JsonRpcError(final int code, final String message, final String data) { + @JsonCreator + public JsonRpcError( + @JsonProperty("code") final int code, + @JsonProperty("message") final String message, + @JsonProperty("data") final String data) { this.code = code; this.message = message; this.data = data; } - JsonRpcError(final int code, final String message) { - this(code, message, null); + public JsonRpcError(final RpcErrorType errorType, final String data) { + this(errorType.getCode(), errorType.getMessage(), data); + + // For execution reverted errors decode the data (if present) + if (errorType == RpcErrorType.REVERT_ERROR && data != null) { + JsonRpcErrorResponse.decodeRevertReason(Bytes.fromHexString(data)) + .ifPresent( + (decodedReason) -> { + this.reason = decodedReason; + }); + } + } + + public JsonRpcError(final RpcErrorType errorType) { + this(errorType, null); } @JsonGetter("code") @@ -239,7 +65,7 @@ public int getCode() { @JsonGetter("message") public String getMessage() { - return message; + return (reason == null ? message : message + ": " + reason); } @JsonGetter("data") @@ -247,20 +73,22 @@ public String getData() { return data; } - public void setData(final String data) { - this.data = data; + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final JsonRpcError that = (JsonRpcError) o; + return code == that.code + && Objects.equals(message.split(":", -1)[0], that.message.split(":", -1)[0]) + && Objects.equals(data, that.data); } - @JsonCreator - public static JsonRpcError fromJson( - @JsonProperty("code") final int code, - @JsonProperty("message") final String message, - @JsonProperty("data") final String data) { - for (final JsonRpcError error : JsonRpcError.values()) { - if (error.code == code && error.message.equals(message) && error.data.equals(data)) { - return error; - } - } - return null; + @Override + public int hashCode() { + return Objects.hash(code, message.split(":", -1)[0], data); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcErrorResponse.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcErrorResponse.java index 9c50d7da4c0..ed8f275c07a 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcErrorResponse.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcErrorResponse.java @@ -14,22 +14,50 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.response; +import org.hyperledger.besu.ethereum.mainnet.ValidationResult; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import java.util.Objects; +import java.util.Optional; import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.google.common.base.MoreObjects; +import org.apache.tuweni.bytes.Bytes; +import org.web3j.abi.FunctionReturnDecoder; +import org.web3j.abi.TypeReference; +import org.web3j.abi.datatypes.AbiTypes; +import org.web3j.abi.datatypes.Type; +import org.web3j.abi.datatypes.Utf8String; @JsonPropertyOrder({"jsonrpc", "id", "error"}) public class JsonRpcErrorResponse implements JsonRpcResponse { private final Object id; private final JsonRpcError error; + @JsonIgnore private final RpcErrorType errorType; + + // Encoding of "Error(string)" to check for at the start of the revert reason + static final String errorMethodABI = "0x08c379a0"; public JsonRpcErrorResponse(final Object id, final JsonRpcError error) { this.id = id; this.error = error; + this.errorType = findErrorType(error.getCode(), error.getMessage()); + } + + public JsonRpcErrorResponse(final Object id, final RpcErrorType error) { + this(id, new JsonRpcError(error)); + } + + public JsonRpcErrorResponse( + final Object id, final ValidationResult validationResult) { + this( + id, + new JsonRpcError(validationResult.getInvalidReason(), validationResult.getErrorMessage())); } @JsonGetter("id") @@ -57,7 +85,7 @@ public boolean equals(final Object o) { return false; } final JsonRpcErrorResponse that = (JsonRpcErrorResponse) o; - return Objects.equals(id, that.id) && error == that.error; + return Objects.equals(id, that.id) && Objects.equals(error, that.error); } @Override @@ -69,4 +97,41 @@ public int hashCode() { public String toString() { return MoreObjects.toStringHelper(this).add("id", id).add("error", error).toString(); } + + @JsonIgnore + public RpcErrorType getErrorType() { + return errorType; + } + + private RpcErrorType findErrorType(final int code, final String message) { + return Arrays.stream(RpcErrorType.values()) + .filter(e -> e.getCode() == code && message.startsWith(e.getMessage())) + .findFirst() + .get(); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + public static Optional decodeRevertReason(final Bytes revertReason) { + if (revertReason.toHexString().startsWith(errorMethodABI)) { + // Remove the "Error(string)" prefix + final String encodedReasonText = + revertReason.toHexString().substring(errorMethodABI.length()); + + try { + List> revertReasonTypes = + Collections.singletonList( + TypeReference.create((Class) AbiTypes.getType("string"))); + List decoded = FunctionReturnDecoder.decode(encodedReasonText, revertReasonTypes); + + // Expect a single decoded string + if (decoded.size() == 1 && (decoded.get(0) instanceof Utf8String)) { + Utf8String decodedRevertReason = (Utf8String) decoded.get(0); + return Optional.of(decodedRevertReason.getValue()); + } + } catch (StringIndexOutOfBoundsException exception) { + return Optional.of("ABI decode error"); + } + } + return Optional.empty(); + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcUnauthorizedResponse.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcUnauthorizedResponse.java index e3650a3bf39..f59b49a30bd 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcUnauthorizedResponse.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcUnauthorizedResponse.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.response; +import java.util.Arrays; import java.util.Objects; import com.fasterxml.jackson.annotation.JsonGetter; @@ -25,10 +26,16 @@ public class JsonRpcUnauthorizedResponse implements JsonRpcResponse { private final Object id; private final JsonRpcError error; + @JsonIgnore private final RpcErrorType errorType; public JsonRpcUnauthorizedResponse(final Object id, final JsonRpcError error) { this.id = id; this.error = error; + this.errorType = findErrorType(error.getCode(), error.getMessage()); + } + + public JsonRpcUnauthorizedResponse(final Object id, final RpcErrorType error) { + this(id, new JsonRpcError(error)); } @JsonGetter("id") @@ -56,11 +63,23 @@ public boolean equals(final Object o) { return false; } final JsonRpcUnauthorizedResponse that = (JsonRpcUnauthorizedResponse) o; - return Objects.equals(id, that.id) && error == that.error; + return Objects.equals(id, that.id) && Objects.equals(error, that.error); } @Override public int hashCode() { return Objects.hash(id, error); } + + @JsonIgnore + public RpcErrorType getErrorType() { + return errorType; + } + + private RpcErrorType findErrorType(final int code, final String message) { + return Arrays.stream(RpcErrorType.values()) + .filter(e -> e.getCode() == code && e.getMessage().equals(message)) + .findFirst() + .get(); + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/RpcErrorType.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/RpcErrorType.java new file mode 100644 index 00000000000..c3ef46016d9 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/RpcErrorType.java @@ -0,0 +1,230 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.response; + +public enum RpcErrorType { + // Standard errors + PARSE_ERROR(-32700, "Parse error"), + INVALID_REQUEST(-32600, "Invalid Request"), + METHOD_NOT_FOUND(-32601, "Method not found"), + INVALID_PARAMS(-32602, "Invalid params"), + INTERNAL_ERROR(-32603, "Internal error"), + TIMEOUT_ERROR(-32603, "Timeout expired"), + + METHOD_NOT_ENABLED(-32604, "Method not enabled"), + + // Resource unavailable error + TX_POOL_DISABLED(-32002, "Transaction pool not enabled"), + + // eth_getBlockByNumber specific error message + UNKNOWN_BLOCK(-39001, "Unknown block"), + + // eth_sendTransaction specific error message + ETH_SEND_TX_NOT_AVAILABLE( + -32604, + "The method eth_sendTransaction is not supported. Use eth_sendRawTransaction to send a signed transaction to Besu."), + ETH_SEND_TX_ALREADY_KNOWN(-32000, "Known transaction"), + ETH_SEND_TX_REPLACEMENT_UNDERPRICED(-32000, "Replacement transaction underpriced"), + // P2P related errors + P2P_DISABLED(-32000, "P2P has been disabled. This functionality is not available"), + P2P_NETWORK_NOT_RUNNING(-32000, "P2P network is not running"), + + // Filter & Subscription Errors + FILTER_NOT_FOUND(-32000, "Filter not found"), + LOGS_FILTER_NOT_FOUND(-32000, "Logs filter not found"), + SUBSCRIPTION_NOT_FOUND(-32000, "Subscription not found"), + NO_MINING_WORK_FOUND(-32000, "No mining work available yet"), + + // Transaction validation failures + NONCE_TOO_LOW(-32001, "Nonce too low"), + INVALID_TRANSACTION_SIGNATURE(-32002, "Invalid signature"), + INVALID_TRANSACTION_TYPE(-32602, "Invalid transaction type"), + INTRINSIC_GAS_EXCEEDS_LIMIT(-32003, "Intrinsic gas exceeds gas limit"), + TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE(-32004, "Upfront cost exceeds account balance"), + EXCEEDS_BLOCK_GAS_LIMIT(-32005, "Transaction gas limit exceeds block gas limit"), + EXCEEDS_RPC_MAX_BLOCK_RANGE(-32005, "Requested range exceeds maximum RPC range limit"), + EXCEEDS_RPC_MAX_BATCH_SIZE(-32005, "Number of requests exceeds max batch size"), + NONCE_TOO_HIGH(-32006, "Nonce too high"), + TX_SENDER_NOT_AUTHORIZED(-32007, "Sender account not authorized to send transactions"), + CHAIN_HEAD_WORLD_STATE_NOT_AVAILABLE(-32008, "Initial sync is still in progress"), + GAS_PRICE_TOO_LOW(-32009, "Gas price below configured minimum gas price"), + GAS_PRICE_BELOW_CURRENT_BASE_FEE(-32009, "Gas price below current base fee"), + WRONG_CHAIN_ID(-32000, "Wrong chainId"), + REPLAY_PROTECTED_SIGNATURES_NOT_SUPPORTED(-32000, "ChainId not supported"), + REPLAY_PROTECTED_SIGNATURE_REQUIRED(-32000, "ChainId is required"), + TX_FEECAP_EXCEEDED(-32000, "Transaction fee cap exceeded"), + REVERT_ERROR(-32000, "Execution reverted"), + TRANSACTION_NOT_FOUND(-32000, "Transaction not found"), + MAX_PRIORITY_FEE_PER_GAS_EXCEEDS_MAX_FEE_PER_GAS( + -32000, "Max priority fee per gas exceeds max fee per gas"), + NONCE_TOO_FAR_IN_FUTURE_FOR_SENDER( + -32000, "Transaction nonce is too distant from current sender nonce"), + LOWER_NONCE_INVALID_TRANSACTION_EXISTS( + -32000, "An invalid transaction with a lower nonce exists"), + TOTAL_BLOB_GAS_TOO_HIGH(-32000, "Total blob gas too high"), + + // Execution engine failures + UNKNOWN_PAYLOAD(-32001, "Payload does not exist / is not available"), + INVALID_TERMINAL_BLOCK(-32002, "Terminal block doesn't satisfy terminal block conditions"), + INVALID_FORKCHOICE_STATE(-38002, "Invalid forkchoice state"), + INVALID_PAYLOAD_ATTRIBUTES(-38003, "Invalid payload attributes"), + INVALID_RANGE_REQUEST_TOO_LARGE(-38004, "Too large request"), + UNSUPPORTED_FORK(-38005, "Unsupported fork"), + // Miner failures + COINBASE_NOT_SET(-32010, "Coinbase not set. Unable to start mining without a coinbase"), + NO_HASHES_PER_SECOND(-32011, "No hashes being generated by the current node"), + TARGET_GAS_LIMIT_MODIFICATION_UNSUPPORTED( + -32011, "The node is not attempting to target a gas limit so the target can't be changed"), + + // Wallet errors + COINBASE_NOT_SPECIFIED(-32000, "Coinbase must be explicitly specified"), + + // Account errors + NO_ACCOUNT_FOUND(-32000, "Account not found"), + + // Worldstate errors + WORLD_STATE_UNAVAILABLE(-32000, "World state unavailable"), + + // Debug failures + BLOCK_NOT_FOUND(-32000, "Block not found"), + PARENT_BLOCK_NOT_FOUND(-32000, "Parent block not found"), + + // Permissioning/Account allowlist errors + ACCOUNT_ALLOWLIST_NOT_ENABLED(-32000, "Account allowlist has not been enabled"), + ACCOUNT_ALLOWLIST_EMPTY_ENTRY(-32000, "Request contains an empty list of accounts"), + ACCOUNT_ALLOWLIST_INVALID_ENTRY(-32000, "Request contains an invalid account"), + ACCOUNT_ALLOWLIST_DUPLICATED_ENTRY(-32000, "Request contains duplicate accounts"), + ACCOUNT_ALLOWLIST_EXISTING_ENTRY(-32000, "Cannot add an existing account to allowlist"), + ACCOUNT_ALLOWLIST_ABSENT_ENTRY(-32000, "Cannot remove an absent account from allowlist"), + + // Permissioning/Node allowlist errors + NODE_ALLOWLIST_NOT_ENABLED(-32000, "Node allowlist has not been enabled"), + NODE_ALLOWLIST_EMPTY_ENTRY(-32000, "Request contains an empty list of nodes"), + NODE_ALLOWLIST_INVALID_ENTRY(-32000, "Request contains an invalid node"), + NODE_ALLOWLIST_DUPLICATED_ENTRY(-32000, "Request contains duplicate nodes"), + NODE_ALLOWLIST_EXISTING_ENTRY(-32000, "Cannot add an existing node to allowlist"), + NODE_ALLOWLIST_MISSING_ENTRY(-32000, "Cannot remove an absent node from allowlist"), + NODE_ALLOWLIST_FIXED_NODE_CANNOT_BE_REMOVED( + -32000, "Cannot remove a fixed node (bootnode or static node) from allowlist"), + + // Permissioning/persistence errors + ALLOWLIST_PERSIST_FAILURE( + -32000, "Unable to persist changes to allowlist configuration file. Changes reverted"), + ALLOWLIST_FILE_SYNC( + -32000, + "The permissioning allowlist configuration file is out of sync. The changes have been applied, but not persisted to disk"), + ALLOWLIST_RELOAD_ERROR( + -32000, + "Error reloading permissions file. Please use perm_getAccountsAllowlist and perm_getNodesAllowlist to review the current state of the allowlists"), + PERMISSIONING_NOT_ENABLED(-32000, "Node/Account allowlist has not been enabled"), + NON_PERMITTED_NODE_CANNOT_BE_ADDED_AS_A_PEER(-32000, "Cannot add a non-permitted node as a peer"), + + // Permissioning/Authorization errors + UNAUTHORIZED(-40100, "Unauthorized"), + + // Private transaction errors + ENCLAVE_ERROR(-50100, "Error communicating with enclave"), + UNSUPPORTED_PRIVATE_TRANSACTION_TYPE(-50100, "Unsupported private transaction type"), + PRIVACY_NOT_ENABLED(-50100, "Privacy is not enabled"), + CREATE_PRIVACY_GROUP_ERROR(-50100, "Error creating privacy group"), + DECODE_ERROR(-50100, "Unable to decode the private signed raw transaction"), + DELETE_PRIVACY_GROUP_ERROR(-50100, "Error deleting privacy group"), + FIND_PRIVACY_GROUP_ERROR(-50100, "Error finding privacy group"), + FIND_FLEXIBLE_PRIVACY_GROUP_ERROR(-50100, "Error finding flexible privacy group"), + GET_PRIVATE_TRANSACTION_NONCE_ERROR(-50100, "Unable to determine nonce for account in group."), + OFFCHAIN_PRIVACY_GROUP_DOES_NOT_EXIST(-50100, "Offchain Privacy group does not exist."), + FLEXIBLE_PRIVACY_GROUP_DOES_NOT_EXIST(-50100, "Flexible Privacy group does not exist."), + FLEXIBLE_PRIVACY_GROUP_NOT_ENABLED(-50100, "Flexible privacy groups not enabled."), + OFFCHAIN_PRIVACY_GROUP_NOT_ENABLED( + -50100, "Offchain privacy group can't be used with Flexible privacy groups enabled."), + FLEXIBLE_PRIVACY_GROUP_ID_NOT_AVAILABLE( + -50100, "Private transactions to flexible privacy groups must use privacyGroupId"), + PMT_FAILED_INTRINSIC_GAS_EXCEEDS_LIMIT( + -50100, + "Privacy Marker Transaction failed due to intrinsic gas exceeding the limit. Gas limit used from the Private Transaction."), + PRIVATE_FROM_DOES_NOT_MATCH_ENCLAVE_PUBLIC_KEY( + -50100, "Private from does not match enclave public key"), + VALUE_NOT_ZERO(-50100, "We cannot transfer ether in a private transaction yet."), + PRIVATE_TRANSACTION_INVALID(-50100, "Private transaction invalid"), + PRIVATE_TRANSACTION_FAILED(-50100, "Private transaction failed"), + + CANT_CONNECT_TO_LOCAL_PEER(-32100, "Cannot add local node as peer."), + CANT_RESOLVE_PEER_ENODE_DNS(-32100, "Cannot resolve enode DNS hostname"), + DNS_NOT_ENABLED(-32100, "Enode DNS support is disabled"), + + // Invalid input errors + ENODE_ID_INVALID( + -32000, + "Invalid node ID: node ID must have exactly 128 hexadecimal characters and should not include any '0x' hex prefix."), + JSON_RPC_NOT_CANONICAL_ERROR(-32000, "Invalid input"), + + // Enclave errors + NODE_MISSING_PEER_URL(-50200, "NodeMissingPeerUrl"), + NODE_PUSHING_TO_PEER(-50200, "NodePushingToPeer"), + NODE_PROPAGATING_TO_ALL_PEERS(-50200, "NodePropagatingToAllPeers"), + NO_SENDER_KEY(-50200, "NoSenderKey"), + INVALID_PAYLOAD(-50200, "InvalidPayload"), + ENCLAVE_CREATE_KEY_PAIR(-50200, "EnclaveCreateKeyPair"), + ENCLAVE_DECODE_PUBLIC_KEY(-50200, "EnclaveDecodePublicKey"), + ENCLAVE_DECRYPT_WRONG_PRIVATE_KEY(-50200, "EnclaveDecryptWrongPrivateKey"), + ENCLAVE_ENCRYPT_COMBINE_KEYS(-50200, "EnclaveEncryptCombineKeys"), + ENCLAVE_MISSING_PRIVATE_KEY_PASSWORD(-50200, "EnclaveMissingPrivateKeyPasswords"), + ENCLAVE_NO_MATCHING_PRIVATE_KEY(-50200, "EnclaveNoMatchingPrivateKey"), + ENCLAVE_NOT_PAYLOAD_OWNER(-50200, "EnclaveNotPayloadOwner"), + ENCLAVE_UNSUPPORTED_PRIVATE_KEY_TYPE(-50200, "EnclaveUnsupportedPrivateKeyType"), + ENCLAVE_STORAGE_DECRYPT(-50200, "EnclaveStorageDecrypt"), + ENCLAVE_PRIVACY_GROUP_CREATION(-50200, "EnclavePrivacyGroupIdCreation"), + ENCLAVE_PAYLOAD_NOT_FOUND(-50200, "EnclavePayloadNotFound"), + CREATE_GROUP_INCLUDE_SELF(-50200, "CreatePrivacyGroupShouldIncludeSelf"), + + // Tessera error codes + TESSERA_NODE_MISSING_PEER_URL(-50200, "Recipient not found for key:"), + TESSERA_CREATE_GROUP_INCLUDE_SELF( + -50200, "The list of members in a privacy group should include self"), + + /** Storing privacy group issue */ + ENCLAVE_UNABLE_STORE_PRIVACY_GROUP(-50200, "PrivacyGroupNotStored"), + ENCLAVE_UNABLE_DELETE_PRIVACY_GROUP(-50200, "PrivacyGroupNotDeleted"), + ENCLAVE_UNABLE_PUSH_DELETE_PRIVACY_GROUP(-50200, "PrivacyGroupNotPushed"), + ENCLAVE_PRIVACY_GROUP_MISSING(-50200, "PrivacyGroupNotFound"), + ENCLAVE_PRIVACY_QUERY_ERROR(-50200, "PrivacyGroupQueryError"), + ENCLAVE_KEYS_CANNOT_DECRYPT_PAYLOAD(-50200, "EnclaveKeysCannotDecryptPayload"), + METHOD_UNIMPLEMENTED(-50200, "MethodUnimplemented"), + + /** Plugins error */ + PLUGIN_NOT_FOUND(-60000, "Plugin not found"), + PLUGIN_INTERNAL_ERROR(-32603, "Plugin internal error"), + + // Retesteth Errors + + BLOCK_RLP_IMPORT_ERROR(-32000, "Could not decode RLP for Block"), + BLOCK_IMPORT_ERROR(-32000, "Could not import Block"); + + private final int code; + private final String message; + + RpcErrorType(final int code, final String message) { + this.code = code; + this.message = message; + } + + public int getCode() { + return code; + } + + public String getMessage() { + return message; + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlobsBundleV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlobsBundleV1.java new file mode 100644 index 00000000000..4350c1d20cd --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlobsBundleV1.java @@ -0,0 +1,97 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; + +import org.hyperledger.besu.datatypes.Blob; +import org.hyperledger.besu.datatypes.BlobsWithCommitments; +import org.hyperledger.besu.datatypes.KZGCommitment; +import org.hyperledger.besu.datatypes.KZGProof; +import org.hyperledger.besu.ethereum.core.Transaction; + +import java.security.InvalidParameterException; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.tuweni.bytes.Bytes; + +@JsonPropertyOrder({"commitments", "proofs", "blobs"}) +public class BlobsBundleV1 { + + private final List commitments; + + private final List proofs; + + private final List blobs; + + public BlobsBundleV1(final List transactions) { + final List blobsWithCommitments = + transactions.stream() + .map(Transaction::getBlobsWithCommitments) + .filter(Optional::isPresent) + .map(Optional::get) + .toList(); + + this.commitments = + blobsWithCommitments.stream() + .flatMap(b -> b.getKzgCommitments().stream()) + .map(KZGCommitment::getData) + .map(Bytes::toString) + .collect(Collectors.toList()); + + this.proofs = + blobsWithCommitments.stream() + .flatMap(b -> b.getKzgProofs().stream()) + .map(KZGProof::getData) + .map(Bytes::toString) + .collect(Collectors.toList()); + + this.blobs = + blobsWithCommitments.stream() + .flatMap(b -> b.getBlobs().stream()) + .map(Blob::getData) + .map(Bytes::toString) + .collect(Collectors.toList()); + } + + public BlobsBundleV1( + final List commitments, final List proofs, final List blobs) { + if (blobs.size() != commitments.size() || blobs.size() != proofs.size()) { + throw new InvalidParameterException( + "There must be an equal number of blobs, commitments and proofs"); + } + this.commitments = commitments; + this.proofs = proofs; + this.blobs = blobs; + } + + @JsonGetter("commitments") + public List getCommitments() { + return commitments; + } + + @JsonGetter("proofs") + public List getProofs() { + return proofs; + } + + @JsonGetter("blobs") + public List getBlobs() { + return blobs; + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResult.java index 9ca61c8b0c7..4506cd81363 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResult.java @@ -84,6 +84,9 @@ public class BlockResult implements JsonRpcResult { private final String withdrawalsRoot; private final List withdrawals; + private final String blobGasUsed; + private final String excessBlobGas; + public BlockResult( final BlockHeader header, final List transactions, @@ -128,6 +131,9 @@ public BlockResult( withdrawals .map(w -> w.stream().map(WithdrawalParameter::fromWithdrawal).collect(toList())) .orElse(null); + + this.blobGasUsed = header.getBlobGasUsed().map(Quantity::create).orElse(null); + this.excessBlobGas = header.getExcessBlobGas().map(Quantity::create).orElse(null); } @JsonGetter(value = "number") @@ -250,4 +256,14 @@ public String getWithdrawalsRoot() { public List getWithdrawals() { return withdrawals; } + + @JsonGetter(value = "blobGasUsed") + public String getBlobGasUsed() { + return blobGasUsed; + } + + @JsonGetter(value = "excessBlobGas") + public String getExcessBlobGas() { + return excessBlobGas; + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java index 0b6d112dade..2d52c31b093 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java @@ -128,6 +128,26 @@ public EngineGetPayloadBodiesResultV1 payloadBodiesCompleteV1( return new EngineGetPayloadBodiesResultV1(payloadBodies); } + public EngineGetPayloadResultV3 payloadTransactionCompleteV3( + final BlockWithReceipts blockWithReceipts) { + final List txs = + blockWithReceipts.getBlock().getBody().getTransactions().stream() + .map(TransactionEncoder::encodeOpaqueBytes) + .map(Bytes::toHexString) + .collect(Collectors.toList()); + + final Wei blockValue = new BlockValueCalculator().calculateBlockValue(blockWithReceipts); + + final BlobsBundleV1 blobsBundleV1 = + new BlobsBundleV1(blockWithReceipts.getBlock().getBody().getTransactions()); + return new EngineGetPayloadResultV3( + blockWithReceipts.getHeader(), + txs, + blockWithReceipts.getBlock().getBody().getWithdrawals(), + Quantity.create(blockValue), + blobsBundleV1); + } + public BlockResult transactionHash(final BlockWithMetadata blockWithMetadata) { return transactionHash(blockWithMetadata, false); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV3.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV3.java new file mode 100644 index 00000000000..985ddc66359 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV3.java @@ -0,0 +1,202 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; + +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameter; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.Withdrawal; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.tuweni.bytes.Bytes32; + +@JsonPropertyOrder({"executionPayload", "blockValue", "blobsBundle"}) +public class EngineGetPayloadResultV3 { + protected final PayloadResult executionPayload; + private final String blockValue; + private final BlobsBundleV1 blobsBundle; + + public EngineGetPayloadResultV3( + final BlockHeader header, + final List transactions, + final Optional> withdrawals, + final String blockValue, + final BlobsBundleV1 blobsBundle) { + this.executionPayload = new PayloadResult(header, transactions, withdrawals); + this.blockValue = blockValue; + this.blobsBundle = blobsBundle; + } + + @JsonGetter(value = "executionPayload") + public PayloadResult getExecutionPayload() { + return executionPayload; + } + + @JsonGetter(value = "blockValue") + public String getBlockValue() { + return blockValue; + } + + @JsonGetter(value = "blobsBundle") + public BlobsBundleV1 getBlobsBundle() { + return blobsBundle; + } + + public static class PayloadResult { + + protected final String blockHash; + private final String parentHash; + private final String feeRecipient; + private final String stateRoot; + private final String receiptsRoot; + private final String logsBloom; + private final String prevRandao; + private final String blockNumber; + private final String gasLimit; + private final String gasUsed; + private final String timestamp; + private final String extraData; + private final String baseFeePerGas; + + private final String excessBlobGas; + + private final String blobGasUsed; + + protected final List transactions; + private final List withdrawals; + + public PayloadResult( + final BlockHeader header, + final List transactions, + final Optional> withdrawals) { + this.blockNumber = Quantity.create(header.getNumber()); + this.blockHash = header.getHash().toString(); + this.parentHash = header.getParentHash().toString(); + this.logsBloom = header.getLogsBloom().toString(); + this.stateRoot = header.getStateRoot().toString(); + this.receiptsRoot = header.getReceiptsRoot().toString(); + this.extraData = header.getExtraData().toString(); + this.baseFeePerGas = header.getBaseFee().map(Quantity::create).orElse(null); + this.gasLimit = Quantity.create(header.getGasLimit()); + this.gasUsed = Quantity.create(header.getGasUsed()); + this.timestamp = Quantity.create(header.getTimestamp()); + this.transactions = transactions; + this.feeRecipient = header.getCoinbase().toString(); + this.prevRandao = header.getPrevRandao().map(Bytes32::toHexString).orElse(null); + this.withdrawals = + withdrawals + .map( + ws -> + ws.stream() + .map(WithdrawalParameter::fromWithdrawal) + .collect(Collectors.toList())) + .orElse(null); + this.blobGasUsed = header.getBlobGasUsed().map(Quantity::create).orElse(Quantity.HEX_ZERO); + this.excessBlobGas = + header.getExcessBlobGas().map(Quantity::create).orElse(Quantity.HEX_ZERO); + } + + @JsonGetter(value = "blockNumber") + public String getNumber() { + return blockNumber; + } + + @JsonGetter(value = "blockHash") + public String getHash() { + return blockHash; + } + + @JsonGetter(value = "parentHash") + public String getParentHash() { + return parentHash; + } + + @JsonGetter(value = "logsBloom") + public String getLogsBloom() { + return logsBloom; + } + + @JsonGetter(value = "prevRandao") + public String getPrevRandao() { + return prevRandao; + } + + @JsonGetter(value = "stateRoot") + public String getStateRoot() { + return stateRoot; + } + + @JsonGetter(value = "receiptsRoot") + public String getReceiptRoot() { + return receiptsRoot; + } + + @JsonGetter(value = "extraData") + public String getExtraData() { + return extraData; + } + + @JsonGetter(value = "baseFeePerGas") + public String getBaseFeePerGas() { + return baseFeePerGas; + } + + @JsonGetter(value = "gasLimit") + public String getGasLimit() { + return gasLimit; + } + + @JsonGetter(value = "gasUsed") + public String getGasUsed() { + return gasUsed; + } + + @JsonGetter(value = "timestamp") + public String getTimestamp() { + return timestamp; + } + + @JsonGetter(value = "transactions") + public List getTransactions() { + return transactions; + } + + @JsonGetter(value = "withdrawals") + public List getWithdrawals() { + return withdrawals; + } + + @JsonGetter(value = "feeRecipient") + @JsonInclude(JsonInclude.Include.NON_NULL) + public String getFeeRecipient() { + return feeRecipient; + } + + @JsonGetter(value = "excessBlobGas") + public String getExcessBlobGas() { + return excessBlobGas; + } + + @JsonGetter(value = "blobGasUsed") + public String getBlobGasUseds() { + return blobGasUsed; + } + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/Quantity.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/Quantity.java index 5a37301d1ed..c9d06e509f5 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/Quantity.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/Quantity.java @@ -21,6 +21,7 @@ import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256; import org.apache.tuweni.units.bigints.UInt256Value; +import org.apache.tuweni.units.bigints.UInt64Value; /** * Utility for formatting "quantity" fields and results to be returned. Quantity fields are @@ -30,7 +31,7 @@ public class Quantity { private static final String HEX_PREFIX = "0x"; - private static final String HEX_ZERO = "0x0"; + public static final String HEX_ZERO = "0x0"; private Quantity() {} @@ -38,6 +39,10 @@ public static String create(final UInt256Value value) { return uint256ToHex(value); } + public static String create(final UInt64Value value) { + return (value == null || value.isZero()) ? HEX_ZERO : value.toMinimalBytes().toShortHexString(); + } + public static String create(final int value) { return uint256ToHex(UInt256.valueOf(value)); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionCompleteResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionCompleteResult.java index 793a6f9cebf..6c786550bc8 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionCompleteResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionCompleteResult.java @@ -14,11 +14,12 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; +import org.hyperledger.besu.datatypes.TransactionType; +import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.evm.AccessListEntry; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.List; @@ -37,6 +38,7 @@ "gasPrice", "maxPriorityFeePerGas", "maxFeePerGas", + "maxFeePerBlobGas", "hash", "input", "nonce", @@ -46,7 +48,8 @@ "value", "v", "r", - "s" + "s", + "blobVersionedHashes" }) public class TransactionCompleteResult implements TransactionResult { @@ -69,6 +72,9 @@ public class TransactionCompleteResult implements TransactionResult { @JsonInclude(JsonInclude.Include.NON_NULL) private final String maxFeePerGas; + @JsonInclude(JsonInclude.Include.NON_NULL) + private final String maxFeePerBlobGas; + private final String hash; private final String input; private final String nonce; @@ -80,6 +86,9 @@ public class TransactionCompleteResult implements TransactionResult { private final String r; private final String s; + @JsonInclude(JsonInclude.Include.NON_NULL) + private final List versionedHashes; + public TransactionCompleteResult(final TransactionWithMetadata tx) { final Transaction transaction = tx.getTransaction(); final TransactionType transactionType = transaction.getType(); @@ -93,6 +102,8 @@ public TransactionCompleteResult(final TransactionWithMetadata tx) { tx.getTransaction().getMaxPriorityFeePerGas().map(Wei::toShortHexString).orElse(null); this.maxFeePerGas = tx.getTransaction().getMaxFeePerGas().map(Wei::toShortHexString).orElse(null); + this.maxFeePerBlobGas = + transaction.getMaxFeePerBlobGas().map(Wei::toShortHexString).orElse(null); this.gasPrice = Quantity.create( transaction @@ -111,6 +122,7 @@ public TransactionCompleteResult(final TransactionWithMetadata tx) { this.v = Quantity.create(transaction.getV()); this.r = Quantity.create(transaction.getR()); this.s = Quantity.create(transaction.getS()); + this.versionedHashes = transaction.getVersionedHashes().orElse(null); } @JsonGetter(value = "accessList") @@ -153,6 +165,11 @@ public String getMaxFeePerGas() { return maxFeePerGas; } + @JsonGetter(value = "maxFeePerBlobGas") + public String getMaxFeePerBlobGas() { + return maxFeePerBlobGas; + } + @JsonGetter(value = "gasPrice") public String getGasPrice() { return gasPrice; @@ -207,4 +224,9 @@ public String getR() { public String getS() { return s; } + + @JsonGetter(value = "blobVersionedHashes") + public List getVersionedHashes() { + return versionedHashes; + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionPendingResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionPendingResult.java index 7aa3828e4d6..65b7b6bca5d 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionPendingResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionPendingResult.java @@ -15,12 +15,12 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; +import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; +import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import org.hyperledger.besu.evm.AccessListEntry; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.List; @@ -36,7 +36,7 @@ "gasPrice", "maxPriorityFeePerGas", "maxFeePerGas", - "maxFeePerDataGas", + "maxFeePerBlobGas", "hash", "input", "nonce", @@ -66,7 +66,7 @@ public class TransactionPendingResult implements TransactionResult { private final String maxFeePerGas; @JsonInclude(JsonInclude.Include.NON_NULL) - private final String maxFeePerDataGas; + private final String maxFeePerBlobGas; private final String hash; private final String input; @@ -81,7 +81,7 @@ public class TransactionPendingResult implements TransactionResult { private final String s; @JsonInclude(JsonInclude.Include.NON_NULL) - private final List versionedHashes; + private final List versionedHashes; public TransactionPendingResult(final Transaction transaction) { final TransactionType transactionType = transaction.getType(); @@ -92,16 +92,14 @@ public TransactionPendingResult(final Transaction transaction) { this.maxPriorityFeePerGas = transaction.getMaxPriorityFeePerGas().map(Wei::toShortHexString).orElse(null); this.maxFeePerGas = transaction.getMaxFeePerGas().map(Wei::toShortHexString).orElse(null); - this.maxFeePerDataGas = - transaction.getMaxFeePerDataGas().map(Wei::toShortHexString).orElse(null); + this.maxFeePerBlobGas = + transaction.getMaxFeePerBlobGas().map(Wei::toShortHexString).orElse(null); this.gasPrice = transaction.getGasPrice().map(Quantity::create).orElse(maxFeePerGas); this.hash = transaction.getHash().toString(); this.input = transaction.getPayload().toString(); this.nonce = Quantity.create(transaction.getNonce()); this.publicKey = transaction.getPublicKey().orElse(null); - final BytesValueRLPOutput out = new BytesValueRLPOutput(); - transaction.writeTo(out); - this.raw = out.encoded().toString(); + this.raw = TransactionEncoder.encodeOpaqueBytes(transaction).toString(); this.to = transaction.getTo().map(Address::toHexString).orElse(null); this.type = transactionType.equals(TransactionType.FRONTIER) @@ -149,9 +147,9 @@ public String getMaxFeePerGas() { return maxFeePerGas; } - @JsonGetter(value = "maxFeePerDataGas") - public String getMaxFeePerDataGas() { - return maxFeePerDataGas; + @JsonGetter(value = "maxFeePerBlobGas") + public String getMaxFeePerBlobGas() { + return maxFeePerBlobGas; } @JsonGetter(value = "hash") @@ -225,7 +223,7 @@ public String getTransactionIndex() { } @JsonGetter(value = "blobVersionedHashes") - public List getVersionedHashes() { + public List getVersionedHashes() { return versionedHashes; } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionReceiptResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionReceiptResult.java index db032289bde..b2f39d7a287 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionReceiptResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionReceiptResult.java @@ -16,11 +16,11 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.evm.log.Log; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.ArrayList; import java.util.List; @@ -46,7 +46,9 @@ "transactionHash", "transactionIndex", "revertReason", - "type" + "type", + "blobGasUsed", + "blobGasPrice" }) public abstract class TransactionReceiptResult { @@ -67,6 +69,9 @@ public abstract class TransactionReceiptResult { protected final TransactionReceipt receipt; protected final String type; + private final String blobGasUsed; + private final String blobGasPrice; + protected TransactionReceiptResult(final TransactionReceiptWithMetadata receiptWithMetadata) { final Transaction txn = receiptWithMetadata.getTransaction(); this.receipt = receiptWithMetadata.getReceipt(); @@ -76,6 +81,8 @@ protected TransactionReceiptResult(final TransactionReceiptWithMetadata receiptW this.cumulativeGasUsed = Quantity.create(receipt.getCumulativeGasUsed()); this.from = txn.getSender().toString(); this.gasUsed = Quantity.create(receiptWithMetadata.getGasUsed()); + this.blobGasUsed = receiptWithMetadata.getBlobGasUsed().map(Quantity::create).orElse(null); + this.blobGasPrice = receiptWithMetadata.getBlobGasPrice().map(Quantity::create).orElse(null); this.effectiveGasPrice = Quantity.create(txn.getEffectiveGasPrice(receiptWithMetadata.getBaseFee())); @@ -127,6 +134,18 @@ public String getGasUsed() { return gasUsed; } + @JsonGetter(value = "blobGasUsed") + @JsonInclude(JsonInclude.Include.NON_NULL) + public String getBlobGasUsed() { + return blobGasUsed; + } + + @JsonGetter(value = "blobGasPrice") + @JsonInclude(JsonInclude.Include.NON_NULL) + public String getBlobGasPrice() { + return blobGasPrice; + } + @JsonGetter(value = "effectiveGasPrice") public String getEffectiveGasPrice() { return effectiveGasPrice; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/ipc/JsonRpcIpcService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/ipc/JsonRpcIpcService.java index d34434c91cb..41214d9021a 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/ipc/JsonRpcIpcService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/ipc/JsonRpcIpcService.java @@ -14,14 +14,14 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.ipc; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INVALID_REQUEST; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INVALID_REQUEST; import org.hyperledger.besu.ethereum.api.jsonrpc.execution.JsonRpcExecutor; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponseType; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import java.io.IOException; import java.nio.file.Files; @@ -81,7 +81,7 @@ public Future start() { .handler( buffer -> { if (buffer.length() == 0) { - errorReturn(socket, null, JsonRpcError.INVALID_REQUEST); + errorReturn(socket, null, RpcErrorType.INVALID_REQUEST); } else { try { final JsonObject jsonRpcRequest = buffer.toJsonObject(); @@ -112,16 +112,16 @@ public Future start() { throwable -> { try { final Integer id = jsonRpcRequest.getInteger("id", null); - errorReturn(socket, id, JsonRpcError.INTERNAL_ERROR); + errorReturn(socket, id, RpcErrorType.INTERNAL_ERROR); } catch (ClassCastException idNotIntegerException) { - errorReturn(socket, null, JsonRpcError.INTERNAL_ERROR); + errorReturn(socket, null, RpcErrorType.INTERNAL_ERROR); } }); } catch (DecodeException jsonObjectDecodeException) { try { final JsonArray batchJsonRpcRequest = buffer.toJsonArray(); if (batchJsonRpcRequest.isEmpty()) { - errorReturn(socket, null, JsonRpcError.INVALID_REQUEST); + errorReturn(socket, null, RpcErrorType.INVALID_REQUEST); } else { vertx .>executeBlocking( @@ -167,10 +167,10 @@ public Future start() { }) .onFailure( throwable -> - errorReturn(socket, null, JsonRpcError.INTERNAL_ERROR)); + errorReturn(socket, null, RpcErrorType.INTERNAL_ERROR)); } } catch (DecodeException jsonArrayDecodeException) { - errorReturn(socket, null, JsonRpcError.PARSE_ERROR); + errorReturn(socket, null, RpcErrorType.PARSE_ERROR); } } } @@ -200,7 +200,7 @@ public Future stop() { } private Future errorReturn( - final NetSocket socket, final Integer id, final JsonRpcError rpcError) { + final NetSocket socket, final Integer id, final RpcErrorType rpcError) { return socket.write(Buffer.buffer(Json.encode(new JsonRpcErrorResponse(id, rpcError)) + '\n')); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ApiGroupJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ApiGroupJsonRpcMethods.java index e92df9fb527..00ea655296f 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ApiGroupJsonRpcMethods.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ApiGroupJsonRpcMethods.java @@ -19,6 +19,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -37,4 +38,8 @@ protected Map mapOf(final JsonRpcMethod... methods) { return Arrays.stream(methods) .collect(Collectors.toMap(JsonRpcMethod::getName, method -> method)); } + + protected Map mapOf(final List methods) { + return methods.stream().collect(Collectors.toMap(JsonRpcMethod::getName, method -> method)); + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EeaJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EeaJsonRpcMethods.java index 8594e2440e6..2edf176cd7c 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EeaJsonRpcMethods.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EeaJsonRpcMethods.java @@ -46,8 +46,7 @@ public EeaJsonRpcMethods( super(blockchainQueries, protocolSchedule, transactionPool, privacyParameters); this.transactionPool = transactionPool; this.privacyParameters = privacyParameters; - this.nonceProvider = - new LatestNonceProvider(blockchainQueries, transactionPool.getPendingTransactions()); + this.nonceProvider = new LatestNonceProvider(blockchainQueries, transactionPool); } @Override diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java index 43edba38359..938e3f62c94 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java @@ -138,11 +138,11 @@ protected Map create() { new EthNewBlockFilter(filterManager), new EthNewPendingTransactionFilter(filterManager), new EthNewFilter(filterManager), - new EthGetTransactionByHash(blockchainQueries, transactionPool.getPendingTransactions()), + new EthGetTransactionByHash(blockchainQueries, transactionPool), new EthGetTransactionByBlockHashAndIndex(blockchainQueries), new EthGetTransactionByBlockNumberAndIndex(blockchainQueries), - new EthGetTransactionCount(blockchainQueries, transactionPool.getPendingTransactions()), - new EthGetTransactionReceipt(blockchainQueries), + new EthGetTransactionCount(blockchainQueries, transactionPool), + new EthGetTransactionReceipt(blockchainQueries, protocolSchedule), new EthUninstallFilter(filterManager), new EthGetFilterChanges(filterManager), new EthGetFilterLogs(filterManager), diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java index d42049b59e3..1d0207887cf 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java @@ -26,8 +26,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayloadBodiesByRangeV1; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayloadV1; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayloadV2; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayloadV3; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineNewPayloadV1; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineNewPayloadV2; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineNewPayloadV3; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EnginePreparePayloadDebug; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineQosTimer; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; @@ -35,6 +37,9 @@ import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.Map; import java.util.Optional; @@ -74,56 +79,78 @@ protected String getApiGroup() { @Override protected Map create() { final EngineQosTimer engineQosTimer = new EngineQosTimer(consensusEngineServer); - if (mergeCoordinator.isPresent()) { - return mapOf( - new EngineGetPayloadV1( - consensusEngineServer, - protocolContext, - mergeCoordinator.get(), - blockResultFactory, - engineQosTimer), - new EngineGetPayloadV2( - consensusEngineServer, - protocolContext, - mergeCoordinator.get(), - blockResultFactory, - engineQosTimer), - new EngineNewPayloadV1( - consensusEngineServer, - protocolSchedule, - protocolContext, - mergeCoordinator.get(), - ethPeers, - engineQosTimer), - new EngineNewPayloadV2( - consensusEngineServer, - protocolSchedule, - protocolContext, - mergeCoordinator.get(), - ethPeers, - engineQosTimer), - new EngineForkchoiceUpdatedV1( - consensusEngineServer, - protocolSchedule, - protocolContext, - mergeCoordinator.get(), - engineQosTimer), - new EngineForkchoiceUpdatedV2( - consensusEngineServer, - protocolSchedule, - protocolContext, - mergeCoordinator.get(), - engineQosTimer), - new EngineExchangeTransitionConfiguration( - consensusEngineServer, protocolContext, engineQosTimer), - new EngineGetPayloadBodiesByHashV1( - consensusEngineServer, protocolContext, blockResultFactory, engineQosTimer), - new EngineGetPayloadBodiesByRangeV1( - consensusEngineServer, protocolContext, blockResultFactory, engineQosTimer), - new EngineExchangeCapabilities(consensusEngineServer, protocolContext, engineQosTimer), - new EnginePreparePayloadDebug( - consensusEngineServer, protocolContext, engineQosTimer, mergeCoordinator.get())); + List executionEngineApisSupported = new ArrayList<>(); + executionEngineApisSupported.addAll( + Arrays.asList( + new EngineGetPayloadV1( + consensusEngineServer, + protocolContext, + mergeCoordinator.get(), + blockResultFactory, + engineQosTimer), + new EngineGetPayloadV2( + consensusEngineServer, + protocolContext, + mergeCoordinator.get(), + blockResultFactory, + engineQosTimer), + new EngineNewPayloadV1( + consensusEngineServer, + protocolSchedule, + protocolContext, + mergeCoordinator.get(), + ethPeers, + engineQosTimer), + new EngineNewPayloadV2( + consensusEngineServer, + protocolSchedule, + protocolContext, + mergeCoordinator.get(), + ethPeers, + engineQosTimer), + new EngineNewPayloadV3( + consensusEngineServer, + protocolSchedule, + protocolContext, + mergeCoordinator.get(), + ethPeers, + engineQosTimer), + new EngineForkchoiceUpdatedV1( + consensusEngineServer, + protocolSchedule, + protocolContext, + mergeCoordinator.get(), + engineQosTimer), + new EngineForkchoiceUpdatedV2( + consensusEngineServer, + protocolSchedule, + protocolContext, + mergeCoordinator.get(), + engineQosTimer), + new EngineExchangeTransitionConfiguration( + consensusEngineServer, protocolContext, engineQosTimer), + new EngineGetPayloadBodiesByHashV1( + consensusEngineServer, protocolContext, blockResultFactory, engineQosTimer), + new EngineGetPayloadBodiesByRangeV1( + consensusEngineServer, protocolContext, blockResultFactory, engineQosTimer), + new EngineExchangeCapabilities( + consensusEngineServer, protocolContext, engineQosTimer), + new EnginePreparePayloadDebug( + consensusEngineServer, protocolContext, engineQosTimer, mergeCoordinator.get()))); + + if (protocolSchedule.anyMatch(p -> p.spec().getName().equalsIgnoreCase("cancun"))) { + executionEngineApisSupported.add( + new EngineGetPayloadV3( + consensusEngineServer, + protocolContext, + mergeCoordinator.get(), + blockResultFactory, + engineQosTimer, + protocolSchedule)); + } + + return mapOf(executionEngineApisSupported); } else { return mapOf( new EngineExchangeTransitionConfiguration( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/TxPoolJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/TxPoolJsonRpcMethods.java index cc20c06b02b..a4ea64101b4 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/TxPoolJsonRpcMethods.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/TxPoolJsonRpcMethods.java @@ -39,8 +39,8 @@ protected String getApiGroup() { @Override protected Map create() { return mapOf( - new TxPoolBesuTransactions(transactionPool.getPendingTransactions()), - new TxPoolBesuPendingTransactions(transactionPool.getPendingTransactions()), - new TxPoolBesuStatistics(transactionPool.getPendingTransactions())); + new TxPoolBesuTransactions(transactionPool), + new TxPoolBesuPendingTransactions(transactionPool), + new TxPoolBesuStatistics(transactionPool)); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketMessageHandler.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketMessageHandler.java index a4e552bc6fc..3f4995d7abd 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketMessageHandler.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketMessageHandler.java @@ -14,14 +14,14 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.websocket; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INVALID_REQUEST; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INVALID_REQUEST; import org.hyperledger.besu.ethereum.api.handlers.IsAliveHandler; import org.hyperledger.besu.ethereum.api.jsonrpc.execution.JsonRpcExecutor; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponseType; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.methods.WebSocketRpcRequest; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; @@ -73,7 +73,7 @@ public WebSocketMessageHandler( public void handle( final ServerWebSocket websocket, final Buffer buffer, final Optional user) { if (buffer.length() == 0) { - replyToClient(websocket, errorResponse(null, JsonRpcError.INVALID_REQUEST)); + replyToClient(websocket, errorResponse(null, RpcErrorType.INVALID_REQUEST)); } else { try { final JsonObject jsonRpcRequest = buffer.toJsonObject(); @@ -104,9 +104,9 @@ public void handle( throwable -> { try { final Integer id = jsonRpcRequest.getInteger("id", null); - replyToClient(websocket, errorResponse(id, JsonRpcError.INTERNAL_ERROR)); + replyToClient(websocket, errorResponse(id, RpcErrorType.INTERNAL_ERROR)); } catch (ClassCastException idNotIntegerException) { - replyToClient(websocket, errorResponse(null, JsonRpcError.INTERNAL_ERROR)); + replyToClient(websocket, errorResponse(null, RpcErrorType.INTERNAL_ERROR)); } }); } catch (DecodeException jsonObjectDecodeException) { @@ -152,9 +152,9 @@ public void handle( }) .onFailure( throwable -> - replyToClient(websocket, errorResponse(null, JsonRpcError.INTERNAL_ERROR))); + replyToClient(websocket, errorResponse(null, RpcErrorType.INTERNAL_ERROR))); } catch (RuntimeException jsonArrayDecodeException) { - replyToClient(websocket, errorResponse(null, JsonRpcError.INTERNAL_ERROR)); + replyToClient(websocket, errorResponse(null, RpcErrorType.INTERNAL_ERROR)); } } } @@ -169,7 +169,7 @@ private void replyToClient(final ServerWebSocket websocket, final Object result) } } - private JsonRpcResponse errorResponse(final Object id, final JsonRpcError error) { + private JsonRpcResponse errorResponse(final Object id, final RpcErrorType error) { return new JsonRpcErrorResponse(id, error); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthSubscribe.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthSubscribe.java index 1abf36b749c..c09d79e0fb7 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthSubscribe.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthSubscribe.java @@ -16,10 +16,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionManager; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request.InvalidSubscriptionRequestException; @@ -48,10 +48,10 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { requestContext.getRequest().getId(), Quantity.create(subscriptionId)); } catch (final InvalidSubscriptionRequestException isEx) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_REQUEST); + requestContext.getRequest().getId(), RpcErrorType.INVALID_REQUEST); } catch (final Exception e) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INTERNAL_ERROR); + requestContext.getRequest().getId(), RpcErrorType.INTERNAL_ERROR); } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthUnsubscribe.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthUnsubscribe.java index ddb1e8166c3..4ebaf1e0ed3 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthUnsubscribe.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthUnsubscribe.java @@ -16,10 +16,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionManager; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionNotFoundException; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request.InvalidSubscriptionRequestException; @@ -48,13 +48,13 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), unsubscribed); } catch (final InvalidSubscriptionRequestException isEx) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_REQUEST); + requestContext.getRequest().getId(), RpcErrorType.INVALID_REQUEST); } catch (final SubscriptionNotFoundException snfEx) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.SUBSCRIPTION_NOT_FOUND); + requestContext.getRequest().getId(), RpcErrorType.SUBSCRIPTION_NOT_FOUND); } catch (final Exception e) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INTERNAL_ERROR); + requestContext.getRequest().getId(), RpcErrorType.INTERNAL_ERROR); } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/PrivSubscribe.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/PrivSubscribe.java index b3766c85b86..72c497ce939 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/PrivSubscribe.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/PrivSubscribe.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionManager; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request.InvalidSubscriptionRequestException; @@ -61,7 +61,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { requestContext.getRequest().getId(), Quantity.create(subscriptionId)); } catch (final InvalidSubscriptionRequestException isEx) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_REQUEST); + requestContext.getRequest().getId(), RpcErrorType.INVALID_REQUEST); } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/PrivUnsubscribe.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/PrivUnsubscribe.java index 513c15c64e9..560f7eeeaf3 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/PrivUnsubscribe.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/PrivUnsubscribe.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionManager; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionNotFoundException; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request.InvalidSubscriptionRequestException; @@ -60,10 +60,10 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), unsubscribed); } catch (final InvalidSubscriptionRequestException isEx) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_REQUEST); + requestContext.getRequest().getId(), RpcErrorType.INVALID_REQUEST); } catch (final SubscriptionNotFoundException snfEx) { return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.SUBSCRIPTION_NOT_FOUND); + requestContext.getRequest().getId(), RpcErrorType.SUBSCRIPTION_NOT_FOUND); } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDetailResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDetailResult.java index bcd87a849e8..af503dba85e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDetailResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDetailResult.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.pending; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.JsonRpcResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.core.Transaction; @@ -30,6 +31,7 @@ "input", "nonce", "to", + "type", "value", "v", "r", @@ -43,6 +45,7 @@ public class PendingTransactionDetailResult implements JsonRpcResult { private final String input; private final String nonce; private final String to; + private final String type; private final String value; private final String v; private final String r; @@ -56,6 +59,10 @@ public PendingTransactionDetailResult(final Transaction tx) { this.input = tx.getPayload().toString(); this.nonce = Quantity.create(tx.getNonce()); this.to = tx.getTo().map(Bytes::toHexString).orElse(null); + this.type = + tx.getType().equals(TransactionType.FRONTIER) + ? Quantity.create(0) + : Quantity.create(tx.getType().getSerializedType()); this.value = Quantity.create(tx.getValue()); this.v = Quantity.create(tx.getV()); this.r = Quantity.create(tx.getR()); @@ -97,6 +104,11 @@ public String getTo() { return to; } + @JsonGetter(value = "type") + public String getType() { + return type; + } + @JsonGetter(value = "value") public String getValue() { return value; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java index 96e01fdb1b2..04bfdd9727a 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java @@ -16,6 +16,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static org.hyperledger.besu.ethereum.api.query.cache.TransactionLogBloomCacher.BLOCKS_PER_BLOOM_CACHE; +import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; @@ -33,6 +34,8 @@ import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.log.LogsBloomFilter; @@ -612,7 +615,7 @@ public Optional transactionLocationByHash(final Hash transa * @return The transaction receipt associated with the referenced transaction. */ public Optional transactionReceiptByTransactionHash( - final Hash transactionHash) { + final Hash transactionHash, final ProtocolSchedule protocolSchedule) { final Optional maybeLocation = blockchain.getTransactionLocation(transactionHash); if (maybeLocation.isEmpty()) { @@ -639,6 +642,12 @@ public Optional transactionReceiptByTransactionH - transactionReceipts.get(location.getTransactionIndex() - 1).getCumulativeGasUsed(); } + Optional maybeBlobGasUsed = + getBlobGasUsed(transaction, protocolSchedule.getByBlockHeader(header)); + + Optional maybeBlobGasPrice = + getBlobGasPrice(transaction, header, protocolSchedule.getByBlockHeader(header)); + return Optional.of( TransactionReceiptWithMetadata.create( transactionReceipt, @@ -648,7 +657,48 @@ public Optional transactionReceiptByTransactionH gasUsed, header.getBaseFee(), blockhash, - header.getNumber())); + header.getNumber(), + maybeBlobGasUsed, + maybeBlobGasPrice)); + } + + /** + * Calculates the blob gas used for data in a transaction. + * + * @param transaction the transaction to calculate the gas for + * @param protocolSpec the protocol specification to use for gas calculation + * @return an Optional containing the blob gas used for data if the transaction type supports + * blobs, otherwise returns an empty Optional + */ + private Optional getBlobGasUsed( + final Transaction transaction, final ProtocolSpec protocolSpec) { + return transaction.getType().supportsBlob() + ? Optional.of(protocolSpec.getGasCalculator().blobGasCost(transaction.getBlobCount())) + : Optional.empty(); + } + + /** + * Calculates the blob gas price for data in a transaction. + * + * @param transaction the transaction to calculate the gas price for + * @param header the block header of the current block + * @param protocolSpec the protocol specification to use for gas price calculation + * @return an Optional containing the blob gas price for data if the transaction type supports + * blobs, otherwise returns an empty Optional + */ + private Optional getBlobGasPrice( + final Transaction transaction, final BlockHeader header, final ProtocolSpec protocolSpec) { + if (transaction.getType().supportsBlob()) { + return blockchain + .getBlockHeader(header.getParentHash()) + .map( + parentHeader -> + protocolSpec + .getFeeMarket() + .blobGasPricePerGas( + calculateExcessBlobGasForParent(protocolSpec, parentHeader))); + } + return Optional.empty(); } /** diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/TransactionReceiptWithMetadata.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/TransactionReceiptWithMetadata.java index 059c7aedc1f..55b85d2678c 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/TransactionReceiptWithMetadata.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/TransactionReceiptWithMetadata.java @@ -30,6 +30,8 @@ public class TransactionReceiptWithMetadata { private final long blockNumber; private final Hash blockHash; private final Transaction transaction; + private final Optional blobGasUsed; + private final Optional blobGasPrice; private TransactionReceiptWithMetadata( final TransactionReceipt receipt, @@ -39,7 +41,9 @@ private TransactionReceiptWithMetadata( final long gasUsed, final Optional baseFee, final Hash blockHash, - final long blockNumber) { + final long blockNumber, + final Optional blobGasUsed, + final Optional blobGasPrice) { this.receipt = receipt; this.transactionHash = transactionHash; this.transactionIndex = transactionIndex; @@ -48,6 +52,8 @@ private TransactionReceiptWithMetadata( this.blockHash = blockHash; this.blockNumber = blockNumber; this.transaction = transaction; + this.blobGasUsed = blobGasUsed; + this.blobGasPrice = blobGasPrice; } public static TransactionReceiptWithMetadata create( @@ -58,7 +64,9 @@ public static TransactionReceiptWithMetadata create( final long gasUsed, final Optional baseFee, final Hash blockHash, - final long blockNumber) { + final long blockNumber, + final Optional blobGasUsed, + final Optional blobGasPrice) { return new TransactionReceiptWithMetadata( receipt, transaction, @@ -67,7 +75,9 @@ public static TransactionReceiptWithMetadata create( gasUsed, baseFee, blockHash, - blockNumber); + blockNumber, + blobGasUsed, + blobGasPrice); } public TransactionReceipt getReceipt() { @@ -103,4 +113,12 @@ public long getGasUsed() { public Optional getBaseFee() { return baseFee; } + + public Optional getBlobGasUsed() { + return blobGasUsed; + } + + public Optional getBlobGasPrice() { + return blobGasPrice; + } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractDataFetcherTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractDataFetcherTest.java index 269cc27f062..0c304fbc3fd 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractDataFetcherTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractDataFetcherTest.java @@ -25,7 +25,7 @@ import graphql.GraphQLContext; import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; -import org.junit.Before; +import org.junit.jupiter.api.BeforeEach; import org.mockito.Mock; import org.mockito.Mockito; @@ -43,7 +43,7 @@ public abstract class AbstractDataFetcherTest { @Mock protected BlockHeader header; - @Before + @BeforeEach public void before() { final GraphQLDataFetchers fetchers = new GraphQLDataFetchers(supportedCapabilities); fetcher = fetchers.getBlockDataFetcher(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java index 01cf7d3bafe..bba69967d52 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java @@ -14,6 +14,9 @@ */ package org.hyperledger.besu.ethereum.api.graphql; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.ImmutableApiConfiguration; @@ -27,16 +30,15 @@ import org.hyperledger.besu.ethereum.eth.EthProtocol; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; import org.hyperledger.besu.plugin.data.SyncStatus; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.testutil.BlockTestUtil; +import java.nio.file.Path; import java.util.Collections; import java.util.HashSet; import java.util.Map; @@ -47,16 +49,15 @@ import io.vertx.core.Vertx; import okhttp3.MediaType; import okhttp3.OkHttpClient; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.io.TempDir; import org.mockito.ArgumentMatchers; import org.mockito.Mockito; public abstract class AbstractEthGraphQLHttpServiceTest { - @ClassRule public static final TemporaryFolder folder = new TemporaryFolder(); + @TempDir private static Path tempDir; private static BlockchainSetupUtil blockchainSetupUtil; @@ -71,7 +72,7 @@ public abstract class AbstractEthGraphQLHttpServiceTest { final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); protected static final MediaType GRAPHQL = MediaType.parse("application/graphql; charset=utf-8"); - @BeforeClass + @BeforeAll public static void setupConstants() { blockchainSetupUtil = BlockchainSetupUtil.createForEthashChain( @@ -79,27 +80,24 @@ public static void setupConstants() { blockchainSetupUtil.importAllBlocks(); } - @Before + @BeforeEach public void setupTest() throws Exception { final Synchronizer synchronizerMock = Mockito.mock(Synchronizer.class); final SyncStatus status = new DefaultSyncStatus(1, 2, 3, Optional.of(4L), Optional.of(5L)); - Mockito.when(synchronizerMock.getSyncStatus()).thenReturn(Optional.of(status)); + when(synchronizerMock.getSyncStatus()).thenReturn(Optional.of(status)); final PoWMiningCoordinator miningCoordinatorMock = Mockito.mock(PoWMiningCoordinator.class); - Mockito.when(miningCoordinatorMock.getMinTransactionGasPrice()).thenReturn(Wei.of(16)); + when(miningCoordinatorMock.getMinTransactionGasPrice()).thenReturn(Wei.of(16)); final TransactionPool transactionPoolMock = Mockito.mock(TransactionPool.class); - Mockito.when(transactionPoolMock.addTransactionViaApi(ArgumentMatchers.any(Transaction.class))) + when(transactionPoolMock.addTransactionViaApi(ArgumentMatchers.any(Transaction.class))) .thenReturn(ValidationResult.valid()); // nonce too low tests uses a tx with nonce=16 - Mockito.when( - transactionPoolMock.addTransactionViaApi( - ArgumentMatchers.argThat(tx -> tx.getNonce() == 16))) + when(transactionPoolMock.addTransactionViaApi( + ArgumentMatchers.argThat(tx -> tx.getNonce() == 16))) .thenReturn(ValidationResult.invalid(TransactionInvalidReason.NONCE_TOO_LOW)); - final PendingTransactions pendingTransactionsMock = Mockito.mock(PendingTransactions.class); - Mockito.when(transactionPoolMock.getPendingTransactions()).thenReturn(pendingTransactionsMock); - Mockito.when(pendingTransactionsMock.getPendingTransactions()) + Mockito.when(transactionPoolMock.getPendingTransactions()) .thenReturn( Collections.singleton( new PendingTransaction.Local( @@ -135,7 +133,7 @@ public void setupTest() throws Exception { service = new GraphQLHttpService( vertx, - folder.newFolder().toPath(), + tempDir, config, graphQL, Map.of( @@ -156,7 +154,7 @@ public void setupTest() throws Exception { baseUrl = service.url() + "/graphql/"; } - @After + @AfterEach public void shutdownServer() { client.dispatcher().executorService().shutdown(); client.connectionPool().evictAll(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/BlockDataFetcherTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/BlockDataFetcherTest.java index b41bb17547c..58689a18fdd 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/BlockDataFetcherTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/BlockDataFetcherTest.java @@ -28,12 +28,12 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentMatchers; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class BlockDataFetcherTest extends AbstractDataFetcherTest { @Test diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/EthGraphQLHttpBySpecTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/EthGraphQLHttpBySpecTest.java index 7beef9c5251..bc1e3c84bc6 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/EthGraphQLHttpBySpecTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/EthGraphQLHttpBySpecTest.java @@ -15,9 +15,7 @@ package org.hyperledger.besu.ethereum.api.graphql; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; +import java.util.stream.Stream; import com.google.common.base.Charsets; import com.google.common.io.Resources; @@ -26,108 +24,78 @@ import okhttp3.RequestBody; import okhttp3.Response; import org.assertj.core.api.Assertions; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public class EthGraphQLHttpBySpecTest extends AbstractEthGraphQLHttpServiceTest { - private final String specFileName; - - public EthGraphQLHttpBySpecTest(final String specFileName) { - this.specFileName = specFileName; - } - - @Parameters(name = "{index}: {0}") - public static Collection specs() { - final List specs = new ArrayList<>(); - - specs.add("eth_blockNumber"); - - specs.add("eth_call_Block8"); - specs.add("eth_call_Block8_invalidHexBytesData"); - specs.add("eth_call_BlockLatest"); - specs.add("eth_call_from_contract"); - - specs.add("eth_estimateGas_transfer"); - specs.add("eth_estimateGas_noParams"); - specs.add("eth_estimateGas_contractDeploy"); - specs.add("eth_estimateGas_from_contract"); - - specs.add("eth_gasPrice"); - - specs.add("eth_getBalance_0x19"); - specs.add("eth_getBalance_invalidAccountBlockNumber"); - specs.add("eth_getBalance_invalidAccountLatest"); - specs.add("eth_getBalance_latest"); - specs.add("eth_getBalance_toobig_bn"); - specs.add("eth_getBalance_without_addr"); - - specs.add("eth_getBlock_byHash"); - specs.add("eth_getBlock_byHash_InvalidHexBytes32Hash"); - specs.add("eth_getBlock_byHashInvalid"); - specs.add("eth_getBlock_byNumber"); - specs.add("eth_getBlock_byNumberInvalid"); - specs.add("eth_getBlock_wrongParams"); - - specs.add("eth_getBlockTransactionCount_byHash"); - specs.add("eth_getBlockTransactionCount_byNumber"); - - specs.add("eth_getCode"); - specs.add("eth_getCode_noCode"); - - specs.add("eth_getLogs_emptyListParam"); - specs.add("eth_getLogs_matchTopic"); - specs.add("eth_getLogs_matchAnyTopic"); - specs.add("eth_getLogs_range"); - - specs.add("eth_getStorageAt"); - specs.add("eth_getStorageAt_illegalRangeGreaterThan"); - - specs.add("eth_getTransaction_byBlockHashAndIndex"); - specs.add("eth_getTransaction_byBlockNumberAndIndex"); - specs.add("eth_getTransaction_byBlockNumberAndInvalidIndex"); - specs.add("eth_getTransaction_byHash"); - specs.add("eth_getTransaction_byHashNull"); - - specs.add("eth_getTransactionCount"); - - specs.add("eth_getTransactionReceipt"); - - specs.add("eth_sendRawTransaction_contractCreation"); - specs.add("eth_sendRawTransaction_messageCall"); - specs.add("eth_sendRawTransaction_nonceTooLow"); - specs.add("eth_sendRawTransaction_transferEther"); - specs.add("eth_sendRawTransaction_unsignedTransaction"); - - specs.add("eth_syncing"); - - specs.add("graphql_blocks_byFrom"); - specs.add("graphql_blocks_byRange"); - specs.add("graphql_blocks_byWrongRange"); - - specs.add("graphql_pending"); - - specs.add("graphql_tooComplex"); - specs.add("graphql_tooComplexSchema"); - - specs.add("graphql_variable_address"); - specs.add("graphql_variable_bytes"); - specs.add("graphql_variable_bytes32"); - specs.add("graphql_variable_long"); - - specs.add("block_withdrawals_pre_shanghai"); - specs.add("block_withdrawals"); - specs.add("eth_getTransaction_type2"); - specs.add("eth_getBlock_shanghai"); - - return specs; + public static Stream specs() { + return Stream.of( + Arguments.of("eth_blockNumber"), + Arguments.of("eth_call_Block8"), + Arguments.of("eth_call_Block8_invalidHexBytesData"), + Arguments.of("eth_call_BlockLatest"), + Arguments.of("eth_call_from_contract"), + Arguments.of("eth_estimateGas_transfer"), + Arguments.of("eth_estimateGas_noParams"), + Arguments.of("eth_estimateGas_contractDeploy"), + Arguments.of("eth_estimateGas_from_contract"), + Arguments.of("eth_gasPrice"), + Arguments.of("eth_getBalance_0x19"), + Arguments.of("eth_getBalance_invalidAccountBlockNumber"), + Arguments.of("eth_getBalance_invalidAccountLatest"), + Arguments.of("eth_getBalance_latest"), + Arguments.of("eth_getBalance_toobig_bn"), + Arguments.of("eth_getBalance_without_addr"), + Arguments.of("eth_getBlock_byHash"), + Arguments.of("eth_getBlock_byHash_InvalidHexBytes32Hash"), + Arguments.of("eth_getBlock_byHashInvalid"), + Arguments.of("eth_getBlock_byNumber"), + Arguments.of("eth_getBlock_byNumberInvalid"), + Arguments.of("eth_getBlock_wrongParams"), + Arguments.of("eth_getBlockTransactionCount_byHash"), + Arguments.of("eth_getBlockTransactionCount_byNumber"), + Arguments.of("eth_getCode"), + Arguments.of("eth_getCode_noCode"), + Arguments.of("eth_getLogs_emptyListParam"), + Arguments.of("eth_getLogs_matchTopic"), + Arguments.of("eth_getLogs_matchAnyTopic"), + Arguments.of("eth_getLogs_range"), + Arguments.of("eth_getStorageAt"), + Arguments.of("eth_getStorageAt_illegalRangeGreaterThan"), + Arguments.of("eth_getTransaction_byBlockHashAndIndex"), + Arguments.of("eth_getTransaction_byBlockNumberAndIndex"), + Arguments.of("eth_getTransaction_byBlockNumberAndInvalidIndex"), + Arguments.of("eth_getTransaction_byHash"), + Arguments.of("eth_getTransaction_byHashNull"), + Arguments.of("eth_getTransactionCount"), + Arguments.of("eth_getTransactionReceipt"), + Arguments.of("eth_sendRawTransaction_contractCreation"), + Arguments.of("eth_sendRawTransaction_messageCall"), + Arguments.of("eth_sendRawTransaction_nonceTooLow"), + Arguments.of("eth_sendRawTransaction_transferEther"), + Arguments.of("eth_sendRawTransaction_unsignedTransaction"), + Arguments.of("eth_syncing"), + Arguments.of("graphql_blocks_byFrom"), + Arguments.of("graphql_blocks_byRange"), + Arguments.of("graphql_blocks_byWrongRange"), + Arguments.of("graphql_pending"), + Arguments.of("graphql_tooComplex"), + Arguments.of("graphql_tooComplexSchema"), + Arguments.of("graphql_variable_address"), + Arguments.of("graphql_variable_bytes"), + Arguments.of("graphql_variable_bytes32"), + Arguments.of("graphql_variable_long"), + Arguments.of("block_withdrawals_pre_shanghai"), + Arguments.of("block_withdrawals"), + Arguments.of("eth_getTransaction_type2"), + Arguments.of("eth_getBlock_shanghai")); } - @Test - public void graphQLCallWithSpecFile() throws Exception { + @ParameterizedTest(name = "{index}: {0}") + @MethodSource("specs") + public void graphQLCallWithSpecFile(final String specFileName) throws Exception { graphQLCall(specFileName); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLConfigurationTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLConfigurationTest.java index 09b84b1e87a..6ea243097b6 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLConfigurationTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLConfigurationTest.java @@ -16,7 +16,7 @@ import static org.assertj.core.api.Assertions.assertThat; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class GraphQLConfigurationTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceHostWhitelistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceHostWhitelistTest.java index fbee1785a31..5b083a79580 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceHostWhitelistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceHostWhitelistTest.java @@ -23,6 +23,7 @@ import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability; import java.io.IOException; +import java.nio.file.Path; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; @@ -37,16 +38,15 @@ import okhttp3.Request; import okhttp3.RequestBody; import org.assertj.core.api.Assertions; -import org.junit.After; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import org.mockito.Mockito; public class GraphQLHttpServiceHostWhitelistTest { - @ClassRule public static final TemporaryFolder folder = new TemporaryFolder(); + @TempDir private static Path folder; protected static Vertx vertx; @@ -57,7 +57,7 @@ public class GraphQLHttpServiceHostWhitelistTest { private final GraphQLConfiguration graphQLConfig = createGraphQLConfig(); private final List hostsWhitelist = Arrays.asList("ally", "friend"); - @Before + @BeforeEach public void initServerAndClient() throws Exception { vertx = Vertx.vertx(); @@ -92,12 +92,7 @@ private GraphQLHttpService createGraphQLHttpService() throws Exception { final GraphQL graphQL = GraphQLProvider.buildGraphQL(dataFetchers); return new GraphQLHttpService( - vertx, - folder.newFolder().toPath(), - graphQLConfig, - graphQL, - graphQLContextMap, - Mockito.mock(EthScheduler.class)); + vertx, folder, graphQLConfig, graphQL, graphQLContextMap, Mockito.mock(EthScheduler.class)); } private static GraphQLConfiguration createGraphQLConfig() { @@ -106,7 +101,7 @@ private static GraphQLConfiguration createGraphQLConfig() { return config; } - @After + @AfterEach public void shutdownServer() { client.dispatcher().executorService().shutdown(); client.connectionPool().evictAll(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceTest.java index 59aaff11d32..b5d0463883b 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceTest.java @@ -31,6 +31,7 @@ import java.net.InetSocketAddress; import java.net.URL; +import java.nio.file.Path; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -49,17 +50,16 @@ import okhttp3.Response; import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Assertions; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import org.mockito.ArgumentMatchers; import org.mockito.Mockito; public class GraphQLHttpServiceTest { - @ClassRule public static final TemporaryFolder folder = new TemporaryFolder(); + @TempDir private static Path folder; private static final Vertx vertx = Vertx.vertx(); @@ -75,7 +75,7 @@ public class GraphQLHttpServiceTest { private final GraphQLTestHelper testHelper = new GraphQLTestHelper(); - @BeforeClass + @BeforeAll public static void initServerAndClient() throws Exception { blockchainQueries = Mockito.mock(BlockchainQueries.class); final Synchronizer synchronizer = Mockito.mock(Synchronizer.class); @@ -109,18 +109,13 @@ public static void initServerAndClient() throws Exception { private static GraphQLHttpService createGraphQLHttpService(final GraphQLConfiguration config) throws Exception { return new GraphQLHttpService( - vertx, - folder.newFolder().toPath(), - config, - graphQL, - graphQlContextMap, - Mockito.mock(EthScheduler.class)); + vertx, folder, config, graphQL, graphQlContextMap, Mockito.mock(EthScheduler.class)); } private static GraphQLHttpService createGraphQLHttpService() throws Exception { return new GraphQLHttpService( vertx, - folder.newFolder().toPath(), + folder, createGraphQLConfig(), graphQL, graphQlContextMap, @@ -133,7 +128,7 @@ private static GraphQLConfiguration createGraphQLConfig() { return config; } - @BeforeClass + @BeforeAll public static void setupConstants() { final URL blocksUrl = BlockTestUtil.getTestBlockchainUrl(); @@ -144,7 +139,7 @@ public static void setupConstants() { } /** Tears down the HTTP server. */ - @AfterClass + @AfterAll public static void shutdownServer() { client.dispatcher().executorService().shutdown(); client.connectionPool().evictAll(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/AddressScalarTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/AddressScalarTest.java index b6f97889264..3c73f8c8e74 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/AddressScalarTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/AddressScalarTest.java @@ -30,8 +30,8 @@ import graphql.schema.CoercingParseValueException; import graphql.schema.CoercingSerializeException; import graphql.schema.GraphQLScalarType; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class AddressScalarTest { @@ -125,7 +125,7 @@ public void parseLiteralErrorTest2() { .isInstanceOf(CoercingParseLiteralException.class); } - @Before + @BeforeEach public void before() { scalar = Scalars.addressScalar(); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/BigIntScalarTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/BigIntScalarTest.java index d1c4751bd94..be754521c06 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/BigIntScalarTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/BigIntScalarTest.java @@ -30,8 +30,8 @@ import graphql.schema.CoercingSerializeException; import graphql.schema.GraphQLScalarType; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class BigIntScalarTest { @@ -109,7 +109,7 @@ public void parseLiteralErrorTest2() { .isInstanceOf(CoercingParseLiteralException.class); } - @Before + @BeforeEach public void before() { scalar = Scalars.bigIntScalar(); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/Bytes32ScalarTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/Bytes32ScalarTest.java index 4583ecac365..165a8afc422 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/Bytes32ScalarTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/Bytes32ScalarTest.java @@ -30,8 +30,8 @@ import graphql.schema.CoercingSerializeException; import graphql.schema.GraphQLScalarType; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class Bytes32ScalarTest { @@ -121,7 +121,7 @@ public void parseLiteralErrorTest2() { .isInstanceOf(CoercingParseLiteralException.class); } - @Before + @BeforeEach public void before() { scalar = Scalars.bytes32Scalar(); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/BytesScalarTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/BytesScalarTest.java index ae7204833b6..711dec53442 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/BytesScalarTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/BytesScalarTest.java @@ -30,8 +30,8 @@ import graphql.schema.CoercingSerializeException; import graphql.schema.GraphQLScalarType; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class BytesScalarTest { @@ -121,7 +121,7 @@ public void parseLiteralErrorTest2() { .isInstanceOf(CoercingParseLiteralException.class); } - @Before + @BeforeEach public void before() { scalar = Scalars.bytesScalar(); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/LongScalarTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/LongScalarTest.java index 3a0861fa84e..6658ac208d5 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/LongScalarTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/LongScalarTest.java @@ -28,8 +28,8 @@ import graphql.schema.CoercingParseValueException; import graphql.schema.CoercingSerializeException; import graphql.schema.GraphQLScalarType; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class LongScalarTest { @@ -140,7 +140,7 @@ public void parseLiteralErrorTest2() { .isInstanceOf(CoercingParseLiteralException.class); } - @Before + @BeforeEach public void before() { scalar = Scalars.longScalar(); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpBySpecTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpBySpecTest.java index 4bb9fb11479..eb924bd8eba 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpBySpecTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpBySpecTest.java @@ -44,11 +44,9 @@ import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public abstract class AbstractJsonRpcHttpBySpecTest extends AbstractJsonRpcHttpServiceTest { private static final ObjectMapper objectMapper = new ObjectMapper(); @@ -59,15 +57,13 @@ public abstract class AbstractJsonRpcHttpBySpecTest extends AbstractJsonRpcHttpS private static final Pattern GAS_MATCH_FOR_TRACE = Pattern.compile("\"gasUsed\":\"[x0-9a-fA-F]+\","); - private final URL specURL; + private URL specURL; - protected AbstractJsonRpcHttpBySpecTest(final String specName, final URL specURL) { + @ParameterizedTest(name = "{index}: {0}") + @MethodSource("specs") + public void jsonRPCCallWithSpecFile(final String specName, final URL specURL) throws Exception { this.specURL = specURL; - } - - @Test - public void jsonRPCCallWithSpecFile() throws Exception { - jsonRPCCall(specURL); + jsonRPCCall(this.specURL); } /** diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java index 1b7a536d0b5..d998f54c7e4 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java @@ -38,7 +38,6 @@ import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.EthProtocol; import org.hyperledger.besu.ethereum.eth.manager.EthPeers; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork; @@ -52,6 +51,7 @@ import java.math.BigInteger; import java.net.URL; +import java.nio.file.Path; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; @@ -64,13 +64,12 @@ import io.vertx.core.VertxOptions; import okhttp3.MediaType; import okhttp3.OkHttpClient; -import org.junit.After; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.io.TempDir; public abstract class AbstractJsonRpcHttpServiceTest { - @ClassRule public static final TemporaryFolder folder = new TemporaryFolder(); + @TempDir private Path folder; protected BlockchainSetupUtil blockchainSetupUtil; @@ -116,7 +115,7 @@ protected BlockchainSetupUtil createBlockchainSetupUtil( new ChainResources(genesisURL, blocksURL), storageFormat); } - @Before + @BeforeEach public void setup() throws Exception { setupBlockchain(); } @@ -140,8 +139,6 @@ protected Map getRpcMethods( // nonce too low tests uses a tx with nonce=16 when(transactionPoolMock.addTransactionViaApi(argThat(tx -> tx.getNonce() == 16))) .thenReturn(ValidationResult.invalid(TransactionInvalidReason.NONCE_TOO_LOW)); - final PendingTransactions pendingTransactionsMock = mock(PendingTransactions.class); - when(transactionPoolMock.getPendingTransactions()).thenReturn(pendingTransactionsMock); final PrivacyParameters privacyParameters = mock(PrivacyParameters.class); final BlockchainQueries blockchainQueries = @@ -188,7 +185,7 @@ protected Map getRpcMethods( mock(MetricsConfiguration.class), natService, new HashMap<>(), - folder.getRoot().toPath(), + folder, mock(EthPeers.class), syncVertx, Optional.empty(), @@ -210,7 +207,7 @@ private void startService(final BlockchainSetupUtil blockchainSetupUtil) throws service = new JsonRpcHttpService( vertx, - folder.newFolder().toPath(), + folder, config, new NoOpMetricsSystem(), natService, @@ -223,7 +220,7 @@ private void startService(final BlockchainSetupUtil blockchainSetupUtil) throws baseUrl = service.url(); } - @After + @AfterEach public void shutdownServer() { client.dispatcher().executorService().shutdown(); client.connectionPool().evictAll(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AdminJsonRpcHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AdminJsonRpcHttpServiceTest.java index 3b2497d18e7..061d2a2d6a3 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AdminJsonRpcHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AdminJsonRpcHttpServiceTest.java @@ -37,15 +37,15 @@ import okhttp3.RequestBody; import okhttp3.Response; import org.apache.tuweni.bytes.Bytes; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class AdminJsonRpcHttpServiceTest extends JsonRpcHttpServiceTestBase { private static final Logger LOG = LoggerFactory.getLogger(AdminJsonRpcHttpServiceTest.class); - @BeforeClass + @BeforeAll public static void setup() throws Exception { initServerAndClient(); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonResponseStreamerTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonResponseStreamerTest.java index 3e3f8efc152..67e692de2e7 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonResponseStreamerTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonResponseStreamerTest.java @@ -29,14 +29,17 @@ import io.vertx.core.impl.future.FailedFuture; import io.vertx.core.impl.future.SucceededFuture; import io.vertx.core.net.SocketAddress; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentMatcher; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class JsonResponseStreamerTest { private final SocketAddress testAddress = SocketAddress.domainSocketAddress("test"); @@ -44,7 +47,7 @@ public class JsonResponseStreamerTest { @Mock private HttpServerResponse failedResponse; - @Before + @BeforeEach public void before() { when(httpResponse.write(any(Buffer.class))).thenReturn(new SucceededFuture<>(null, null)); when(failedResponse.write(any(Buffer.class))) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcConfigurationTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcConfigurationTest.java index d912193b9fc..079aa7907d7 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcConfigurationTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcConfigurationTest.java @@ -22,7 +22,7 @@ import java.util.Optional; import com.google.common.collect.Lists; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class JsonRpcConfigurationTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java index 226197c5deb..961970615fb 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java @@ -44,6 +44,8 @@ import java.io.IOException; import java.math.BigInteger; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -59,15 +61,14 @@ import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; -import org.junit.After; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; public class JsonRpcHttpServiceHostAllowlistTest { - @ClassRule public static final TemporaryFolder folder = new TemporaryFolder(); + @TempDir private Path folder; protected static final Vertx vertx = Vertx.vertx(); @@ -84,7 +85,7 @@ public class JsonRpcHttpServiceHostAllowlistTest { private final List hostsAllowlist = Arrays.asList("ally", "friend"); - @Before + @BeforeEach public void initServerAndClient() throws Exception { final P2PNetwork peerDiscoveryMock = mock(P2PNetwork.class); final BlockchainQueries blockchainQueries = mock(BlockchainQueries.class); @@ -121,7 +122,7 @@ public void initServerAndClient() throws Exception { mock(MetricsConfiguration.class), natService, new HashMap<>(), - folder.getRoot().toPath(), + folder, mock(EthPeers.class), vertx, Optional.empty(), @@ -136,7 +137,7 @@ public void initServerAndClient() throws Exception { private JsonRpcHttpService createJsonRpcHttpService() throws Exception { return new JsonRpcHttpService( vertx, - folder.newFolder().toPath(), + Files.createTempDirectory(folder, "tempDir"), jsonRpcConfig, new NoOpMetricsSystem(), natService, @@ -151,7 +152,7 @@ private static JsonRpcConfiguration createJsonRpcConfig() { return config; } - @After + @AfterEach public void shutdownServer() { service.stop().join(); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java index 5d7e3391d04..481aedd8ad7 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java @@ -49,6 +49,7 @@ import java.io.IOException; import java.math.BigInteger; +import java.nio.file.Path; import java.nio.file.Paths; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; @@ -77,18 +78,17 @@ import okhttp3.RequestBody; import okhttp3.Response; import org.assertj.core.api.Assertions; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.StrictStubs.class) +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) public class JsonRpcHttpServiceLoginTest { - @ClassRule public static final TemporaryFolder folder = new TemporaryFolder(); + @TempDir private static Path folder; private static final Vertx vertx = Vertx.vertx(); @@ -112,7 +112,7 @@ public class JsonRpcHttpServiceLoginTest { protected final JsonRpcTestHelper testHelper = new JsonRpcTestHelper(); protected static final NatService natService = new NatService(Optional.empty()); - @BeforeClass + @BeforeAll public static void initServerAndClient() throws Exception { peerDiscoveryMock = mock(P2PNetwork.class); blockchainQueries = mock(BlockchainQueries.class); @@ -151,7 +151,7 @@ public static void initServerAndClient() throws Exception { mock(MetricsConfiguration.class), natService, new HashMap<>(), - folder.getRoot().toPath(), + folder, mock(EthPeers.class), vertx, Optional.empty(), @@ -178,7 +178,7 @@ private static JsonRpcHttpService createJsonRpcHttpService() throws Exception { return new JsonRpcHttpService( vertx, - folder.newFolder().toPath(), + folder, config, new NoOpMetricsSystem(), natService, @@ -195,7 +195,7 @@ private static JsonRpcConfiguration createJsonRpcConfig() { } /** Tears down the HTTP server. */ - @AfterClass + @AfterAll public static void shutdownServer() { service.stop().join(); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceParameterizedTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceParameterizedTest.java index f61986ff5c1..cbbd478100a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceParameterizedTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceParameterizedTest.java @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import java.util.Arrays; import java.util.Collection; @@ -24,45 +25,37 @@ import io.vertx.core.json.JsonObject; import okhttp3.RequestBody; import okhttp3.Response; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public class JsonRpcHttpServiceParameterizedTest extends JsonRpcHttpServiceTestBase { - private final String requestJson; - - public JsonRpcHttpServiceParameterizedTest(final String requestJson) { - this.requestJson = requestJson; - } - - @BeforeClass + @BeforeAll public static void setup() throws Exception { initServerAndClient(); } /** Tears down the HTTP server. */ - @AfterClass + @AfterAll public static void shutdownServer() { service.stop().join(); } - @Parameterized.Parameters public static Collection data() { return Arrays.asList(new Object[][] {{"\"a string\""}, {"a string"}, {"{bla"}, {""}}); } - @Test - public void invalidJsonShouldReturnParseError() throws Exception { + @ParameterizedTest + @MethodSource("data") + public void invalidJsonShouldReturnParseError(final String requestJson) throws Exception { final RequestBody body = RequestBody.create(requestJson, JSON); try (final Response resp = client.newCall(buildPostRequest(body)).execute()) { assertThat(resp.code()).isEqualTo(400); final JsonObject json = new JsonObject(resp.body().string()); - final JsonRpcError expectedError = JsonRpcError.PARSE_ERROR; + final JsonRpcError expectedError = new JsonRpcError(RpcErrorType.PARSE_ERROR); testHelper.assertValidJsonRpcError( json, null, expectedError.getCode(), expectedError.getMessage()); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java index 06d428ab348..52b942b7238 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java @@ -27,7 +27,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.health.HealthService; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethodsFactory; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; @@ -157,7 +157,7 @@ public void requestWithNetMethodShouldSuccessWithCode200WhenNetApiIsNotEnabled() assertThat(resp.code()).isEqualTo(200); // Check general format of result final JsonObject json = new JsonObject(resp.body().string()); - final JsonRpcError expectedError = JsonRpcError.METHOD_NOT_ENABLED; + final RpcErrorType expectedError = RpcErrorType.METHOD_NOT_ENABLED; testHelper.assertValidJsonRpcError( json, id, expectedError.getCode(), expectedError.getMessage()); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTest.java index 759426f3d83..f9c9b14ccd0 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTest.java @@ -27,7 +27,7 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.api.util.TestJsonRpcMethodsUtil; @@ -58,14 +58,14 @@ import okhttp3.Response; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatchers; public class JsonRpcHttpServiceTest extends JsonRpcHttpServiceTestBase { - @BeforeClass + @BeforeAll public static void setup() throws Exception { initServerAndClient(); } @@ -78,7 +78,7 @@ protected static JsonRpcConfiguration createJsonRpcConfig() { } /** Tears down the HTTP server. */ - @AfterClass + @AfterAll public static void shutdownServer() { service.stop().join(); } @@ -762,7 +762,7 @@ public void getBlockByHashWithMissingHashParameter() throws Exception { assertThat(resp.code()).isEqualTo(200); // Check general format of result final JsonObject json = new JsonObject(resp.body().string()); - final JsonRpcError expectedError = JsonRpcError.INVALID_PARAMS; + final RpcErrorType expectedError = RpcErrorType.INVALID_PARAMS; testHelper.assertValidJsonRpcError( json, id, expectedError.getCode(), expectedError.getMessage()); } @@ -786,7 +786,7 @@ public void getBlockByHashWithMissingBooleanParameter() throws Exception { assertThat(resp.code()).isEqualTo(200); // Check general format of result final JsonObject json = new JsonObject(resp.body().string()); - final JsonRpcError expectedError = JsonRpcError.INVALID_PARAMS; + final RpcErrorType expectedError = RpcErrorType.INVALID_PARAMS; testHelper.assertValidJsonRpcError( json, id, expectedError.getCode(), expectedError.getMessage()); } @@ -809,7 +809,7 @@ public void getBlockByHashWithInvalidHashParameterWithOddLength() throws Excepti assertThat(resp.code()).isEqualTo(200); // Check general format of result final JsonObject json = new JsonObject(resp.body().string()); - final JsonRpcError expectedError = JsonRpcError.INVALID_PARAMS; + final RpcErrorType expectedError = RpcErrorType.INVALID_PARAMS; testHelper.assertValidJsonRpcError( json, id, expectedError.getCode(), expectedError.getMessage()); } @@ -832,7 +832,7 @@ public void getBlockByHashWithInvalidHashParameterThatIsTooShort() throws Except assertThat(resp.code()).isEqualTo(200); // Check general format of result final JsonObject json = new JsonObject(resp.body().string()); - final JsonRpcError expectedError = JsonRpcError.INVALID_PARAMS; + final RpcErrorType expectedError = RpcErrorType.INVALID_PARAMS; testHelper.assertValidJsonRpcError( json, id, expectedError.getCode(), expectedError.getMessage()); } @@ -856,7 +856,7 @@ public void getBlockByHashWithInvalidBooleanParameter() throws Exception { assertThat(resp.code()).isEqualTo(200); // Check general format of result final JsonObject json = new JsonObject(resp.body().string()); - final JsonRpcError expectedError = JsonRpcError.INVALID_PARAMS; + final RpcErrorType expectedError = RpcErrorType.INVALID_PARAMS; testHelper.assertValidJsonRpcError( json, id, expectedError.getCode(), expectedError.getMessage()); } @@ -876,7 +876,7 @@ public void getBlockByHashWithAllParametersMissing() throws Exception { assertThat(resp.code()).isEqualTo(200); // Check general format of result final JsonObject json = new JsonObject(resp.body().string()); - final JsonRpcError expectedError = JsonRpcError.INVALID_PARAMS; + final RpcErrorType expectedError = RpcErrorType.INVALID_PARAMS; testHelper.assertValidJsonRpcError( json, id, expectedError.getCode(), expectedError.getMessage()); } @@ -896,7 +896,7 @@ public void getBlockByHashWithNoParameters() throws Exception { assertThat(resp.code()).isEqualTo(200); // Check general format of result final JsonObject json = new JsonObject(resp.body().string()); - final JsonRpcError expectedError = JsonRpcError.INVALID_PARAMS; + final RpcErrorType expectedError = RpcErrorType.INVALID_PARAMS; testHelper.assertValidJsonRpcError( json, id, expectedError.getCode(), expectedError.getMessage()); } @@ -982,7 +982,7 @@ public void getBlockByNumberForInvalidBlockParameter() throws Exception { // Check general format of result final String respBody = resp.body().string(); final JsonObject json = new JsonObject(respBody); - final JsonRpcError expectedError = JsonRpcError.INVALID_PARAMS; + final RpcErrorType expectedError = RpcErrorType.INVALID_PARAMS; testHelper.assertValidJsonRpcError( json, id, expectedError.getCode(), expectedError.getMessage()); } @@ -1304,7 +1304,7 @@ public void objectId() throws Exception { try (final Response resp = client.newCall(buildPostRequest(body)).execute()) { assertThat(resp.code()).isEqualTo(400); final JsonObject json = new JsonObject(resp.body().string()); - final JsonRpcError expectedError = JsonRpcError.INVALID_REQUEST; + final RpcErrorType expectedError = RpcErrorType.INVALID_REQUEST; testHelper.assertValidJsonRpcError( json, null, expectedError.getCode(), expectedError.getMessage()); } @@ -1319,7 +1319,7 @@ public void arrayId() throws Exception { try (final Response resp = client.newCall(buildPostRequest(body)).execute()) { assertThat(resp.code()).isEqualTo(400); final JsonObject json = new JsonObject(resp.body().string()); - final JsonRpcError expectedError = JsonRpcError.INVALID_REQUEST; + final RpcErrorType expectedError = RpcErrorType.INVALID_REQUEST; testHelper.assertValidJsonRpcError( json, null, expectedError.getCode(), expectedError.getMessage()); } @@ -1334,7 +1334,7 @@ public void missingMethodField() throws Exception { try (final Response resp = client.newCall(buildPostRequest(body)).execute()) { assertThat(resp.code()).isEqualTo(400); final JsonObject json = new JsonObject(resp.body().string()); - final JsonRpcError expectedError = JsonRpcError.INVALID_REQUEST; + final RpcErrorType expectedError = RpcErrorType.INVALID_REQUEST; testHelper.assertValidJsonRpcError( json, id, expectedError.getCode(), expectedError.getMessage()); } @@ -1369,7 +1369,7 @@ public void unknownMethod() throws Exception { try (final Response resp = client.newCall(buildPostRequest(body)).execute()) { assertThat(resp.code()).isEqualTo(200); final JsonObject json = new JsonObject(resp.body().string()); - final JsonRpcError expectedError = JsonRpcError.METHOD_NOT_FOUND; + final RpcErrorType expectedError = RpcErrorType.METHOD_NOT_FOUND; testHelper.assertValidJsonRpcError( json, id, expectedError.getCode(), expectedError.getMessage()); } @@ -1395,7 +1395,7 @@ public void disabledMethod() throws Exception { try (final Response resp = client.newCall(buildPostRequest(body)).execute()) { assertThat(resp.code()).isEqualTo(200); final JsonObject json = new JsonObject(resp.body().string()); - final JsonRpcError expectedError = JsonRpcError.METHOD_NOT_ENABLED; + final RpcErrorType expectedError = RpcErrorType.METHOD_NOT_ENABLED; testHelper.assertValidJsonRpcError( json, id, expectedError.getCode(), expectedError.getMessage()); } @@ -1420,7 +1420,7 @@ public void exceptionallyHandleJsonSingleRequest() throws Exception { try (final Response resp = client.newCall(buildPostRequest(body)).execute()) { assertThat(resp.code()).isEqualTo(200); final JsonObject json = new JsonObject(resp.body().string()); - final JsonRpcError expectedError = JsonRpcError.INTERNAL_ERROR; + final RpcErrorType expectedError = RpcErrorType.INTERNAL_ERROR; testHelper.assertValidJsonRpcError( json, "666", expectedError.getCode(), expectedError.getMessage()); } @@ -1444,7 +1444,7 @@ public void exceptionallyHandleJsonBatchRequest() throws Exception { assertThat(resp.code()).isEqualTo(200); final JsonArray array = new JsonArray(resp.body().string()); testHelper.assertValidJsonRpcResult(array.getJsonObject(0), "000"); - final JsonRpcError expectedError = JsonRpcError.INTERNAL_ERROR; + final RpcErrorType expectedError = RpcErrorType.INTERNAL_ERROR; testHelper.assertValidJsonRpcError( array.getJsonObject(1), "111", expectedError.getCode(), expectedError.getMessage()); testHelper.assertValidJsonRpcResult(array.getJsonObject(2), "222"); @@ -1488,7 +1488,7 @@ public void batchRequest() throws Exception { // Check result unknown method final JsonObject jsonError = responses.get(brokenRequestId); - final JsonRpcError expectedError = JsonRpcError.METHOD_NOT_FOUND; + final RpcErrorType expectedError = RpcErrorType.METHOD_NOT_FOUND; testHelper.assertValidJsonRpcError( jsonError, brokenRequestId, expectedError.getCode(), expectedError.getMessage()); @@ -1543,7 +1543,7 @@ public void batchRequestContainingInvalidRequest() throws Exception { // Check invalid request final JsonObject jsonError = responses.get(invalidId); - final JsonRpcError expectedError = JsonRpcError.INVALID_REQUEST; + final RpcErrorType expectedError = RpcErrorType.INVALID_REQUEST; testHelper.assertValidJsonRpcError( jsonError, null, expectedError.getCode(), expectedError.getMessage()); @@ -1567,7 +1567,7 @@ public void batchRequestParseError() throws Exception { try (final Response resp = client.newCall(buildPostRequest(body)).execute()) { assertThat(resp.code()).isEqualTo(400); final JsonObject json = new JsonObject(resp.body().string()); - final JsonRpcError expectedError = JsonRpcError.PARSE_ERROR; + final RpcErrorType expectedError = RpcErrorType.PARSE_ERROR; testHelper.assertValidJsonRpcError( json, null, expectedError.getCode(), expectedError.getMessage()); } @@ -1624,7 +1624,7 @@ public void emptyBatchRequest() throws Exception { try (final Response resp = client.newCall(buildPostRequest(body)).execute()) { assertThat(resp.code()).isEqualTo(400); final JsonObject json = new JsonObject(resp.body().string()); - final JsonRpcError expectedError = JsonRpcError.INVALID_REQUEST; + final RpcErrorType expectedError = RpcErrorType.INVALID_REQUEST; testHelper.assertValidJsonRpcError( json, null, expectedError.getCode(), expectedError.getMessage()); } @@ -2032,7 +2032,7 @@ public void ethGetStorageAtInvalidParameterStorageIndex() throws Exception { assertThat(resp.code()).isEqualTo(200); // Check general format of result final JsonObject json = new JsonObject(resp.body().string()); - final JsonRpcError expectedError = JsonRpcError.INVALID_PARAMS; + final RpcErrorType expectedError = RpcErrorType.INVALID_PARAMS; testHelper.assertValidJsonRpcError( json, id, expectedError.getCode(), expectedError.getMessage()); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java index 0b3b9441dc8..94ec09b2367 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java @@ -45,6 +45,7 @@ import org.hyperledger.besu.nat.NatService; import java.math.BigInteger; +import java.nio.file.Path; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -59,13 +60,12 @@ import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; -import org.junit.AfterClass; -import org.junit.ClassRule; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.io.TempDir; public class JsonRpcHttpServiceTestBase { - @ClassRule public static final TemporaryFolder folder = new TemporaryFolder(); + @TempDir private static Path folder; protected final JsonRpcTestHelper testHelper = new JsonRpcTestHelper(); private static final Vertx vertx = Vertx.vertx(); @@ -130,7 +130,7 @@ public static void initServerAndClient() throws Exception { mock(MetricsConfiguration.class), natService, new HashMap<>(), - folder.getRoot().toPath(), + folder, ethPeersMock, vertx, Optional.empty(), @@ -147,7 +147,7 @@ protected static JsonRpcHttpService createJsonRpcHttpService(final JsonRpcConfig throws Exception { return new JsonRpcHttpService( vertx, - folder.newFolder().toPath(), + folder, config, new NoOpMetricsSystem(), natService, @@ -159,7 +159,7 @@ protected static JsonRpcHttpService createJsonRpcHttpService(final JsonRpcConfig protected static JsonRpcHttpService createJsonRpcHttpService() throws Exception { return new JsonRpcHttpService( vertx, - folder.newFolder().toPath(), + folder, createLimitedJsonRpcConfig(), new NoOpMetricsSystem(), natService, @@ -186,7 +186,7 @@ protected Request buildGetRequest(final String path) { } /** Tears down the HTTP server. */ - @AfterClass + @AfterAll public static void shutdownServer() { service.stop().join(); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java index fcbfb399d16..75612fa1fb8 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java @@ -71,14 +71,13 @@ import okhttp3.Response; import okhttp3.ResponseBody; import org.assertj.core.api.Assertions; -import org.junit.After; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; public class JsonRpcHttpServiceTlsClientAuthTest { - @ClassRule public static final TemporaryFolder folder = new TemporaryFolder(); + @TempDir private static Path folder; protected static final Vertx vertx = Vertx.vertx(); @@ -99,7 +98,7 @@ public class JsonRpcHttpServiceTlsClientAuthTest { private final FileBasedPasswordProvider fileBasedPasswordProvider = new FileBasedPasswordProvider(createPasswordFile(besuCertificate)); - @Before + @BeforeEach public void initServer() throws Exception { final P2PNetwork peerDiscoveryMock = mock(P2PNetwork.class); final BlockchainQueries blockchainQueries = mock(BlockchainQueries.class); @@ -136,7 +135,7 @@ public void initServer() throws Exception { mock(MetricsConfiguration.class), natService, Collections.emptyMap(), - folder.getRoot().toPath(), + folder, mock(EthPeers.class), vertx, Optional.empty(), @@ -155,7 +154,7 @@ private JsonRpcHttpService createJsonRpcHttpService(final JsonRpcConfiguration j throws Exception { return new JsonRpcHttpService( vertx, - folder.newFolder().toPath(), + folder, jsonRpcConfig, new NoOpMetricsSystem(), natService, @@ -217,13 +216,13 @@ private Path createPasswordFile(final SelfSignedP12Certificate selfSignedP12Cert private Path createTempFile() { try { - return folder.newFile().toPath(); + return Files.createTempFile(folder, "newFile", ""); } catch (IOException e) { throw new UncheckedIOException(e); } } - @After + @AfterEach public void shutdownServer() { System.clearProperty("javax.net.ssl.trustStore"); System.clearProperty("javax.net.ssl.trustStorePassword"); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java index 1e6d1f169cf..6e1ade32850 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java @@ -194,7 +194,7 @@ void exceptionRaisedWhenInvalidKeystoreFileIsSpecified() throws IOException { Assertions.fail("service.start should have failed"); }) .withCauseInstanceOf(JsonRpcServiceException.class) - .withMessageContaining("Short read of DER length"); + .withMessageContaining("Tag number over 30 is not supported"); } @Test diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java index f45410cc9c8..853412376c7 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java @@ -68,14 +68,13 @@ import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; -import org.junit.After; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; public class JsonRpcHttpServiceTlsTest { - @ClassRule public static final TemporaryFolder folder = new TemporaryFolder(); + @TempDir private Path folder; protected static final Vertx vertx = Vertx.vertx(); @@ -89,7 +88,7 @@ public class JsonRpcHttpServiceTlsTest { private final JsonRpcTestHelper testHelper = new JsonRpcTestHelper(); private final SelfSignedP12Certificate besuCertificate = SelfSignedP12Certificate.create(); - @Before + @BeforeEach public void initServer() throws Exception { final P2PNetwork peerDiscoveryMock = mock(P2PNetwork.class); final BlockchainQueries blockchainQueries = mock(BlockchainQueries.class); @@ -126,7 +125,7 @@ public void initServer() throws Exception { mock(MetricsConfiguration.class), natService, Collections.emptyMap(), - folder.getRoot().toPath(), + folder, mock(EthPeers.class), vertx, Optional.empty(), @@ -140,7 +139,7 @@ private JsonRpcHttpService createJsonRpcHttpService(final JsonRpcConfiguration j throws Exception { return new JsonRpcHttpService( vertx, - folder.newFolder().toPath(), + Files.createTempDirectory(folder, "newFolder"), jsonRpcConfig, new NoOpMetricsSystem(), natService, @@ -178,13 +177,13 @@ private Path createPasswordFile(final char[] password) { private Path createTempFile() { try { - return folder.newFile().toPath(); + return Files.createFile(folder.resolve("tempFile")); } catch (IOException e) { throw new UncheckedIOException(e); } } - @After + @AfterEach public void shutdownServer() { service.stop().join(); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/LatestNonceProviderTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/LatestNonceProviderTest.java index bc3312fe059..71fc3a4b47b 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/LatestNonceProviderTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/LatestNonceProviderTest.java @@ -19,17 +19,17 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import java.util.OptionalLong; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class LatestNonceProviderTest { private final Address senderAddress = Address.fromHexString("1"); @@ -37,17 +37,17 @@ public class LatestNonceProviderTest { @Mock private BlockchainQueries blockchainQueries; private LatestNonceProvider nonceProvider; - @Mock private PendingTransactions pendingTransactions; + @Mock private TransactionPool transactionPool; - @Before + @BeforeEach public void setUp() { - nonceProvider = new LatestNonceProvider(blockchainQueries, pendingTransactions); + nonceProvider = new LatestNonceProvider(blockchainQueries, transactionPool); } @Test public void nextNonceUsesTxPool() { final long highestNonceInPendingTransactions = 123; - when(pendingTransactions.getNextNonceForSender(senderAddress)) + when(transactionPool.getNextNonceForSender(senderAddress)) .thenReturn(OptionalLong.of(highestNonceInPendingTransactions)); assertThat(nonceProvider.getNonce(senderAddress)).isEqualTo(highestNonceInPendingTransactions); } @@ -56,7 +56,7 @@ public void nextNonceUsesTxPool() { public void nextNonceIsTakenFromBlockchainIfNoPendingTransactionResponse() { final long headBlockNumber = 8; final long nonceInBlockchain = 56; - when(pendingTransactions.getNextNonceForSender(senderAddress)).thenReturn(OptionalLong.empty()); + when(transactionPool.getNextNonceForSender(senderAddress)).thenReturn(OptionalLong.empty()); when(blockchainQueries.headBlockNumber()).thenReturn(headBlockNumber); when(blockchainQueries.getTransactionCount(senderAddress, headBlockNumber)) .thenReturn(nonceInBlockchain); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/LimitConnectionsJsonRpcHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/LimitConnectionsJsonRpcHttpServiceTest.java index 0fcd03e1efa..625e3fe5687 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/LimitConnectionsJsonRpcHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/LimitConnectionsJsonRpcHttpServiceTest.java @@ -22,12 +22,12 @@ import okhttp3.OkHttpClient; import okhttp3.Response; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; public class LimitConnectionsJsonRpcHttpServiceTest extends JsonRpcHttpServiceTestBase { - @BeforeClass + @BeforeAll public static void initLimitedServerAndClient() throws Exception { maxConnections = 2; initServerAndClient(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/MaxBatchSizeJsonRpcHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/MaxBatchSizeJsonRpcHttpServiceTest.java index d648baaa949..3c206fa2235 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/MaxBatchSizeJsonRpcHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/MaxBatchSizeJsonRpcHttpServiceTest.java @@ -17,13 +17,13 @@ import static org.assertj.core.api.Assertions.assertThat; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; import okhttp3.RequestBody; import okhttp3.Response; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class MaxBatchSizeJsonRpcHttpServiceTest extends JsonRpcHttpServiceTestBase { @@ -74,7 +74,7 @@ public void shouldReturnErrorWhenBatchRequestGreaterThanConfig() throws Exceptio try (final Response resp = client.newCall(buildPostRequest(body)).execute()) { assertThat(resp.code()).isEqualTo(200); final JsonObject json = new JsonObject(resp.body().string()); - final JsonRpcError expectedError = JsonRpcError.EXCEEDS_RPC_MAX_BATCH_SIZE; + final RpcErrorType expectedError = RpcErrorType.EXCEEDS_RPC_MAX_BATCH_SIZE; testHelper.assertValidJsonRpcError( json, null, expectedError.getCode(), expectedError.getMessage()); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcErrorConverterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcErrorTypeConverterTest.java similarity index 55% rename from ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcErrorConverterTest.java rename to ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcErrorTypeConverterTest.java index 42afd064578..6a52b39c853 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcErrorConverterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcErrorTypeConverterTest.java @@ -16,75 +16,66 @@ import static org.assertj.core.api.Assertions.assertThat; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; import java.util.Arrays; import java.util.Collection; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameter; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) -public class JsonRpcErrorConverterTest { +public class RpcErrorTypeConverterTest { - @Parameters public static Collection expectedErrorMapping() { return Arrays.asList( new Object[][] { - {TransactionInvalidReason.NONCE_TOO_LOW, JsonRpcError.NONCE_TOO_LOW}, - {TransactionInvalidReason.PRIVATE_NONCE_TOO_LOW, JsonRpcError.NONCE_TOO_LOW}, - {TransactionInvalidReason.NONCE_TOO_HIGH, JsonRpcError.NONCE_TOO_HIGH}, - {TransactionInvalidReason.PRIVATE_NONCE_TOO_HIGH, JsonRpcError.NONCE_TOO_HIGH}, - {TransactionInvalidReason.INVALID_SIGNATURE, JsonRpcError.INVALID_TRANSACTION_SIGNATURE}, + {TransactionInvalidReason.NONCE_TOO_LOW, RpcErrorType.NONCE_TOO_LOW}, + {TransactionInvalidReason.PRIVATE_NONCE_TOO_LOW, RpcErrorType.NONCE_TOO_LOW}, + {TransactionInvalidReason.NONCE_TOO_HIGH, RpcErrorType.NONCE_TOO_HIGH}, + {TransactionInvalidReason.PRIVATE_NONCE_TOO_HIGH, RpcErrorType.NONCE_TOO_HIGH}, + {TransactionInvalidReason.INVALID_SIGNATURE, RpcErrorType.INVALID_TRANSACTION_SIGNATURE}, { TransactionInvalidReason.INTRINSIC_GAS_EXCEEDS_GAS_LIMIT, - JsonRpcError.INTRINSIC_GAS_EXCEEDS_LIMIT + RpcErrorType.INTRINSIC_GAS_EXCEEDS_LIMIT }, { TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE, - JsonRpcError.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE + RpcErrorType.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE }, - {TransactionInvalidReason.EXCEEDS_BLOCK_GAS_LIMIT, JsonRpcError.EXCEEDS_BLOCK_GAS_LIMIT}, - {TransactionInvalidReason.WRONG_CHAIN_ID, JsonRpcError.WRONG_CHAIN_ID}, + {TransactionInvalidReason.EXCEEDS_BLOCK_GAS_LIMIT, RpcErrorType.EXCEEDS_BLOCK_GAS_LIMIT}, + {TransactionInvalidReason.WRONG_CHAIN_ID, RpcErrorType.WRONG_CHAIN_ID}, { TransactionInvalidReason.REPLAY_PROTECTED_SIGNATURES_NOT_SUPPORTED, - JsonRpcError.REPLAY_PROTECTED_SIGNATURES_NOT_SUPPORTED + RpcErrorType.REPLAY_PROTECTED_SIGNATURES_NOT_SUPPORTED }, { - TransactionInvalidReason.TX_SENDER_NOT_AUTHORIZED, JsonRpcError.TX_SENDER_NOT_AUTHORIZED + TransactionInvalidReason.TX_SENDER_NOT_AUTHORIZED, RpcErrorType.TX_SENDER_NOT_AUTHORIZED }, { TransactionInvalidReason.CHAIN_HEAD_WORLD_STATE_NOT_AVAILABLE, - JsonRpcError.CHAIN_HEAD_WORLD_STATE_NOT_AVAILABLE + RpcErrorType.CHAIN_HEAD_WORLD_STATE_NOT_AVAILABLE }, - {TransactionInvalidReason.GAS_PRICE_TOO_LOW, JsonRpcError.GAS_PRICE_TOO_LOW}, + {TransactionInvalidReason.GAS_PRICE_TOO_LOW, RpcErrorType.GAS_PRICE_TOO_LOW}, { TransactionInvalidReason.OFFCHAIN_PRIVACY_GROUP_DOES_NOT_EXIST, - JsonRpcError.OFFCHAIN_PRIVACY_GROUP_DOES_NOT_EXIST + RpcErrorType.OFFCHAIN_PRIVACY_GROUP_DOES_NOT_EXIST }, { TransactionInvalidReason.TRANSACTION_ALREADY_KNOWN, - JsonRpcError.ETH_SEND_TX_ALREADY_KNOWN + RpcErrorType.ETH_SEND_TX_ALREADY_KNOWN }, { TransactionInvalidReason.TRANSACTION_REPLACEMENT_UNDERPRICED, - JsonRpcError.ETH_SEND_TX_REPLACEMENT_UNDERPRICED + RpcErrorType.ETH_SEND_TX_REPLACEMENT_UNDERPRICED } }); } - @Parameter(0) - public TransactionInvalidReason txInvalidReason; - - @Parameter(1) - public JsonRpcError expectedJsonRpcError; - - @Test - public void expectedTransactionValidationToJsonRpcErrorConversion() { + @ParameterizedTest + @MethodSource("expectedErrorMapping") + public void expectedTransactionValidationToJsonRpcErrorConversion( + final TransactionInvalidReason txInvalidReason, final RpcErrorType expectedJsonRpcError) { assertThat(JsonRpcErrorConverter.convertTransactionInvalidReason(txInvalidReason)) .isEqualTo(expectedJsonRpcError); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/SimpleTestTransactionBuilder.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/SimpleTestTransactionBuilder.java index 434f97986a3..7d5e7f772e3 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/SimpleTestTransactionBuilder.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/SimpleTestTransactionBuilder.java @@ -19,6 +19,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; @@ -40,6 +41,7 @@ public static Transaction transaction(final Hash hash) { "0x5b5b610705806100106000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063102accc11461012c57806312a7b9141461013a5780631774e6461461014c5780631e26fd331461015d5780631f9030371461016e578063343a875d1461018057806338cc4831146101955780634e7ad367146101bd57806357cb2fc4146101cb57806365538c73146101e057806368895979146101ee57806376bc21d9146102005780639a19a9531461020e5780639dc2c8f51461021f578063a53b1c1e1461022d578063a67808571461023e578063b61c05031461024c578063c2b12a731461025a578063d2282dc51461026b578063e30081a01461027c578063e8beef5b1461028d578063f38b06001461029b578063f5b53e17146102a9578063fd408767146102bb57005b6101346104d6565b60006000f35b61014261039b565b8060005260206000f35b610157600435610326565b60006000f35b6101686004356102c9565b60006000f35b610176610442565b8060005260206000f35b6101886103d3565b8060ff1660005260206000f35b61019d610413565b8073ffffffffffffffffffffffffffffffffffffffff1660005260206000f35b6101c56104c5565b60006000f35b6101d36103b7565b8060000b60005260206000f35b6101e8610454565b60006000f35b6101f6610401565b8060005260206000f35b61020861051f565b60006000f35b6102196004356102e5565b60006000f35b610227610693565b60006000f35b610238600435610342565b60006000f35b610246610484565b60006000f35b610254610493565b60006000f35b61026560043561038d565b60006000f35b610276600435610350565b60006000f35b61028760043561035e565b60006000f35b6102956105b4565b60006000f35b6102a3610547565b60006000f35b6102b16103ef565b8060005260206000f35b6102c3610600565b60006000f35b80600060006101000a81548160ff021916908302179055505b50565b80600060016101000a81548160ff02191690837f01000000000000000000000000000000000000000000000000000000000000009081020402179055505b50565b80600060026101000a81548160ff021916908302179055505b50565b806001600050819055505b50565b806002600050819055505b50565b80600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055505b50565b806004600050819055505b50565b6000600060009054906101000a900460ff1690506103b4565b90565b6000600060019054906101000a900460000b90506103d0565b90565b6000600060029054906101000a900460ff1690506103ec565b90565b600060016000505490506103fe565b90565b60006002600050549050610410565b90565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905061043f565b90565b60006004600050549050610451565b90565b7f65c9ac8011e286e89d02a269890f41d67ca2cc597b2c76c7c69321ff492be5806000602a81526020016000a15b565b6000602a81526020016000a05b565b60017f81933b308056e7e85668661dcd102b1f22795b4431f9cf4625794f381c271c6b6000602a81526020016000a25b565b60016000602a81526020016000a15b565b3373ffffffffffffffffffffffffffffffffffffffff1660017f0e216b62efbb97e751a2ce09f607048751720397ecfb9eef1e48a6644948985b6000602a81526020016000a35b565b3373ffffffffffffffffffffffffffffffffffffffff1660016000602a81526020016000a25b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6001023373ffffffffffffffffffffffffffffffffffffffff1660017f317b31292193c2a4f561cc40a95ea0d97a2733f14af6d6d59522473e1f3ae65f6000602a81526020016000a45b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6001023373ffffffffffffffffffffffffffffffffffffffff1660016000602a81526020016000a35b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6001023373ffffffffffffffffffffffffffffffffffffffff1660017fd5f0a30e4be0c6be577a71eceb7464245a796a7e6a55c0d971837b250de05f4e60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe98152602001602a81526020016000a45b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6001023373ffffffffffffffffffffffffffffffffffffffff16600160007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe98152602001602a81526020016000a35b56", "0x0", null, + "0xf8", "0xa", "0x1c", "0xe439aa8812c1c0a751b0931ea20c5a30cd54fe15cae883c59fd8107e04557679", @@ -54,6 +56,7 @@ public static Transaction transaction( final String input, final String nonce, final String toAddress, + final String type, final String value, final String v, final String r, @@ -67,6 +70,7 @@ public static Transaction transaction( when(transaction.getR()).thenReturn(bigInteger(r)); when(transaction.getS()).thenReturn(bigInteger(s)); when(transaction.getTo()).thenReturn(Optional.ofNullable(address(toAddress))); + when(transaction.getType()).thenReturn(TransactionType.of(Integer.decode(type))); when(transaction.getSender()).thenReturn(address(fromAddress)); when(transaction.getPayload()).thenReturn(Bytes.fromHexString(input)); when(transaction.getValue()).thenReturn(wei(value)); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/AuthenticationServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/AuthenticationServiceTest.java index 0ce032617c7..27b18066f5d 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/AuthenticationServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/AuthenticationServiceTest.java @@ -30,7 +30,7 @@ import io.vertx.core.json.JsonObject; import io.vertx.ext.auth.JWTOptions; import io.vertx.ext.auth.User; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class AuthenticationServiceTest { private final Vertx vertx = Vertx.vertx(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/AuthenticationUtilsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/AuthenticationUtilsTest.java index 9c611136017..c3b4d1793c3 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/AuthenticationUtilsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/AuthenticationUtilsTest.java @@ -16,7 +16,7 @@ import static org.assertj.core.api.Assertions.assertThat; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class AuthenticationUtilsTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/EngineAuthServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/EngineAuthServiceTest.java index 6093f0e5677..4c2fc787ff5 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/EngineAuthServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/EngineAuthServiceTest.java @@ -34,7 +34,7 @@ import io.vertx.core.json.JsonObject; import io.vertx.ext.auth.User; import io.vertx.ext.auth.jwt.JWTAuth; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class EngineAuthServiceTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/JWTAuthOptionsFactoryTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/JWTAuthOptionsFactoryTest.java index b173d72da26..1a756fd59ac 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/JWTAuthOptionsFactoryTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/JWTAuthOptionsFactoryTest.java @@ -34,7 +34,7 @@ import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.io.pem.PemObject; import org.bouncycastle.util.io.pem.PemReader; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class JWTAuthOptionsFactoryTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/TomlAuthTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/TomlAuthTest.java index b3d22cc3e34..a2066c9d1c4 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/TomlAuthTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/TomlAuthTest.java @@ -14,6 +14,8 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.authentication; +import static org.junit.jupiter.api.Assertions.assertEquals; + import java.net.URISyntaxException; import java.nio.file.NoSuchFileException; import java.nio.file.Paths; @@ -21,22 +23,25 @@ import io.vertx.core.Vertx; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import io.vertx.junit5.VertxExtension; +import io.vertx.junit5.VertxTestContext; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; -@RunWith(VertxUnitRunner.class) +@ExtendWith(VertxExtension.class) public class TomlAuthTest { private Vertx vertx; + private VertxTestContext testContext; private JsonObject validAuthInfo; private TomlAuth tomlAuth; - @Before - public void before(final TestContext context) throws URISyntaxException { + @BeforeEach + public void before() throws URISyntaxException { vertx = Vertx.vertx(); + testContext = new VertxTestContext(); + tomlAuth = new TomlAuth( vertx, new TomlAuthOptions().setTomlPath(getTomlPath("authentication/auth.toml"))); @@ -44,69 +49,57 @@ public void before(final TestContext context) throws URISyntaxException { } @Test - public void authInfoWithoutUsernameShouldFailAuthentication(final TestContext context) { + public void authInfoWithoutUsernameShouldFailAuthentication() { JsonObject authInfo = new JsonObject().put("password", "foo"); tomlAuth.authenticate( - authInfo, - context.asyncAssertFailure( - th -> context.assertEquals("No username provided", th.getMessage()))); + authInfo, testContext.failing(th -> assertEquals("No username provided", th.getMessage()))); } @Test - public void authInfoWithoutPasswordShouldFailAuthentication(final TestContext context) { + public void authInfoWithoutPasswordShouldFailAuthentication() { JsonObject authInfo = new JsonObject().put("username", "foo"); tomlAuth.authenticate( - authInfo, - context.asyncAssertFailure( - th -> context.assertEquals("No password provided", th.getMessage()))); + authInfo, testContext.failing(th -> assertEquals("No password provided", th.getMessage()))); } @Test - public void parseFailureWithIOExceptionShouldFailAuthentication(final TestContext context) { + public void parseFailureWithIOExceptionShouldFailAuthentication() { tomlAuth = new TomlAuth(vertx, new TomlAuthOptions().setTomlPath("invalid_path")); tomlAuth.authenticate( validAuthInfo, - context.asyncAssertFailure( - th -> { - context.assertEquals(th.getClass(), NoSuchFileException.class); - })); + testContext.failing(th -> assertEquals(th.getClass(), NoSuchFileException.class))); } @Test - public void authInfoWithAbsentUserShouldFailAuthentication(final TestContext context) { + public void authInfoWithAbsentUserShouldFailAuthentication() { JsonObject authInfo = new JsonObject().put("username", "foo").put("password", "foo"); tomlAuth.authenticate( - authInfo, - context.asyncAssertFailure(th -> context.assertEquals("User not found", th.getMessage()))); + authInfo, testContext.failing(th -> assertEquals("User not found", th.getMessage()))); } @Test - public void userWithoutPasswordSetShouldFailAuthentication(final TestContext context) { + public void userWithoutPasswordSetShouldFailAuthentication() { JsonObject authInfo = new JsonObject().put("username", "noPasswordUser").put("password", "foo"); tomlAuth.authenticate( authInfo, - context.asyncAssertFailure( - th -> context.assertEquals("No password set for user", th.getMessage()))); + testContext.failing(th -> assertEquals("No password set for user", th.getMessage()))); } @Test - public void passwordMismatchShouldFailAuthentication(final TestContext context) { + public void passwordMismatchShouldFailAuthentication() { JsonObject authInfo = new JsonObject().put("username", "userA").put("password", "foo"); tomlAuth.authenticate( - authInfo, - context.asyncAssertFailure( - th -> context.assertEquals("Invalid password", th.getMessage()))); + authInfo, testContext.failing(th -> assertEquals("Invalid password", th.getMessage()))); } @Test - public void validPasswordWithAllValuesShouldAuthenticateAndCreateUserSuccessfully( - final TestContext context) { + public void validPasswordWithAllValuesShouldAuthenticateAndCreateUserSuccessfully() { JsonObject expectedPrincipal = new JsonObject() .put("username", "userA") @@ -119,14 +112,11 @@ public void validPasswordWithAllValuesShouldAuthenticateAndCreateUserSuccessfull JsonObject authInfo = new JsonObject().put("username", "userA").put("password", "pegasys"); tomlAuth.authenticate( - authInfo, - context.asyncAssertSuccess( - res -> context.assertEquals(expectedPrincipal, res.principal()))); + authInfo, testContext.succeeding(res -> assertEquals(expectedPrincipal, res.principal()))); } @Test - public void validPasswordWithOptionalValuesShouldAuthenticateAndCreateUserSuccessfully( - final TestContext context) { + public void validPasswordWithOptionalValuesShouldAuthenticateAndCreateUserSuccessfully() { JsonObject expectedPrincipal = new JsonObject() .put("username", "userB") @@ -138,9 +128,7 @@ public void validPasswordWithOptionalValuesShouldAuthenticateAndCreateUserSucces JsonObject authInfo = new JsonObject().put("username", "userB").put("password", "pegasys"); tomlAuth.authenticate( - authInfo, - context.asyncAssertSuccess( - res -> context.assertEquals(expectedPrincipal, res.principal()))); + authInfo, testContext.succeeding(res -> assertEquals(expectedPrincipal, res.principal()))); } private String getTomlPath(final String tomlFileName) throws URISyntaxException { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/TomlUserTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/TomlUserTest.java index 95aeadfa176..68e62f2ad04 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/TomlUserTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/TomlUserTest.java @@ -21,7 +21,7 @@ import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class TomlUserTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/DebugJsonRpcHttpBySpecTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/DebugJsonRpcHttpBySpecTest.java index ba55e7cf110..8757e00d3ec 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/DebugJsonRpcHttpBySpecTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/DebugJsonRpcHttpBySpecTest.java @@ -16,26 +16,17 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.AbstractJsonRpcHttpBySpecTest; -import java.net.URL; +import org.junit.jupiter.api.BeforeEach; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -@RunWith(Parameterized.class) public class DebugJsonRpcHttpBySpecTest extends AbstractJsonRpcHttpBySpecTest { - public DebugJsonRpcHttpBySpecTest(final String specName, final URL specURL) { - super(specName, specURL); - } - @Override + @BeforeEach public void setup() throws Exception { setupBonsaiBlockchain(); startService(); } - @Parameters(name = "{index}: {0}") public static Object[][] specs() { return findSpecFiles( new String[] {"debug"}, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/EthByzantiumJsonRpcHttpBySpecTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/EthByzantiumJsonRpcHttpBySpecTest.java index d012c1eb40e..a5f3ae0ab0c 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/EthByzantiumJsonRpcHttpBySpecTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/EthByzantiumJsonRpcHttpBySpecTest.java @@ -18,20 +18,12 @@ import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; -import java.net.URL; +import org.junit.jupiter.api.BeforeEach; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -@RunWith(Parameterized.class) public class EthByzantiumJsonRpcHttpBySpecTest extends AbstractJsonRpcHttpBySpecTest { - public EthByzantiumJsonRpcHttpBySpecTest(final String specName, final URL specURL) { - super(specName, specURL); - } - @Override + @BeforeEach public void setup() throws Exception { setupBonsaiBlockchain(); startService(); @@ -43,7 +35,6 @@ protected BlockchainSetupUtil getBlockchainSetupUtil(final DataStorageFormat dat "trace/chain-data/genesis.json", "trace/chain-data/blocks.bin", dataStorageFormat); } - @Parameters(name = "{index}: {0}") public static Object[][] specs() { return AbstractJsonRpcHttpBySpecTest.findSpecFiles(new String[] {"eth_latest"}); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/EthJsonRpcHttpBySpecTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/EthJsonRpcHttpBySpecTest.java index 96aa9b3adaf..2a824a89afd 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/EthJsonRpcHttpBySpecTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/EthJsonRpcHttpBySpecTest.java @@ -16,26 +16,17 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.AbstractJsonRpcHttpBySpecTest; -import java.net.URL; +import org.junit.jupiter.api.BeforeEach; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -@RunWith(Parameterized.class) public class EthJsonRpcHttpBySpecTest extends AbstractJsonRpcHttpBySpecTest { - public EthJsonRpcHttpBySpecTest(final String specName, final URL specURL) { - super(specName, specURL); - } - @Override + @BeforeEach public void setup() throws Exception { setupBonsaiBlockchain(); startService(); } - @Parameters(name = "{index}: {0}") public static Object[][] specs() { return findSpecFiles( new String[] {"eth"}, "getProof"); // getProof is not working with bonsai trie diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/TraceJsonRpcHttpBySpecTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/TraceJsonRpcHttpBySpecTest.java index 922e1aa6ff4..127d7d3b696 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/TraceJsonRpcHttpBySpecTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/TraceJsonRpcHttpBySpecTest.java @@ -18,20 +18,12 @@ import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; -import java.net.URL; +import org.junit.jupiter.api.BeforeEach; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -@RunWith(Parameterized.class) public class TraceJsonRpcHttpBySpecTest extends AbstractJsonRpcHttpBySpecTest { - public TraceJsonRpcHttpBySpecTest(final String specName, final URL specURL) { - super(specName, specURL); - } - @Override + @BeforeEach public void setup() throws Exception { setupBonsaiBlockchain(); startService(); @@ -43,7 +35,6 @@ protected BlockchainSetupUtil getBlockchainSetupUtil(final DataStorageFormat sto "trace/chain-data/genesis.json", "trace/chain-data/blocks.bin", storageFormat); } - @Parameters(name = "{index}: {0}") public static Object[][] specs() { return AbstractJsonRpcHttpBySpecTest.findSpecFiles( new String[] { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/context/ContextKeyTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/context/ContextKeyTest.java index 3459d54bc5e..a31bcb96d8e 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/context/ContextKeyTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/context/ContextKeyTest.java @@ -26,15 +26,11 @@ import io.vertx.core.json.JsonObject; import io.vertx.ext.web.RoutingContext; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public class ContextKeyTest { - @Parameters public static Collection data() { return Arrays.asList( new Object[][] { @@ -50,24 +46,14 @@ public static Collection data() { } private static final String JSON = "{\"key\": \"value\"}"; - private final ContextKey key; - private final RoutingContext ctx; - private final Supplier defaultSupplier; - private final T expected; - public ContextKeyTest( + @ParameterizedTest + @MethodSource("data") + public void test( final ContextKey key, final RoutingContext ctx, final Supplier defaultSupplier, final T expected) { - this.key = key; - this.ctx = ctx; - this.defaultSupplier = defaultSupplier; - this.expected = expected; - } - - @Test - public void test() { assertThat(key.extractFrom(ctx, defaultSupplier)).isEqualTo(expected); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/DebugJsonRpcHttpBySpecTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/DebugJsonRpcHttpBySpecTest.java index b9ab7d398ab..f6908f88933 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/DebugJsonRpcHttpBySpecTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/DebugJsonRpcHttpBySpecTest.java @@ -16,26 +16,17 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.AbstractJsonRpcHttpBySpecTest; -import java.net.URL; +import org.junit.jupiter.api.BeforeEach; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -@RunWith(Parameterized.class) public class DebugJsonRpcHttpBySpecTest extends AbstractJsonRpcHttpBySpecTest { - public DebugJsonRpcHttpBySpecTest(final String specName, final URL specURL) { - super(specName, specURL); - } - @Override + @BeforeEach public void setup() throws Exception { setupBlockchain(); startService(); } - @Parameters(name = "{index}: {0}") public static Object[][] specs() { return findSpecFiles(new String[] {"debug"}); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/EthByzantiumJsonRpcHttpBySpecTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/EthByzantiumJsonRpcHttpBySpecTest.java index 3d0a85ce6e4..a98aa9b45e5 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/EthByzantiumJsonRpcHttpBySpecTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/EthByzantiumJsonRpcHttpBySpecTest.java @@ -18,20 +18,12 @@ import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; -import java.net.URL; +import org.junit.jupiter.api.BeforeEach; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -@RunWith(Parameterized.class) public class EthByzantiumJsonRpcHttpBySpecTest extends AbstractJsonRpcHttpBySpecTest { - public EthByzantiumJsonRpcHttpBySpecTest(final String specName, final URL specURL) { - super(specName, specURL); - } - @Override + @BeforeEach public void setup() throws Exception { setupBlockchain(); startService(); @@ -43,7 +35,6 @@ protected BlockchainSetupUtil getBlockchainSetupUtil(final DataStorageFormat sto "trace/chain-data/genesis.json", "trace/chain-data/blocks.bin", storageFormat); } - @Parameters(name = "{index}: {0}") public static Object[][] specs() { return AbstractJsonRpcHttpBySpecTest.findSpecFiles(new String[] {"eth_latest"}); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/EthJsonRpcHttpBySpecTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/EthJsonRpcHttpBySpecTest.java index faf6ed93ac7..277f1b89d03 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/EthJsonRpcHttpBySpecTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/EthJsonRpcHttpBySpecTest.java @@ -16,26 +16,17 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.AbstractJsonRpcHttpBySpecTest; -import java.net.URL; +import org.junit.jupiter.api.BeforeEach; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -@RunWith(Parameterized.class) public class EthJsonRpcHttpBySpecTest extends AbstractJsonRpcHttpBySpecTest { - public EthJsonRpcHttpBySpecTest(final String specName, final URL specURL) { - super(specName, specURL); - } - @Override + @BeforeEach public void setup() throws Exception { setupBlockchain(); startService(); } - @Parameters(name = "{index}: {0}") public static Object[][] specs() { return findSpecFiles(new String[] {"eth"}); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/TraceJsonRpcHttpBySpecTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/TraceJsonRpcHttpBySpecTest.java index d3a503ca8fe..36b5b6f17e1 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/TraceJsonRpcHttpBySpecTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/TraceJsonRpcHttpBySpecTest.java @@ -18,20 +18,12 @@ import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; -import java.net.URL; +import org.junit.jupiter.api.BeforeEach; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -@RunWith(Parameterized.class) public class TraceJsonRpcHttpBySpecTest extends AbstractJsonRpcHttpBySpecTest { - public TraceJsonRpcHttpBySpecTest(final String specName, final URL specURL) { - super(specName, specURL); - } - @Override + @BeforeEach public void setup() throws Exception { setupBlockchain(); startService(); @@ -43,7 +35,6 @@ protected BlockchainSetupUtil getBlockchainSetupUtil(final DataStorageFormat sto "trace/chain-data/genesis.json", "trace/chain-data/blocks.bin", storageFormat); } - @Parameters(name = "{index}: {0}") public static Object[][] specs() { return AbstractJsonRpcHttpBySpecTest.findSpecFiles( new String[] { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/health/ReadinessCheckTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/health/ReadinessCheckTest.java index bbfc38b866b..ca8d2328ca7 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/health/ReadinessCheckTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/health/ReadinessCheckTest.java @@ -27,7 +27,7 @@ import java.util.Map; import java.util.Optional; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class ReadinessCheckTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/QosTimerTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/QosTimerTest.java index e89a83c6a71..7224c28e033 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/QosTimerTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/QosTimerTest.java @@ -14,32 +14,33 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal; -import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import java.util.concurrent.TimeoutException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import io.vertx.core.Vertx; -import io.vertx.ext.unit.Async; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; +import io.vertx.junit5.VertxExtension; +import io.vertx.junit5.VertxTestContext; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; -@RunWith(VertxUnitRunner.class) +@ExtendWith(VertxExtension.class) public class QosTimerTest { static Vertx vertx = Vertx.vertx(); + private final VertxTestContext testContext = new VertxTestContext(); - @Ignore("fails on CI with short timeouts and don't want to slow test suite down with longer ones") + @Disabled( + "fails on CI with short timeouts and don't want to slow test suite down with longer ones") @Test - public void shouldExecuteConsecutivelyAtTimeout(final TestContext ctx) { + public void shouldExecuteConsecutivelyAtTimeout() throws InterruptedException { final long TEST_QOS_TIMEOUT = 100L; final int INVOCATIONS_COUNT = 2; - final Async async = ctx.async(INVOCATIONS_COUNT); + final CountDownLatch latch = new CountDownLatch(INVOCATIONS_COUNT); final long startTime = System.currentTimeMillis(); - new QosTimer(vertx, TEST_QOS_TIMEOUT, z -> async.countDown()); - async.awaitSuccess(); + new QosTimer(vertx, TEST_QOS_TIMEOUT, z -> latch.countDown()); + latch.await(); final long executionTime = System.currentTimeMillis() - startTime; assertThat(executionTime) .as("Execution ended ahead of time") @@ -47,12 +48,12 @@ public void shouldExecuteConsecutivelyAtTimeout(final TestContext ctx) { } @Test - public void shouldExecuteOnceAtTimeout(final TestContext ctx) { + public void shouldExecuteOnceAtTimeout() throws InterruptedException { final long TEST_QOS_TIMEOUT = 75L; - final Async async = ctx.async(); + final CountDownLatch latch = new CountDownLatch(1); final long startTime = System.currentTimeMillis(); - new QosTimer(vertx, TEST_QOS_TIMEOUT, z -> async.countDown()); - async.awaitSuccess(); + new QosTimer(vertx, TEST_QOS_TIMEOUT, z -> latch.countDown()); + latch.await(); final long executionTime = System.currentTimeMillis() - startTime; assertThat(executionTime) .as("Execution ended ahead of time") @@ -60,21 +61,21 @@ public void shouldExecuteOnceAtTimeout(final TestContext ctx) { } @Test - public void shouldNotExecuteBeforeTimeout(final TestContext ctx) { + public void shouldNotExecuteBeforeTimeout() throws InterruptedException { final long TEST_QOS_TIMEOUT = 200L; - final Async async = ctx.async(); - new QosTimer(vertx, TEST_QOS_TIMEOUT, z -> async.countDown()); - assertThatThrownBy(() -> async.awaitSuccess(50L)).isInstanceOf(TimeoutException.class); + final CountDownLatch latch = new CountDownLatch(1); + new QosTimer(vertx, TEST_QOS_TIMEOUT, z -> latch.countDown()); + assertThat(latch.await(50L, TimeUnit.MILLISECONDS)).isFalse(); } @Test - public void shouldNotExecuteWhenReset(final TestContext ctx) { + public void shouldNotExecuteWhenReset() throws InterruptedException { final long TEST_QOS_TIMEOUT = 50L; - final Async async = ctx.async(); - final var timer = new QosTimer(vertx, TEST_QOS_TIMEOUT, z -> async.countDown()); + final CountDownLatch latch = new CountDownLatch(1); + final var timer = new QosTimer(vertx, TEST_QOS_TIMEOUT, z -> latch.countDown()); // reset QoS timer every 25 millis vertx.setPeriodic(25L, z -> timer.resetTimer()); - assertThatThrownBy(() -> async.awaitSuccess(200L)).isInstanceOf(TimeoutException.class); - async.complete(); + assertThat(latch.await(200L, TimeUnit.MILLISECONDS)).isFalse(); + testContext.completeNow(); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/EthJsonRpcHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/EthJsonRpcHttpServiceTest.java index d431621fc82..bdef98bb039 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/EthJsonRpcHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/EthJsonRpcHttpServiceTest.java @@ -31,7 +31,7 @@ import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class EthJsonRpcHttpServiceTest extends AbstractJsonRpcHttpServiceTest { @@ -45,8 +45,7 @@ private Hash recordPendingTransaction(final int blockNumber, final int transacti @Test public void getFilterChanges_noBlocks() throws Exception { startService(); - final String expectedRespBody = - String.format("{%n \"jsonrpc\" : \"2.0\",%n \"id\" : 2,%n \"result\" : [ ]%n}"); + final String expectedRespBody = String.format("{\"jsonrpc\":\"2.0\",\"id\":2,\"result\":[]}"); final ResponseBody body = ethNewBlockFilter(1).body(); final String result = getResult(body); body.close(); @@ -60,7 +59,7 @@ public void getFilterChanges_oneBlock() throws Exception { BlockchainSetupUtil blockchainSetupUtil = startServiceWithEmptyChain(DataStorageFormat.FOREST); final String expectedRespBody = String.format( - "{%n \"jsonrpc\" : \"2.0\",%n \"id\" : 2,%n \"result\" : [ \"0x10aaf14a53caf27552325374429d3558398a36d3682ede6603c2c6511896e9f9\" ]%n}"); + "{\"jsonrpc\":\"2.0\",\"id\":2,\"result\":[\"0x10aaf14a53caf27552325374429d3558398a36d3682ede6603c2c6511896e9f9\"]}"); final ResponseBody body = ethNewBlockFilter(1).body(); final String result = getResult(body); body.close(); @@ -75,8 +74,7 @@ public void getFilterChanges_oneBlock() throws Exception { @Test public void getFilterChanges_noTransactions() throws Exception { startService(); - final String expectedRespBody = - String.format("{%n \"jsonrpc\" : \"2.0\",%n \"id\" : 2,%n \"result\" : [ ]%n}"); + final String expectedRespBody = String.format("{\"jsonrpc\":\"2.0\",\"id\":2,\"result\":[]}"); final ResponseBody body = ethNewPendingTransactionFilter(1).body(); final String result = getResult(body); body.close(); @@ -96,18 +94,14 @@ public void getFilterChanges_oneTransaction() throws Exception { final Response resp = ethGetFilterChanges(2, result); assertThat(resp.code()).isEqualTo(200); final String expectedRespBody = - String.format( - "{%n \"jsonrpc\" : \"2.0\",%n \"id\" : 2,%n \"result\" : [ \"" - + transactionHash - + "\" ]%n}"); + String.format("{\"jsonrpc\":\"2.0\",\"id\":2,\"result\":[\"" + transactionHash + "\"]}"); assertThat(resp.body().string()).isEqualTo(expectedRespBody); } @Test public void uninstallFilter() throws Exception { startService(); - final String expectedRespBody = - String.format("{%n \"jsonrpc\" : \"2.0\",%n \"id\" : 2,%n \"result\" : true%n}"); + final String expectedRespBody = String.format("{\"jsonrpc\":\"2.0\",\"id\":2,\"result\":true}"); final ResponseBody body = ethNewBlockFilter(1).body(); final String result = getResult(body); body.close(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterIdGeneratorTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterIdGeneratorTest.java index 94b4c37ec92..f3d850374a7 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterIdGeneratorTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterIdGeneratorTest.java @@ -17,7 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class FilterIdGeneratorTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java index 709f349bf45..72d56748f81 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java @@ -49,14 +49,14 @@ import com.google.common.collect.Lists; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.Spy; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class FilterManagerLogFilterTest { private static final String PRIVACY_GROUP_ID = "Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs="; @@ -70,7 +70,7 @@ public class FilterManagerLogFilterTest { @Mock private TransactionPool transactionPool; @Spy private final FilterRepository filterRepository = new FilterRepository(); - @Before + @BeforeEach public void setupTest() { when(blockchainQueries.getBlockchain()).thenReturn(blockchain); this.filterManager = diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerTest.java index 5e0c220a36c..c4555339e22 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerTest.java @@ -36,14 +36,14 @@ import java.util.Optional; import com.google.common.collect.Lists; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.Spy; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class FilterManagerTest { private BlockDataGenerator blockGenerator; @@ -55,7 +55,7 @@ public class FilterManagerTest { @Mock private TransactionPool transactionPool; @Spy final FilterRepository filterRepository = new FilterRepository(); - @Before + @BeforeEach public void setupTest() { when(blockchainQueries.getBlockchain()).thenReturn(blockchain); this.blockGenerator = new BlockDataGenerator(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterRepositoryTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterRepositoryTest.java index 6a8782eff13..03e16be4fcc 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterRepositoryTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterRepositoryTest.java @@ -21,14 +21,14 @@ import java.util.Optional; import org.assertj.core.util.Lists; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class FilterRepositoryTest { private FilterRepository repository; - @Before + @BeforeEach public void before() { repository = new FilterRepository(); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterTest.java index 59d6e398070..9dcfb8f43cd 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterTest.java @@ -19,7 +19,7 @@ import java.time.Duration; import java.time.Instant; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class FilterTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterTimeoutMonitorTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterTimeoutMonitorTest.java index 62c1ad881ce..e7076c9083a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterTimeoutMonitorTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterTimeoutMonitorTest.java @@ -23,20 +23,20 @@ import java.util.Collections; import com.google.common.collect.Lists; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class FilterTimeoutMonitorTest { @Mock private FilterRepository filterRepository; private FilterTimeoutMonitor timeoutMonitor; - @Before + @BeforeEach public void before() { timeoutMonitor = new FilterTimeoutMonitor(filterRepository); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/LogsQueryTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/LogsQueryTest.java index 041130ad4fc..a9f06ed27ac 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/LogsQueryTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/LogsQueryTest.java @@ -29,7 +29,7 @@ import com.google.common.collect.Lists; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class LogsQueryTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminAddPeerTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminAddPeerTest.java index 8c476722d3d..25a0899c8c4 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminAddPeerTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminAddPeerTest.java @@ -20,23 +20,23 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork; import org.hyperledger.besu.ethereum.p2p.network.exceptions.P2PDisabledException; import org.hyperledger.besu.ethereum.p2p.peers.ImmutableEnodeDnsConfiguration; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.StrictStubs.class) +@ExtendWith(MockitoExtension.class) public class AdminAddPeerTest { @Mock private P2PNetwork p2pNetwork; @@ -69,7 +69,7 @@ public class AdminAddPeerTest { new JsonRpcRequestContext( new JsonRpcRequest("2.0", "admin_addPeer", new String[] {validDNSEnode})); - @Before + @BeforeEach public void setup() { method = new AdminAddPeer( @@ -102,7 +102,7 @@ public void requestIsMissingParameter() { final JsonRpcRequestContext request = new JsonRpcRequestContext(new JsonRpcRequest("2.0", "admin_addPeer", new String[] {})); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actualResponse = method.response(request); @@ -114,7 +114,7 @@ public void requestHasNullObjectParameter() { final JsonRpcRequestContext request = new JsonRpcRequestContext(new JsonRpcRequest("2.0", "admin_addPeer", null)); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actualResponse = method.response(request); @@ -126,7 +126,7 @@ public void requestHasNullArrayParameter() { final JsonRpcRequestContext request = new JsonRpcRequestContext(new JsonRpcRequest("2.0", "admin_addPeer", new String[] {null})); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actualResponse = method.response(request); @@ -139,7 +139,7 @@ public void requestHasInvalidEnode() { new JsonRpcRequestContext( new JsonRpcRequest("2.0", "admin_addPeer", new String[] {"asdf"})); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.PARSE_ERROR); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.PARSE_ERROR); final JsonRpcResponse actualResponse = method.response(request); @@ -159,7 +159,7 @@ public void requestHasInvalidEnodeLength() { new JsonRpcRequestContext( new JsonRpcRequest("2.0", "admin_addPeer", new String[] {invalidLengthEnode})); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.ENODE_ID_INVALID); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.ENODE_ID_INVALID); final JsonRpcResponse actualResponse = method.response(request); @@ -196,7 +196,7 @@ public void requestAddsValidDNSEnode() { public void requestAddsDNSEnodeButDNSDisabled() { final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( - validDNSRequest.getRequest().getId(), JsonRpcError.DNS_NOT_ENABLED); + validDNSRequest.getRequest().getId(), RpcErrorType.DNS_NOT_ENABLED); final JsonRpcResponse actualResponse = methodDNSDisabled.response(validDNSRequest); @@ -207,7 +207,7 @@ public void requestAddsDNSEnodeButDNSDisabled() { public void requestAddsDNSEnodeButDNSNotResolved() { final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( - validDNSRequest.getRequest().getId(), JsonRpcError.CANT_RESOLVE_PEER_ENODE_DNS); + validDNSRequest.getRequest().getId(), RpcErrorType.CANT_RESOLVE_PEER_ENODE_DNS); final JsonRpcResponse actualResponse = methodDNSUpdateDisabled.response(validDNSRequest); @@ -221,7 +221,7 @@ public void requestRefusesListOfNodes() { new JsonRpcRequest("2.0", "admin_addPeer", new String[] {validEnode, validEnode})); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actualResponse = method.response(request); @@ -247,7 +247,7 @@ public void requestReturnsErrorWhenP2pDisabled() { new P2PDisabledException("P2P networking disabled. Unable to connect to add peer.")); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(validRequest.getRequest().getId(), JsonRpcError.P2P_DISABLED); + new JsonRpcErrorResponse(validRequest.getRequest().getId(), RpcErrorType.P2P_DISABLED); final JsonRpcResponse actualResponse = method.response(validRequest); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminChangeLogLevelTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminChangeLogLevelTest.java index eeefcbc045b..120f380cd7a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminChangeLogLevelTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminChangeLogLevelTest.java @@ -18,26 +18,26 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.util.LogConfigurator; import org.apache.logging.log4j.Level; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class AdminChangeLogLevelTest { private AdminChangeLogLevel adminChangeLogLevel; - @Before + @BeforeEach public void before() { adminChangeLogLevel = new AdminChangeLogLevel(); LogConfigurator.setLevel("", "INFO"); @@ -117,7 +117,7 @@ public void requestHasNullArrayParameter() { new JsonRpcRequestContext( new JsonRpcRequest("2.0", "admin_changeLogLevel", new Object[] {null})); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actualResponse = adminChangeLogLevel.response(request); assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); @@ -129,7 +129,7 @@ public void requestHasInvalidStringLogLevelParameter() { new JsonRpcRequestContext( new JsonRpcRequest("2.0", "admin_changeLogLevel", new String[] {"INVALID"})); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actualResponse = adminChangeLogLevel.response(request); assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); @@ -141,7 +141,7 @@ public void requestHasInvalidLogFilterParameter() { new JsonRpcRequestContext( new JsonRpcRequest("2.0", "admin_changeLogLevel", new Object[] {"DEBUG", "INVALID"})); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actualResponse = adminChangeLogLevel.response(request); assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminGenerateLogBloomCacheTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminGenerateLogBloomCacheTest.java index 72981bda355..ec56c83f330 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminGenerateLogBloomCacheTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminGenerateLogBloomCacheTest.java @@ -29,15 +29,15 @@ import java.util.List; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.StrictStubs.class) +@ExtendWith(MockitoExtension.class) public class AdminGenerateLogBloomCacheTest { @Mock private BlockchainQueries blockchainQueries; @@ -47,7 +47,7 @@ public class AdminGenerateLogBloomCacheTest { private AdminGenerateLogBloomCache method; - @Before + @BeforeEach public void setup() { method = new AdminGenerateLogBloomCache(blockchainQueries); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminLogsRemoveCacheTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminLogsRemoveCacheTest.java index 788d3126288..fbe27b42fb9 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminLogsRemoveCacheTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminLogsRemoveCacheTest.java @@ -22,10 +22,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.query.cache.TransactionLogBloomCacher; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -36,15 +36,15 @@ import java.util.Map; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class AdminLogsRemoveCacheTest { @Mock private BlockchainQueries blockchainQueries; @Mock private Blockchain blockchain; @@ -55,7 +55,7 @@ public class AdminLogsRemoveCacheTest { private AdminLogsRemoveCache adminLogsRemoveCache; - @Before + @BeforeEach public void setup() { adminLogsRemoveCache = new AdminLogsRemoveCache(blockchainQueries); } @@ -152,7 +152,7 @@ public void requestBlockRangeInvalidTest() { new JsonRpcRequestContext( new JsonRpcRequest("2.0", "admin_logsRemoveCache", new String[] {"0x20", "0x1"})); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); when(blockchainQueries.getBlockchain()).thenReturn(blockchain); when(blockchain.getBlockByNumber(anyLong())).thenReturn(Optional.of(block)); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminLogsRepairCacheTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminLogsRepairCacheTest.java index 226eafb17b4..34253e40044 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminLogsRepairCacheTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminLogsRepairCacheTest.java @@ -32,13 +32,13 @@ import java.util.Map; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class AdminLogsRepairCacheTest { @Mock private BlockchainQueries blockchainQueries; @Mock private Blockchain blockchain; @@ -47,7 +47,7 @@ public class AdminLogsRepairCacheTest { private AdminLogsRepairCache adminLogsRepairCache; - @Before + @BeforeEach public void setup() { adminLogsRepairCache = new AdminLogsRepairCache(blockchainQueries); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminNodeInfoTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminNodeInfoTest.java index b87bf4df4fc..57120d4a4fa 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminNodeInfoTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminNodeInfoTest.java @@ -24,10 +24,10 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.ChainHead; @@ -50,13 +50,16 @@ import com.google.common.collect.ImmutableMap; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.StrictStubs.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class AdminNodeInfoTest { @Mock private P2PNetwork p2pNetwork; @@ -81,7 +84,7 @@ public class AdminNodeInfoTest { .listeningPort(30303) .build()); - @Before + @BeforeEach public void setup() { when(blockHeader.getHash()).thenReturn(Hash.EMPTY); final ChainHead testChainHead = new ChainHead(blockHeader, Difficulty.ONE, 1L); @@ -334,7 +337,7 @@ public void returnsErrorWhenP2PDisabled() { final JsonRpcRequestContext request = adminNodeInfo(); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.P2P_DISABLED); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.P2P_DISABLED); final JsonRpcResponse response = method.response(request); assertThat(response).isInstanceOf(JsonRpcErrorResponse.class); @@ -349,7 +352,7 @@ public void returnsErrorWhenP2PNotReady() { final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.P2P_NETWORK_NOT_RUNNING); + request.getRequest().getId(), RpcErrorType.P2P_NETWORK_NOT_RUNNING); final JsonRpcResponse response = method.response(request); assertThat(response).isInstanceOf(JsonRpcErrorResponse.class); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminPeersTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminPeersTest.java index 5123c29fc56..1835a498835 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminPeersTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminPeersTest.java @@ -20,10 +20,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.MockPeerConnection; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.PeerResult; import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; import org.hyperledger.besu.ethereum.eth.manager.EthPeer; @@ -43,13 +43,13 @@ import io.vertx.core.json.Json; import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class AdminPeersTest { private AdminPeers adminPeers; @@ -59,7 +59,7 @@ public class AdminPeersTest { @Mock private EthPeers ethPeers; - @Before + @BeforeEach public void before() { adminPeers = new AdminPeers(ethPeers); } @@ -102,7 +102,7 @@ public void shouldFailIfP2pDisabled() { final JsonRpcRequestContext request = adminPeers(); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.P2P_DISABLED); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.P2P_DISABLED); Assertions.assertThat(adminPeers.response(request)) .usingRecursiveComparison() diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminRemovePeerTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminRemovePeerTest.java index 21c2cf2462f..b2245b51b86 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminRemovePeerTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminRemovePeerTest.java @@ -20,23 +20,23 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork; import org.hyperledger.besu.ethereum.p2p.network.exceptions.P2PDisabledException; import org.hyperledger.besu.ethereum.p2p.peers.ImmutableEnodeDnsConfiguration; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.StrictStubs.class) +@ExtendWith(MockitoExtension.class) public class AdminRemovePeerTest { @Mock private P2PNetwork p2pNetwork; @@ -69,7 +69,7 @@ public class AdminRemovePeerTest { new JsonRpcRequestContext( new JsonRpcRequest("2.0", "admin_removePeer", new String[] {validDNSEnode})); - @Before + @BeforeEach public void setup() { method = new AdminRemovePeer( @@ -102,7 +102,7 @@ public void requestIsMissingParameter() { final JsonRpcRequestContext request = new JsonRpcRequestContext(new JsonRpcRequest("2.0", "admin_removePeer", new String[] {})); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actualResponse = method.response(request); @@ -114,7 +114,7 @@ public void requestHasNullObjectParameter() { final JsonRpcRequestContext request = new JsonRpcRequestContext(new JsonRpcRequest("2.0", "admin_removePeer", null)); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actualResponse = method.response(request); @@ -127,7 +127,7 @@ public void requestHasNullArrayParameter() { new JsonRpcRequestContext( new JsonRpcRequest("2.0", "admin_removePeer", new String[] {null})); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actualResponse = method.response(request); @@ -140,7 +140,7 @@ public void requestHasInvalidEnode() { new JsonRpcRequestContext( new JsonRpcRequest("2.0", "admin_removePeer", new String[] {"asdf"})); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.PARSE_ERROR); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.PARSE_ERROR); final JsonRpcResponse actualResponse = method.response(request); @@ -160,7 +160,7 @@ public void requestHasInvalidEnodeLength() { new JsonRpcRequestContext( new JsonRpcRequest("2.0", "admin_removePeer", new String[] {invalidLengthEnode})); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.ENODE_ID_INVALID); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.ENODE_ID_INVALID); final JsonRpcResponse actualResponse = method.response(request); @@ -197,7 +197,7 @@ public void requestRemovesValidDNSEnode() { public void requestRemovesDNSEnodeButDNSDisabled() { final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( - validDNSRequest.getRequest().getId(), JsonRpcError.DNS_NOT_ENABLED); + validDNSRequest.getRequest().getId(), RpcErrorType.DNS_NOT_ENABLED); final JsonRpcResponse actualResponse = methodDNSDisabled.response(validDNSRequest); @@ -208,7 +208,7 @@ public void requestRemovesDNSEnodeButDNSDisabled() { public void requestRemovesDNSEnodeButDNSNotResolved() { final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( - validDNSRequest.getRequest().getId(), JsonRpcError.CANT_RESOLVE_PEER_ENODE_DNS); + validDNSRequest.getRequest().getId(), RpcErrorType.CANT_RESOLVE_PEER_ENODE_DNS); final JsonRpcResponse actualResponse = methodDNSUpdateDisabled.response(validDNSRequest); @@ -222,7 +222,7 @@ public void requestRefusesListOfNodes() { new JsonRpcRequest("2.0", "admin_removePeer", new String[] {validEnode, validEnode})); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actualResponse = method.response(request); @@ -249,7 +249,7 @@ public void requestReturnsErrorWhenP2pDisabled() { "P2P networking disabled. Unable to connect to remove peer.")); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(validRequest.getRequest().getId(), JsonRpcError.P2P_DISABLED); + new JsonRpcErrorResponse(validRequest.getRequest().getId(), RpcErrorType.P2P_DISABLED); final JsonRpcResponse actualResponse = method.response(validRequest); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugAccountAtTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugAccountAtTest.java index cc97c40bb38..d7840241d5a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugAccountAtTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugAccountAtTest.java @@ -27,10 +27,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTracer; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.Tracer; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.DebugAccountAtResult; import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; @@ -97,8 +97,8 @@ void testBlockNotFoundResponse() { final JsonRpcResponse response = debugAccountAt.response(request); Assertions.assertThat(response).isInstanceOf(JsonRpcErrorResponse.class); - Assertions.assertThat(((JsonRpcErrorResponse) response).getError()) - .isEqualByComparingTo(JsonRpcError.BLOCK_NOT_FOUND); + Assertions.assertThat(((JsonRpcErrorResponse) response).getErrorType()) + .isEqualByComparingTo(RpcErrorType.BLOCK_NOT_FOUND); } @Test @@ -112,8 +112,8 @@ void testInvalidParamsResponseEmptyList() { final JsonRpcResponse response = debugAccountAt.response(request); Assertions.assertThat(response).isInstanceOf(JsonRpcErrorResponse.class); - Assertions.assertThat(((JsonRpcErrorResponse) response).getError()) - .isEqualByComparingTo(JsonRpcError.INVALID_PARAMS); + Assertions.assertThat(((JsonRpcErrorResponse) response).getErrorType()) + .isEqualByComparingTo(RpcErrorType.INVALID_PARAMS); } @Test @@ -128,8 +128,8 @@ void testInvalidParamsResponseNegative() { final JsonRpcResponse response = debugAccountAt.response(request); Assertions.assertThat(response).isInstanceOf(JsonRpcErrorResponse.class); - Assertions.assertThat(((JsonRpcErrorResponse) response).getError()) - .isEqualByComparingTo(JsonRpcError.INVALID_PARAMS); + Assertions.assertThat(((JsonRpcErrorResponse) response).getErrorType()) + .isEqualByComparingTo(RpcErrorType.INVALID_PARAMS); } @Test @@ -144,8 +144,8 @@ void testInvalidParamsResponseTooHigh() { final JsonRpcResponse response = debugAccountAt.response(request); Assertions.assertThat(response).isInstanceOf(JsonRpcErrorResponse.class); - Assertions.assertThat(((JsonRpcErrorResponse) response).getError()) - .isEqualByComparingTo(JsonRpcError.INVALID_PARAMS); + Assertions.assertThat(((JsonRpcErrorResponse) response).getErrorType()) + .isEqualByComparingTo(RpcErrorType.INVALID_PARAMS); } @Test @@ -169,8 +169,8 @@ void testTransactionNotFoundResponse() { final JsonRpcResponse response = debugAccountAt.response(request); Assertions.assertThat(response).isInstanceOf(JsonRpcErrorResponse.class); - Assertions.assertThat(((JsonRpcErrorResponse) response).getError()) - .isEqualByComparingTo(JsonRpcError.TRANSACTION_NOT_FOUND); + Assertions.assertThat(((JsonRpcErrorResponse) response).getErrorType()) + .isEqualByComparingTo(RpcErrorType.TRANSACTION_NOT_FOUND); } @Test @@ -194,8 +194,8 @@ void testNoAccountFoundResponse() { final JsonRpcResponse response = debugAccountAt.response(request); Assertions.assertThat(response).isInstanceOf(JsonRpcErrorResponse.class); - Assertions.assertThat(((JsonRpcErrorResponse) response).getError()) - .isEqualByComparingTo(JsonRpcError.NO_ACCOUNT_FOUND); + Assertions.assertThat(((JsonRpcErrorResponse) response).getErrorType()) + .isEqualByComparingTo(RpcErrorType.NO_ACCOUNT_FOUND); } @Test diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugBatchSendRawTransactionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugBatchSendRawTransactionTest.java index c72b3f917d0..bb4226f0b35 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugBatchSendRawTransactionTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugBatchSendRawTransactionTest.java @@ -29,13 +29,13 @@ import java.util.List; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) @SuppressWarnings("unchecked") public class DebugBatchSendRawTransactionTest { @@ -44,7 +44,7 @@ public class DebugBatchSendRawTransactionTest { @Mock TransactionPool transactionPool; DebugBatchSendRawTransaction method; - @Before + @BeforeEach public void setUp() { method = new DebugBatchSendRawTransaction(transactionPool); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugGetBadBlockTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugGetBadBlockTest.java index 21fa5c50be9..685641f111d 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugGetBadBlockTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugGetBadBlockTest.java @@ -42,7 +42,7 @@ import java.util.List; import java.util.Optional; -import org.junit.Test; +import org.junit.jupiter.api.Test; @SuppressWarnings("unchecked") public class DebugGetBadBlockTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugMetricsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugMetricsTest.java index c438ff97fec..6e41fc9c1bf 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugMetricsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugMetricsTest.java @@ -31,7 +31,7 @@ import java.util.stream.Stream; import com.google.common.collect.ImmutableMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class DebugMetricsTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStandardTraceBadBlockToFileTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStandardTraceBadBlockToFileTest.java index 1c749df131e..207ebd73f3b 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStandardTraceBadBlockToFileTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStandardTraceBadBlockToFileTest.java @@ -37,20 +37,20 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; +import java.nio.file.Path; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Optional; import java.util.function.Function; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; public class DebugStandardTraceBadBlockToFileTest { - @ClassRule public static final TemporaryFolder folder = new TemporaryFolder(); + @TempDir private static Path folder; private final BlockchainQueries blockchainQueries = mock(BlockchainQueries.class); private final Blockchain blockchain = mock(Blockchain.class); @@ -62,9 +62,9 @@ public class DebugStandardTraceBadBlockToFileTest { private final DebugStandardTraceBadBlockToFile debugStandardTraceBadBlockToFile = new DebugStandardTraceBadBlockToFile( - () -> transactionTracer, blockchainQueries, protocolSchedule, folder.getRoot().toPath()); + () -> transactionTracer, blockchainQueries, protocolSchedule, folder); - @Before + @BeforeEach public void setup() { doAnswer( invocation -> diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStandardTraceBlockToFileTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStandardTraceBlockToFileTest.java index ddae8a94ffe..073c604c111 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStandardTraceBlockToFileTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStandardTraceBlockToFileTest.java @@ -32,19 +32,19 @@ import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import java.nio.file.Path; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Optional; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import org.mockito.Answers; public class DebugStandardTraceBlockToFileTest { - @ClassRule public static final TemporaryFolder folder = new TemporaryFolder(); + @TempDir private static Path folder; private final WorldStateArchive archive = mock(WorldStateArchive.class, Answers.RETURNS_DEEP_STUBS); @@ -53,8 +53,7 @@ public class DebugStandardTraceBlockToFileTest { spy(new BlockchainQueries(blockchain, archive)); private final TransactionTracer transactionTracer = mock(TransactionTracer.class); private final DebugStandardTraceBlockToFile debugStandardTraceBlockToFile = - new DebugStandardTraceBlockToFile( - () -> transactionTracer, blockchainQueries, folder.getRoot().toPath()); + new DebugStandardTraceBlockToFile(() -> transactionTracer, blockchainQueries, folder); @Test public void nameShouldBeDebugTraceTransaction() { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStorageRangeAtTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStorageRangeAtTest.java index 5767b1b0085..0fa791fcc02 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStorageRangeAtTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStorageRangeAtTest.java @@ -55,8 +55,8 @@ import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Answers; import org.mockito.invocation.InvocationOnMock; @@ -82,7 +82,7 @@ public class DebugStorageRangeAtTest { Hash.fromHexString("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); private final Address accountAddress = Address.MODEXP; - @Before + @BeforeEach public void setUp() { when(transaction.getHash()).thenReturn(transactionHash); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockByHashTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockByHashTest.java index 253dffb1dce..c6857bec332 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockByHashTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockByHashTest.java @@ -44,8 +44,8 @@ import java.util.function.Function; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Answers; public class DebugTraceBlockByHashTest { @@ -62,7 +62,7 @@ public class DebugTraceBlockByHashTest { private final Hash blockHash = Hash.fromHexString("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); - @Before + @BeforeEach public void setUp() { doAnswer( invocation -> diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockByNumberTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockByNumberTest.java index 2b78ec562da..9b23ab12e91 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockByNumberTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockByNumberTest.java @@ -45,7 +45,7 @@ import java.util.function.Function; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.Answers; public class DebugTraceBlockByNumberTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockTest.java index df337f44f2f..60841c24ef4 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockTest.java @@ -30,9 +30,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTracer; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.Tracer; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -49,7 +49,7 @@ import java.util.OptionalLong; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.Answers; import org.mockito.Mockito; @@ -165,6 +165,6 @@ public void shouldReturnErrorResponseWhenParentBlockMissing() { when(blockchainQueries.blockByHash(any())).thenReturn(Optional.empty()); final JsonRpcErrorResponse response = (JsonRpcErrorResponse) debugTraceBlock.response(request); - assertThat(response.getError()).isEqualByComparingTo(JsonRpcError.PARENT_BLOCK_NOT_FOUND); + assertThat(response.getErrorType()).isEqualByComparingTo(RpcErrorType.PARENT_BLOCK_NOT_FOUND); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceTransactionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceTransactionTest.java index c7c0aca44a6..580897abb8f 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceTransactionTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceTransactionTest.java @@ -51,8 +51,8 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Answers; public class DebugTraceTransactionTest { @@ -71,7 +71,7 @@ public class DebugTraceTransactionTest { private final Hash transactionHash = Hash.fromHexString("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); - @Before + @BeforeEach public void setup() { doAnswer(__ -> Optional.of(blockHeader)) .when(blockchainQueries) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlockNumberTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlockNumberTest.java index 373bbbf4b46..9a532cb1dfe 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlockNumberTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlockNumberTest.java @@ -24,13 +24,13 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EthBlockNumberTest { private final String JSON_RPC_VERSION = "2.0"; @@ -39,7 +39,7 @@ public class EthBlockNumberTest { @Mock private BlockchainQueries blockchainQueries; private EthBlockNumber method; - @Before + @BeforeEach public void setUp() { method = new EthBlockNumber(blockchainQueries); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java index 5bdda906415..7580d511df8 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java @@ -15,8 +15,9 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; import static org.assertj.core.api.Assertions.assertThat; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.BLOCK_NOT_FOUND; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INTERNAL_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.BLOCK_NOT_FOUND; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INTERNAL_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.REVERT_ERROR; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; @@ -32,6 +33,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; @@ -44,6 +46,7 @@ import org.hyperledger.besu.ethereum.mainnet.ImmutableTransactionValidationParams; import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; +import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; import org.hyperledger.besu.ethereum.transaction.CallParameter; import org.hyperledger.besu.ethereum.transaction.PreCloseStateHandler; import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; @@ -52,15 +55,18 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class EthCallTest { private EthCall method; @@ -74,7 +80,7 @@ public class EthCallTest { @Captor ArgumentCaptor>> mapperCaptor; - @Before + @BeforeEach public void setUp() { method = new EthCall(blockchainQueries, transactionSimulator); blockHeader = mock(BlockHeader.class); @@ -161,6 +167,128 @@ public void shouldReturnExecutionResultWhenExecutionIsSuccessful() { verifyNoMoreInteractions(blockchainQueries); } + @Test + public void shouldReturnBasicExecutionRevertErrorWithoutReason() { + final JsonRpcRequestContext request = ethCallRequest(callParameter(), "latest"); + + // Expect a revert error with no decoded reason (error doesn't begin "Error(string)" so ignored) + final String abiHexString = "0x1234"; + final JsonRpcError expectedError = new JsonRpcError(REVERT_ERROR, abiHexString); + final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse(null, expectedError); + + assertThat(((JsonRpcErrorResponse) expectedResponse).getError().getMessage()) + .isEqualTo("Execution reverted"); + + mockTransactionProcessorSuccessResult(expectedResponse); + when(blockchainQueries.getBlockchain()).thenReturn(blockchain); + when(blockchain.getChainHead()).thenReturn(chainHead); + + final BlockHeader blockHeader = mock(BlockHeader.class); + when(blockHeader.getBaseFee()).thenReturn(Optional.of(Wei.ZERO)); + when(chainHead.getBlockHeader()).thenReturn(blockHeader); + + final JsonRpcResponse response = method.response(request); + + final TransactionProcessingResult processingResult = + new TransactionProcessingResult( + null, null, 0, 0, null, null, Optional.of(Bytes.fromHexString(abiHexString))); + + final TransactionSimulatorResult result = mock(TransactionSimulatorResult.class); + when(result.isSuccessful()).thenReturn(false); + when(result.getValidationResult()).thenReturn(ValidationResult.valid()); + when(result.getResult()).thenReturn(processingResult); + verify(transactionSimulator).process(any(), any(), any(), mapperCaptor.capture(), any()); + assertThat(mapperCaptor.getValue().apply(mock(MutableWorldState.class), Optional.of(result))) + .isEqualTo(Optional.of(expectedResponse)); + + assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse); + assertThat(((JsonRpcErrorResponse) response).getError().getMessage()) + .isEqualTo("Execution reverted"); + } + + @Test + public void shouldReturnExecutionRevertErrorWithABIParseError() { + final JsonRpcRequestContext request = ethCallRequest(callParameter(), "latest"); + + // Expect a revert error with no decoded reason (error begins with "Error(string)" but trailing + // bytes are invalid ABI) + final String abiHexString = "0x08c379a002d36d"; + final JsonRpcError expectedError = new JsonRpcError(REVERT_ERROR, abiHexString); + final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse(null, expectedError); + + assertThat(((JsonRpcErrorResponse) expectedResponse).getError().getMessage()) + .isEqualTo("Execution reverted: ABI decode error"); + + mockTransactionProcessorSuccessResult(expectedResponse); + when(blockchainQueries.getBlockchain()).thenReturn(blockchain); + when(blockchain.getChainHead()).thenReturn(chainHead); + + final BlockHeader blockHeader = mock(BlockHeader.class); + when(blockHeader.getBaseFee()).thenReturn(Optional.of(Wei.ZERO)); + when(chainHead.getBlockHeader()).thenReturn(blockHeader); + + final JsonRpcResponse response = method.response(request); + final TransactionProcessingResult processingResult = + new TransactionProcessingResult( + null, null, 0, 0, null, null, Optional.of(Bytes.fromHexString(abiHexString))); + + final TransactionSimulatorResult result = mock(TransactionSimulatorResult.class); + when(result.isSuccessful()).thenReturn(false); + when(result.getValidationResult()).thenReturn(ValidationResult.valid()); + when(result.getResult()).thenReturn(processingResult); + verify(transactionSimulator).process(any(), any(), any(), mapperCaptor.capture(), any()); + assertThat(mapperCaptor.getValue().apply(mock(MutableWorldState.class), Optional.of(result))) + .isEqualTo(Optional.of(expectedResponse)); + + assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse); + assertThat(((JsonRpcErrorResponse) response).getError().getMessage()) + .isEqualTo("Execution reverted: ABI decode error"); + } + + @Test + public void shouldReturnExecutionRevertErrorWithParsedABI() { + final JsonRpcRequestContext request = ethCallRequest(callParameter(), "latest"); + + // Expect a revert error with decoded reason (error begins with "Error(string)", trailing bytes + // = "ERC20: transfer from the zero address") + final String abiHexString = + "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002545524332303a207472616e736665722066726f6d20746865207a65726f2061646472657373000000000000000000000000000000000000000000000000000000"; + final JsonRpcError expectedError = new JsonRpcError(REVERT_ERROR, abiHexString); + final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse(null, expectedError); + + assertThat(((JsonRpcErrorResponse) expectedResponse).getError().getMessage()) + .isEqualTo("Execution reverted: ERC20: transfer from the zero address"); + + mockTransactionProcessorSuccessResult(expectedResponse); + when(blockchainQueries.getBlockchain()).thenReturn(blockchain); + when(blockchain.getChainHead()).thenReturn(chainHead); + + final BlockHeader blockHeader = mock(BlockHeader.class); + when(blockHeader.getBaseFee()).thenReturn(Optional.of(Wei.ZERO)); + when(chainHead.getBlockHeader()).thenReturn(blockHeader); + + final JsonRpcResponse response = method.response(request); + + final TransactionProcessingResult processingResult = + new TransactionProcessingResult( + null, null, 0, 0, null, null, Optional.of(Bytes.fromHexString(abiHexString))); + + final TransactionSimulatorResult result = mock(TransactionSimulatorResult.class); + when(result.isSuccessful()).thenReturn(false); + when(result.getValidationResult()).thenReturn(ValidationResult.valid()); + when(result.getResult()).thenReturn(processingResult); + + verify(transactionSimulator).process(any(), any(), any(), mapperCaptor.capture(), any()); + System.out.println(result); + System.out.println(expectedResponse); + assertThat(mapperCaptor.getValue().apply(mock(MutableWorldState.class), Optional.of(result))) + .isEqualTo(Optional.of(expectedResponse)); + + assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse); + assertThat(((JsonRpcErrorResponse) response).getError().getMessage()) + .isEqualTo("Execution reverted: ERC20: transfer from the zero address"); + } + @Test public void shouldUseCorrectBlockNumberWhenLatest() { final JsonRpcRequestContext request = ethCallRequest(callParameter(), "latest"); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthChainIdTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthChainIdTest.java index 2425b4299cc..2d049f3023e 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthChainIdTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthChainIdTest.java @@ -25,15 +25,15 @@ import java.math.BigInteger; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class EthChainIdTest { private EthChainId method; private final BigInteger CHAIN_ID = BigInteger.ONE; - @Before + @BeforeEach public void setUp() { method = new EthChainId(Optional.of(CHAIN_ID)); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCoinbaseTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCoinbaseTest.java index ddd0b7d4acb..8694bd0a2f4 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCoinbaseTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCoinbaseTest.java @@ -22,21 +22,21 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EthCoinbaseTest { @Mock private MiningCoordinator miningCoordinator; @@ -44,7 +44,7 @@ public class EthCoinbaseTest { private final String JSON_RPC_VERSION = "2.0"; private final String ETH_METHOD = "eth_coinbase"; - @Before + @BeforeEach public void setUp() { method = new EthCoinbase(miningCoordinator); } @@ -73,7 +73,7 @@ public void shouldReturnExpectedValueWhenMiningCoordinatorExists() { public void shouldReturnErrorWhenCoinbaseNotSpecified() { final JsonRpcRequestContext request = requestWithParams(); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.COINBASE_NOT_SPECIFIED); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.COINBASE_NOT_SPECIFIED); when(miningCoordinator.getCoinbase()).thenReturn(Optional.empty()); final JsonRpcResponse actualResponse = method.response(request); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCreateAccessListTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCreateAccessListTest.java index 06f9eed54e5..2d44f8997b8 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCreateAccessListTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCreateAccessListTest.java @@ -33,6 +33,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.CreateAccessListResult; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -52,15 +53,18 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.MockedStatic; import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class EthCreateAccessListTest { private final String METHOD = "eth_createAccessList"; @@ -72,7 +76,7 @@ public class EthCreateAccessListTest { @Mock private TransactionSimulator transactionSimulator; @Mock private WorldStateArchive worldStateArchive; - @Before + @BeforeEach public void setUp() { when(blockchainQueries.headBlockNumber()).thenReturn(1L); when(blockchainQueries.getBlockchain()).thenReturn(blockchain); @@ -143,7 +147,7 @@ public void shouldReturnErrorWhenWorldStateIsNotAvailable() { mockTransactionSimulatorResult(false, false, 1L); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.WORLD_STATE_UNAVAILABLE); + new JsonRpcErrorResponse(null, RpcErrorType.WORLD_STATE_UNAVAILABLE); Assertions.assertThat(method.response(request)) .usingRecursiveComparison() @@ -156,8 +160,9 @@ public void shouldReturnErrorWhenTransactionReverted() { ethCreateAccessListRequest(legacyTransactionCallParameter(Wei.ZERO)); mockTransactionSimulatorResult(false, true, 1L); + final String errorReason = "0x00"; final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.REVERT_ERROR); + new JsonRpcErrorResponse(null, new JsonRpcError(RpcErrorType.REVERT_ERROR, errorReason)); Assertions.assertThat(method.response(request)) .usingRecursiveComparison() diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java index 7280560a5ac..038aed5baa2 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java @@ -31,6 +31,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -50,13 +51,16 @@ import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class EthEstimateGasTest { private EthEstimateGas method; @@ -67,7 +71,7 @@ public class EthEstimateGasTest { @Mock private TransactionSimulator transactionSimulator; @Mock private WorldStateArchive worldStateArchive; - @Before + @BeforeEach public void setUp() { when(blockchainQueries.headBlockNumber()).thenReturn(1L); when(blockchainQueries.getBlockchain()).thenReturn(blockchain); @@ -97,7 +101,7 @@ public void shouldReturnErrorWhenTransientLegacyTransactionProcessorReturnsEmpty .thenReturn(Optional.empty()); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.INTERNAL_ERROR); + new JsonRpcErrorResponse(null, RpcErrorType.INTERNAL_ERROR); Assertions.assertThat(method.response(request)) .usingRecursiveComparison() @@ -115,7 +119,7 @@ public void shouldReturnErrorWhenTransientEip1559TransactionProcessorReturnsEmpt .thenReturn(Optional.empty()); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.INTERNAL_ERROR); + new JsonRpcErrorResponse(null, RpcErrorType.INTERNAL_ERROR); Assertions.assertThat(method.response(request)) .usingRecursiveComparison() @@ -140,7 +144,7 @@ public void shouldUseGasPriceParameterWhenIsPresent() { final Wei gasPrice = Wei.of(1000); final JsonRpcRequestContext request = ethEstimateGasRequest(defaultLegacyTransactionCallParameter(gasPrice)); - mockTransientProcessorResultGasEstimate(1L, true, false, gasPrice); + mockTransientProcessorResultGasEstimate(1L, true, gasPrice, Optional.empty()); final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, Quantity.create(1L)); @@ -179,7 +183,7 @@ public void shouldReturnGasEstimateErrorWhenGasPricePresentForEip1559Transaction mockTransientProcessorResultGasEstimate(1L, false, false); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.INTERNAL_ERROR); + new JsonRpcErrorResponse(null, RpcErrorType.INTERNAL_ERROR); Assertions.assertThat(method.response(request)) .usingRecursiveComparison() @@ -193,7 +197,7 @@ public void shouldReturnGasEstimateErrorWhenGasPricePresentForEip1559Transaction mockTransientProcessorResultGasEstimate(1L, false, false); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.INTERNAL_ERROR); + new JsonRpcErrorResponse(null, RpcErrorType.INTERNAL_ERROR); Assertions.assertThat(method.response(request)) .usingRecursiveComparison() @@ -208,7 +212,7 @@ public void shouldReturnErrorWhenLegacyTransactionProcessorReturnsTxInvalidReaso TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE); + new JsonRpcErrorResponse(null, RpcErrorType.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE); Assertions.assertThat(method.response(request)) .usingRecursiveComparison() @@ -222,7 +226,7 @@ public void shouldReturnErrorWhenEip1559TransactionProcessorReturnsTxInvalidReas TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE); + new JsonRpcErrorResponse(null, RpcErrorType.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE); Assertions.assertThat(method.response(request)) .usingRecursiveComparison() @@ -237,7 +241,7 @@ public void shouldReturnErrorWhenWorldStateIsNotAvailable() { mockTransientProcessorResultGasEstimate(1L, false, false); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.WORLD_STATE_UNAVAILABLE); + new JsonRpcErrorResponse(null, RpcErrorType.WORLD_STATE_UNAVAILABLE); Assertions.assertThat(method.response(request)) .usingRecursiveComparison() @@ -251,11 +255,73 @@ public void shouldReturnErrorWhenTransactionReverted() { mockTransientProcessorResultGasEstimate(1L, false, true); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.REVERT_ERROR); + new JsonRpcErrorResponse(null, new JsonRpcError(RpcErrorType.REVERT_ERROR, "0x00")); - Assertions.assertThat(method.response(request)) - .usingRecursiveComparison() - .isEqualTo(expectedResponse); + assertThat(((JsonRpcErrorResponse) expectedResponse).getError().getMessage()) + .isEqualTo("Execution reverted"); + + final JsonRpcResponse actualResponse = method.response(request); + + Assertions.assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); + + assertThat(((JsonRpcErrorResponse) actualResponse).getError().getMessage()) + .isEqualTo("Execution reverted"); + } + + @Test + public void shouldReturnErrorReasonWhenTransactionReverted() { + final JsonRpcRequestContext request = + ethEstimateGasRequest(defaultLegacyTransactionCallParameter(Wei.ZERO)); + + // ABI encoding of EVM "Error(string)" prefix + "ERC20: transfer from the zero address" + final String executionRevertedReason = + "0x08c379a000000000000000000000000000000000000000000000000000000000" + + "000000200000000000000000000000000000000000000000000000000000000000" + + "00002545524332303a207472616e736665722066726f6d20746865207a65726f20" + + "61646472657373000000000000000000000000000000000000000000000000000000"; + + mockTransientProcessorTxReverted(1L, false, Bytes.fromHexString(executionRevertedReason)); + + final JsonRpcResponse expectedResponse = + new JsonRpcErrorResponse( + null, new JsonRpcError(RpcErrorType.REVERT_ERROR, executionRevertedReason)); + + assertThat(((JsonRpcErrorResponse) expectedResponse).getError().getMessage()) + .isEqualTo("Execution reverted: ERC20: transfer from the zero address"); + + final JsonRpcResponse actualResponse = method.response(request); + + Assertions.assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); + + assertThat(((JsonRpcErrorResponse) actualResponse).getError().getMessage()) + .isEqualTo("Execution reverted: ERC20: transfer from the zero address"); + } + + @Test + public void shouldReturnABIDecodeErrorReasonWhenInvalidRevertReason() { + final JsonRpcRequestContext request = + ethEstimateGasRequest(defaultLegacyTransactionCallParameter(Wei.ZERO)); + + // Invalid ABI bytes + final String invalidRevertReason = + "0x08c379a000000000000000000000000000000000000000000000000000000000" + + "123451234512345123451234512345123451234512345123451234512345123451"; + + mockTransientProcessorTxReverted(1L, false, Bytes.fromHexString(invalidRevertReason)); + + final JsonRpcResponse expectedResponse = + new JsonRpcErrorResponse( + null, new JsonRpcError(RpcErrorType.REVERT_ERROR, invalidRevertReason)); + + assertThat(((JsonRpcErrorResponse) expectedResponse).getError().getMessage()) + .isEqualTo("Execution reverted: ABI decode error"); + + final JsonRpcResponse actualResponse = method.response(request); + + Assertions.assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); + + assertThat(((JsonRpcErrorResponse) actualResponse).getError().getMessage()) + .isEqualTo("Execution reverted: ABI decode error"); } @Test @@ -300,28 +366,38 @@ public void shouldNotIgnoreSenderBalanceAccountWhenStrictModeDisabled() { private void mockTransientProcessorResultTxInvalidReason(final TransactionInvalidReason reason) { final TransactionSimulatorResult mockTxSimResult = - getMockTransactionSimulatorResult(false, false, 0, Wei.ZERO); + getMockTransactionSimulatorResult(false, 0, Wei.ZERO, Optional.empty()); when(mockTxSimResult.getValidationResult()).thenReturn(ValidationResult.invalid(reason)); } + private void mockTransientProcessorTxReverted( + final long estimateGas, final boolean isSuccessful, final Bytes revertReason) { + mockTransientProcessorResultGasEstimate( + estimateGas, isSuccessful, Wei.ZERO, Optional.of(revertReason)); + } + private void mockTransientProcessorResultGasEstimate( final long estimateGas, final boolean isSuccessful, final boolean isReverted) { - mockTransientProcessorResultGasEstimate(estimateGas, isSuccessful, isReverted, Wei.ZERO); + mockTransientProcessorResultGasEstimate( + estimateGas, + isSuccessful, + Wei.ZERO, + isReverted ? Optional.of(Bytes.of(0)) : Optional.empty()); } private void mockTransientProcessorResultGasEstimate( final long estimateGas, final boolean isSuccessful, - final boolean isReverted, - final Wei gasPrice) { - getMockTransactionSimulatorResult(isSuccessful, isReverted, estimateGas, gasPrice); + final Wei gasPrice, + final Optional revertReason) { + getMockTransactionSimulatorResult(isSuccessful, estimateGas, gasPrice, revertReason); } private TransactionSimulatorResult getMockTransactionSimulatorResult( final boolean isSuccessful, - final boolean isReverted, final long estimateGas, - final Wei gasPrice) { + final Wei gasPrice, + final Optional revertReason) { final TransactionSimulatorResult mockTxSimResult = mock(TransactionSimulatorResult.class); when(transactionSimulator.process( eq(modifiedLegacyTransactionCallParameter(gasPrice)), @@ -335,10 +411,11 @@ private TransactionSimulatorResult getMockTransactionSimulatorResult( any(OperationTracer.class), eq(1L))) .thenReturn(Optional.of(mockTxSimResult)); + final TransactionProcessingResult mockResult = mock(TransactionProcessingResult.class); when(mockResult.getEstimateGasUsedByTransaction()).thenReturn(estimateGas); - when(mockResult.getRevertReason()) - .thenReturn(isReverted ? Optional.of(Bytes.of(0)) : Optional.empty()); + when(mockResult.getRevertReason()).thenReturn(revertReason); + when(mockTxSimResult.getResult()).thenReturn(mockResult); when(mockTxSimResult.isSuccessful()).thenReturn(isSuccessful); return mockTxSimResult; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthFeeHistoryTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthFeeHistoryTest.java index 24e00d2822a..9005c36d16b 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthFeeHistoryTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthFeeHistoryTest.java @@ -27,10 +27,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.FeeHistory; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.ImmutableFeeHistory; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.ImmutableFeeHistoryResult; @@ -43,8 +43,8 @@ import java.util.List; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class EthFeeHistoryTest { final BlockDataGenerator gen = new BlockDataGenerator(); @@ -52,7 +52,7 @@ public class EthFeeHistoryTest { private EthFeeHistory method; private ProtocolSchedule protocolSchedule; - @Before + @BeforeEach public void setUp() { protocolSchedule = mock(ProtocolSchedule.class); final Block genesisBlock = gen.genesisBlock(); @@ -108,20 +108,20 @@ public void allFieldsPresentForLatestBlock() { public void cantGetBlockHigherThanChainHead() { assertThat( ((JsonRpcErrorResponse) feeHistoryRequest("0x2", "11", new double[] {100.0})) - .getError()) - .isEqualTo(JsonRpcError.INVALID_PARAMS); + .getErrorType()) + .isEqualTo(RpcErrorType.INVALID_PARAMS); } @Test public void blockCountBounds() { assertThat( ((JsonRpcErrorResponse) feeHistoryRequest("0x0", "latest", new double[] {100.0})) - .getError()) - .isEqualTo(JsonRpcError.INVALID_PARAMS); + .getErrorType()) + .isEqualTo(RpcErrorType.INVALID_PARAMS); assertThat( ((JsonRpcErrorResponse) feeHistoryRequest("0x401", "latest", new double[] {100.0})) - .getError()) - .isEqualTo(JsonRpcError.INVALID_PARAMS); + .getErrorType()) + .isEqualTo(RpcErrorType.INVALID_PARAMS); } @Test diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java index 043a87d92ce..7c1d753e05a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java @@ -42,14 +42,14 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.internal.verification.VerificationModeFactory; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EthGasPriceTest { @Mock private PoWMiningCoordinator miningCoordinator; @@ -58,7 +58,7 @@ public class EthGasPriceTest { private final String JSON_RPC_VERSION = "2.0"; private final String ETH_METHOD = "eth_gasPrice"; - @Before + @BeforeEach public void setUp() { method = new EthGasPrice( @@ -164,6 +164,7 @@ private Object createFakeBlock(final Long height) { null, null, null, + null, null), new BlockBody( List.of( @@ -204,6 +205,7 @@ private Object createEmptyBlock(final Long height) { null, null, null, + null, null), new BlockBody(List.of(), List.of()))); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockByHashTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockByHashTest.java index e8c9ebe41e5..1747030ba60 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockByHashTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockByHashTest.java @@ -25,13 +25,13 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EthGetBlockByHashTest { @Mock private BlockchainQueries blockchainQueries; @@ -41,7 +41,7 @@ public class EthGetBlockByHashTest { private final String ETH_METHOD = "eth_getBlockByHash"; private final String ZERO_HASH = String.valueOf(Hash.ZERO); - @Before + @BeforeEach public void setUp() { method = new EthGetBlockByHash(blockchainQueries, blockResult); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockByNumberTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockByNumberTest.java index b766b093161..2d3390e7f30 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockByNumberTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockByNumberTest.java @@ -24,11 +24,11 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponseType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; @@ -42,13 +42,16 @@ import java.util.List; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class EthGetBlockByNumberTest { private static final String JSON_RPC_VERSION = "2.0"; private static final String ETH_METHOD = "eth_getBlockByNumber"; @@ -64,7 +67,7 @@ public class EthGetBlockByNumberTest { @Mock private Synchronizer synchronizer; @Mock private WorldStateArchive worldStateArchive; - @Before + @BeforeEach public void setUp() { blockchain = createInMemoryBlockchain(blockDataGenerator.genesisBlock()); @@ -139,7 +142,7 @@ public void errorWhenAskingFinalizedButFinalizedIsNotPresent() { JsonRpcResponse resp = method.response(requestWithParams("finalized", "false")); assertThat(resp.getType()).isEqualTo(JsonRpcResponseType.ERROR); JsonRpcErrorResponse errorResp = (JsonRpcErrorResponse) resp; - assertThat(errorResp.getError()).isEqualTo(JsonRpcError.UNKNOWN_BLOCK); + assertThat(errorResp.getErrorType()).isEqualTo(RpcErrorType.UNKNOWN_BLOCK); } @Test @@ -147,7 +150,7 @@ public void errorWhenAskingSafeButSafeIsNotPresent() { JsonRpcResponse resp = method.response(requestWithParams("safe", "false")); assertThat(resp.getType()).isEqualTo(JsonRpcResponseType.ERROR); JsonRpcErrorResponse errorResp = (JsonRpcErrorResponse) resp; - assertThat(errorResp.getError()).isEqualTo(JsonRpcError.UNKNOWN_BLOCK); + assertThat(errorResp.getErrorType()).isEqualTo(RpcErrorType.UNKNOWN_BLOCK); } @Test diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChangesTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChangesTest.java index 9791d2d0815..7bf8e1a9dde 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChangesTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChangesTest.java @@ -28,10 +28,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult; import org.hyperledger.besu.ethereum.core.LogWithMetadata; @@ -40,20 +40,20 @@ import com.google.common.collect.Lists; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EthGetFilterChangesTest { private EthGetFilterChanges method; @Mock FilterManager filterManager; - @Before + @BeforeEach public void setUp() { method = new EthGetFilterChanges(filterManager); } @@ -92,7 +92,7 @@ public void shouldThrowExceptionWhenInvalidParamsSupplied() { public void shouldReturnErrorResponseWhenFilterManagerDoesNotFindAnyFilters() { final JsonRpcRequestContext request = requestWithParams("0x1"); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.FILTER_NOT_FOUND); + new JsonRpcErrorResponse(null, RpcErrorType.FILTER_NOT_FOUND); when(filterManager.blockChanges(anyString())).thenReturn(null); when(filterManager.pendingTransactionChanges(anyString())).thenReturn(null); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogsTest.java index 04402a1abcc..ee9723c6672 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogsTest.java @@ -26,10 +26,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult; import org.hyperledger.besu.ethereum.core.LogWithMetadata; @@ -39,20 +39,20 @@ import com.google.common.collect.Lists; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EthGetFilterLogsTest { private EthGetFilterLogs method; @Mock FilterManager filterManager; - @Before + @BeforeEach public void setUp() { method = new EthGetFilterLogs(filterManager); } @@ -91,7 +91,7 @@ public void shouldReturnErrorWhenMissingFilterId() { public void shouldReturnFilterNotFoundWhenFilterManagerReturnsNull() { final JsonRpcRequestContext request = requestWithFilterId("NOT FOUND"); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.LOGS_FILTER_NOT_FOUND); + new JsonRpcErrorResponse(null, RpcErrorType.LOGS_FILTER_NOT_FOUND); when(filterManager.logs(eq("NOT FOUND"))).thenReturn(null); final JsonRpcResponse response = method.response(request); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetLogsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetLogsTest.java index ff3604d65e3..bd054c87d37 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetLogsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetLogsTest.java @@ -31,23 +31,23 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.BlockHeader; import java.util.ArrayList; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EthGetLogsTest { private EthGetLogs method; @@ -55,7 +55,7 @@ public class EthGetLogsTest { @Mock BlockchainQueries blockchainQueries; @Mock Optional maxLogRange; - @Before + @BeforeEach public void setUp() { method = new EthGetLogs(blockchainQueries, maxLogRange); } @@ -283,7 +283,7 @@ public void shouldFailIfParamsExceedMaxRange() { final JsonRpcResponse response = method.response(request); assertThat(response).isInstanceOf(JsonRpcErrorResponse.class); final JsonRpcErrorResponse errorResponse = (JsonRpcErrorResponse) response; - assertThat(errorResponse.getError()).isEqualTo(JsonRpcError.EXCEEDS_RPC_MAX_BLOCK_RANGE); + assertThat(errorResponse.getErrorType()).isEqualTo(RpcErrorType.EXCEEDS_RPC_MAX_BLOCK_RANGE); } private JsonRpcRequestContext buildRequest(final long fromBlock, final long toBlock) { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetMinerDataByBlockHashTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetMinerDataByBlockHashTest.java index f0fa298f0b6..653f6835f35 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetMinerDataByBlockHashTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetMinerDataByBlockHashTest.java @@ -43,13 +43,13 @@ import com.google.common.base.Suppliers; import org.assertj.core.util.Arrays; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EthGetMinerDataByBlockHashTest { @Mock private BlockchainQueries blockchainQueries; @Mock private ProtocolSchedule protocolSchedule; @@ -59,7 +59,7 @@ public class EthGetMinerDataByBlockHashTest { private final String ETH_METHOD = "eth_getMinerDataByBlockHash"; private final BlockHeaderTestFixture blockHeaderTestFixture = new BlockHeaderTestFixture(); - @Before + @BeforeEach public void before() { this.method = new EthGetMinerDataByBlockHash(Suppliers.ofInstance(blockchainQueries), protocolSchedule); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetMinerDataByBlockNumberTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetMinerDataByBlockNumberTest.java index 99e6e6889e8..5c0dc630bc2 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetMinerDataByBlockNumberTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetMinerDataByBlockNumberTest.java @@ -42,13 +42,13 @@ import java.util.Optional; import org.assertj.core.util.Arrays; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EthGetMinerDataByBlockNumberTest { @Mock private BlockchainQueries blockchainQueries; @Mock private ProtocolSchedule protocolSchedule; @@ -58,7 +58,7 @@ public class EthGetMinerDataByBlockNumberTest { private final String ETH_METHOD = "eth_getMinerDataByBlockNumber"; private final BlockHeaderTestFixture blockHeaderTestFixture = new BlockHeaderTestFixture(); - @Before + @BeforeEach public void before() { this.method = new EthGetMinerDataByBlockNumber(blockchainQueries, protocolSchedule); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetProofTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetProofTest.java index e361a5b688f..c9957ad8545 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetProofTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetProofTest.java @@ -31,10 +31,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.proof.GetProofResult; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -133,7 +133,7 @@ void errorWhenAccountNotFound() { when(archive.getAccountProof(any(Hash.class), any(Address.class), any())) .thenReturn(Optional.empty()); final JsonRpcErrorResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.NO_ACCOUNT_FOUND); + new JsonRpcErrorResponse(null, RpcErrorType.NO_ACCOUNT_FOUND); final JsonRpcRequestContext request = requestWithParams( @@ -150,7 +150,7 @@ void errorWhenAccountNotFound() { void errorWhenWorldStateUnavailable() { final JsonRpcErrorResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.WORLD_STATE_UNAVAILABLE); + new JsonRpcErrorResponse(null, RpcErrorType.WORLD_STATE_UNAVAILABLE); when(archive.getMutable(any(BlockHeader.class), anyBoolean())).thenReturn(Optional.empty()); final JsonRpcRequestContext request = diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByBlockHashAndIndexTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByBlockHashAndIndexTest.java index 6a31107ec70..8f515718102 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByBlockHashAndIndexTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByBlockHashAndIndexTest.java @@ -26,12 +26,12 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EthGetTransactionByBlockHashAndIndexTest { private EthGetTransactionByBlockHashAndIndex method; @Mock private BlockchainQueries blockchain; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByHashTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByHashTest.java index ecdb8fb67d0..4b1b3c2527d 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByHashTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByHashTest.java @@ -21,33 +21,33 @@ import static org.mockito.Mockito.when; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionCompleteResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionPendingResult; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; -import org.hyperledger.besu.plugin.data.Transaction; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EthGetTransactionByHashTest { private static final String VALID_TRANSACTION = @@ -58,11 +58,11 @@ public class EthGetTransactionByHashTest { private final String JSON_RPC_VERSION = "2.0"; private final String ETH_METHOD = "eth_getTransactionByHash"; - @Mock private PendingTransactions pendingTransactions; + @Mock private TransactionPool transactionPool; - @Before + @BeforeEach public void setUp() { - method = new EthGetTransactionByHash(blockchainQueries, pendingTransactions); + method = new EthGetTransactionByHash(blockchainQueries, transactionPool); } @Test @@ -76,7 +76,7 @@ public void shouldReturnErrorResponseIfMissingRequiredParameter() { final JsonRpcRequestContext context = new JsonRpcRequestContext(request); final JsonRpcErrorResponse expectedResponse = - new JsonRpcErrorResponse(request.getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actualResponse = method.response(context); @@ -87,7 +87,7 @@ public void shouldReturnErrorResponseIfMissingRequiredParameter() { public void shouldReturnNullResultWhenTransactionDoesNotExist() { final String transactionHash = "0xf9ef5f0cf02685711cdf687b72d4754901729b942f4ea7f956e7fb206cae2f9e"; - when(pendingTransactions.getTransactionByHash(eq(Hash.fromHexString(transactionHash)))) + when(transactionPool.getTransactionByHash(eq(Hash.fromHexString(transactionHash)))) .thenReturn(Optional.empty()); when(blockchainQueries.transactionByHash(eq(Hash.fromHexString(transactionHash)))) .thenReturn(Optional.empty()); @@ -110,7 +110,7 @@ public void shouldReturnPendingTransactionWhenTransactionExistsAndIsPending() { org.hyperledger.besu.ethereum.core.Transaction.readFrom( Bytes.fromHexString(VALID_TRANSACTION)); - when(pendingTransactions.getTransactionByHash(eq(transaction.getHash()))) + when(transactionPool.getTransactionByHash(eq(transaction.getHash()))) .thenReturn(Optional.of(transaction)); verifyNoInteractions(blockchainQueries); @@ -135,9 +135,9 @@ public void shouldReturnCompleteTransactionWhenTransactionExistsInBlockchain() { final TransactionWithMetadata transactionWithMetadata = new TransactionWithMetadata(transaction, 1, Optional.empty(), Hash.ZERO, 0); - when(pendingTransactions.getTransactionByHash(eq(transaction.getHash()))) + when(transactionPool.getTransactionByHash(eq(transaction.getHash()))) .thenReturn(Optional.empty()); - verifyNoMoreInteractions(pendingTransactions); + verifyNoMoreInteractions(transactionPool); when(blockchainQueries.transactionByHash(eq(transaction.getHash()))) .thenReturn(Optional.of(transactionWithMetadata)); @@ -158,9 +158,9 @@ public void shouldReturnCompleteTransactionWhenTransactionExistsInBlockchain() { @Test public void validateResultSpec() { - PendingTransaction pendingTx = getPendingTransactions().stream().findFirst().get(); + PendingTransaction pendingTx = getTransactionPool().stream().findFirst().get(); Hash hash = pendingTx.getHash(); - when(this.pendingTransactions.getTransactionByHash(hash)) + when(this.transactionPool.getTransactionByHash(hash)) .thenReturn(Optional.of(pendingTx.getTransaction())); final JsonRpcRequestContext request = new JsonRpcRequestContext( @@ -188,7 +188,7 @@ public void validateResultSpec() { assertThat(result.getS()).isNotNull(); } - private Set getPendingTransactions() { + private Set getTransactionPool() { final BlockDataGenerator gen = new BlockDataGenerator(); Transaction pendingTransaction = gen.transaction(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionCountTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionCountTest.java index 65fc57fa35b..c75aedbfd96 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionCountTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionCountTest.java @@ -27,7 +27,7 @@ import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.ChainHead; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import java.util.OptionalLong; @@ -42,19 +42,19 @@ public class EthGetTransactionCountTest { private EthGetTransactionCount ethGetTransactionCount; private final String pendingTransactionString = "0x00000000000000000000000000000000000000AA"; private final Object[] pendingParams = new Object[] {pendingTransactionString, "pending"}; - private PendingTransactions pendingTransactions; + private TransactionPool transactionPool; @BeforeEach public void setup() { - pendingTransactions = mock(PendingTransactions.class); - ethGetTransactionCount = new EthGetTransactionCount(blockchainQueries, pendingTransactions); + transactionPool = mock(TransactionPool.class); + ethGetTransactionCount = new EthGetTransactionCount(blockchainQueries, transactionPool); } @Test public void shouldUsePendingTransactionsWhenToldTo() { final Address address = Address.fromHexString(pendingTransactionString); - when(pendingTransactions.getNextNonceForSender(address)).thenReturn(OptionalLong.of(12)); + when(transactionPool.getNextNonceForSender(address)).thenReturn(OptionalLong.of(12)); mockGetTransactionCount(address, 7L); final JsonRpcRequestContext request = new JsonRpcRequestContext( @@ -68,7 +68,7 @@ public void shouldUsePendingTransactionsWhenToldTo() { public void shouldUseLatestTransactionsWhenNoPendingTransactions() { final Address address = Address.fromHexString(pendingTransactionString); - when(pendingTransactions.getNextNonceForSender(address)).thenReturn(OptionalLong.empty()); + when(transactionPool.getNextNonceForSender(address)).thenReturn(OptionalLong.empty()); mockGetTransactionCount(address, 7L); final JsonRpcRequestContext request = new JsonRpcRequestContext( @@ -83,7 +83,7 @@ public void shouldUseLatestWhenItIsBiggerThanPending() { final Address address = Address.fromHexString(pendingTransactionString); mockGetTransactionCount(address, 8); - when(pendingTransactions.getNextNonceForSender(Address.fromHexString(pendingTransactionString))) + when(transactionPool.getNextNonceForSender(Address.fromHexString(pendingTransactionString))) .thenReturn(OptionalLong.of(4)); final JsonRpcRequestContext request = new JsonRpcRequestContext( @@ -97,8 +97,7 @@ public void shouldUseLatestWhenItIsBiggerThanPending() { public void shouldReturnPendingWithHighNonce() { final Address address = Address.fromHexString(pendingTransactionString); - when(pendingTransactions.getNextNonceForSender(address)) - .thenReturn(OptionalLong.of(MAX_NONCE - 1)); + when(transactionPool.getNextNonceForSender(address)).thenReturn(OptionalLong.of(MAX_NONCE - 1)); mockGetTransactionCount(address, 7L); final JsonRpcRequestContext request = new JsonRpcRequestContext( @@ -112,8 +111,7 @@ public void shouldReturnPendingWithHighNonce() { public void shouldReturnLatestWithHighNonce() { final Address address = Address.fromHexString(pendingTransactionString); - when(pendingTransactions.getNextNonceForSender(address)) - .thenReturn(OptionalLong.of(MAX_NONCE - 2)); + when(transactionPool.getNextNonceForSender(address)).thenReturn(OptionalLong.of(MAX_NONCE - 2)); mockGetTransactionCount(address, MAX_NONCE - 1); final JsonRpcRequestContext request = new JsonRpcRequestContext( diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java index def0693a75b..6c094c12deb 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java @@ -15,13 +15,17 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import org.hyperledger.besu.crypto.SECPSignature; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.GasLimitCalculator; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; @@ -31,6 +35,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionReceiptStatusResult; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata; +import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.chain.TransactionLocation; +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; @@ -39,16 +47,20 @@ import org.hyperledger.besu.ethereum.mainnet.PoWHasher; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; +import org.hyperledger.besu.ethereum.mainnet.feemarket.CancunFeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; -import org.hyperledger.besu.plugin.data.TransactionType; +import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; import java.math.BigInteger; import java.util.Collections; +import java.util.List; import java.util.Optional; import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256s; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class EthGetTransactionReceiptTest { private final TransactionReceipt statusReceipt = @@ -82,10 +94,28 @@ public class EthGetTransactionReceiptTest { private final TransactionReceiptWithMetadata statusReceiptWithMetadata = TransactionReceiptWithMetadata.create( - statusReceipt, transaction, hash, 1, 2, Optional.empty(), blockHash, 4); + statusReceipt, + transaction, + hash, + 1, + 2, + Optional.empty(), + blockHash, + 4, + Optional.empty(), + Optional.empty()); private final TransactionReceiptWithMetadata rootReceiptWithMetaData = TransactionReceiptWithMetadata.create( - rootReceipt, transaction, hash, 1, 2, Optional.empty(), blockHash, 4); + rootReceipt, + transaction, + hash, + 1, + 2, + Optional.empty(), + blockHash, + 4, + Optional.empty(), + Optional.empty()); private final ProtocolSpec rootTransactionTypeSpec = new ProtocolSpec( @@ -115,6 +145,7 @@ public class EthGetTransactionReceiptTest { null, Optional.empty(), null, + true, true); private final ProtocolSpec statusTransactionTypeSpec = new ProtocolSpec( @@ -144,14 +175,18 @@ public class EthGetTransactionReceiptTest { null, Optional.empty(), null, + true, true); @SuppressWarnings("unchecked") private final ProtocolSchedule protocolSchedule = mock(ProtocolSchedule.class); - private final BlockchainQueries blockchain = mock(BlockchainQueries.class); + private final Blockchain blockchain = mock(Blockchain.class); + + private final BlockchainQueries blockchainQueries = + spy(new BlockchainQueries(blockchain, mock(WorldStateArchive.class))); private final EthGetTransactionReceipt ethGetTransactionReceipt = - new EthGetTransactionReceipt(blockchain); + new EthGetTransactionReceipt(blockchainQueries, protocolSchedule); private final String receiptString = "0xcbef69eaf44af151aa66677ae4b8d8c343a09f667c873a3a6f4558fa4051fa5f"; private final Hash receiptHash = @@ -162,8 +197,8 @@ public class EthGetTransactionReceiptTest { @Test public void shouldCreateAStatusTransactionReceiptWhenStatusTypeProtocol() { - when(blockchain.headBlockNumber()).thenReturn(1L); - when(blockchain.transactionReceiptByTransactionHash(receiptHash)) + when(blockchainQueries.headBlockNumber()).thenReturn(1L); + when(blockchainQueries.transactionReceiptByTransactionHash(receiptHash, protocolSchedule)) .thenReturn(Optional.of(statusReceiptWithMetadata)); when(protocolSchedule.getByBlockHeader(blockHeader(1))).thenReturn(statusTransactionTypeSpec); @@ -178,8 +213,8 @@ public void shouldCreateAStatusTransactionReceiptWhenStatusTypeProtocol() { @Test public void shouldCreateARootTransactionReceiptWhenRootTypeProtocol() { - when(blockchain.headBlockNumber()).thenReturn(1L); - when(blockchain.transactionReceiptByTransactionHash(receiptHash)) + when(blockchainQueries.headBlockNumber()).thenReturn(1L); + when(blockchainQueries.transactionReceiptByTransactionHash(receiptHash, protocolSchedule)) .thenReturn(Optional.of(rootReceiptWithMetaData)); when(protocolSchedule.getByBlockHeader(blockHeader(1))).thenReturn(rootTransactionTypeSpec); @@ -193,14 +228,23 @@ public void shouldCreateARootTransactionReceiptWhenRootTypeProtocol() { @Test public void shouldWorkFor1559Txs() { - when(blockchain.headBlockNumber()).thenReturn(1L); + when(blockchainQueries.headBlockNumber()).thenReturn(1L); final Transaction transaction1559 = new BlockDataGenerator().transaction(TransactionType.EIP1559); final Wei baseFee = Wei.ONE; final TransactionReceiptWithMetadata transactionReceiptWithMetadata = TransactionReceiptWithMetadata.create( - statusReceipt, transaction1559, hash, 1, 2, Optional.of(baseFee), blockHash, 4); - when(blockchain.transactionReceiptByTransactionHash(receiptHash)) + statusReceipt, + transaction1559, + hash, + 1, + 2, + Optional.of(baseFee), + blockHash, + 4, + Optional.empty(), + Optional.empty()); + when(blockchainQueries.transactionReceiptByTransactionHash(receiptHash, protocolSchedule)) .thenReturn(Optional.of(transactionReceiptWithMetadata)); when(protocolSchedule.getByBlockHeader(blockHeader(1))).thenReturn(rootTransactionTypeSpec); @@ -218,6 +262,63 @@ public void shouldWorkFor1559Txs() { transaction1559.getMaxFeePerGas().get())); } + /** + * Test case to verify that the TransactionReceiptStatusResult contains blob gas used and blob gas + * price when the transaction type is TransactionType#BLOB + */ + @Test + public void shouldContainBlobGasUsedAndBlobGasPriceWhenBlobTransaction() { + + var hash = Hash.wrap(Bytes32.random()); + mockBlockWithBlobTransaction(hash, 1L); + when(blockchain.getTxReceipts(hash)).thenReturn(Optional.of(List.of(statusReceipt))); + // Call the real method to get the transaction receipt by transaction hash + when(blockchainQueries.transactionReceiptByTransactionHash(receiptHash, protocolSchedule)) + .thenCallRealMethod(); + + final JsonRpcSuccessResponse response = + (JsonRpcSuccessResponse) ethGetTransactionReceipt.response(request); + final TransactionReceiptStatusResult result = + (TransactionReceiptStatusResult) response.getResult(); + + assertThat(result.getType()).isEqualTo("0x3"); + assertThat(result.getBlobGasUsed()).isEqualTo("0x20000"); + assertThat(result.getBlobGasPrice()).isEqualTo("0x1"); + } + + private void mockBlockWithBlobTransaction(final Hash blockHash, final long blockNumber) { + Hash parentHash = Hash.wrap(Bytes32.random()); + TransactionLocation transactionLocation = mock(TransactionLocation.class); + Block block = mock(Block.class); + BlockBody body = mock(BlockBody.class); + BlockHeader header = mock(BlockHeader.class); + BlockHeader parentHeader = mock(BlockHeader.class); + when(transactionLocation.getBlockHash()).thenReturn(blockHash); + when(transactionLocation.getTransactionIndex()).thenReturn(0); + when(header.getNumber()).thenReturn(blockNumber); + when(header.getBlockHash()).thenReturn(blockHash); + when(header.getParentHash()).thenReturn(parentHash); + when(blockchain.getBlockHeader(parentHash)).thenReturn(Optional.of(parentHeader)); + when(block.getHeader()).thenReturn(header); + when(block.getBody()).thenReturn(body); + when(body.getTransactions()) + .thenReturn(List.of(new BlockDataGenerator().transaction(TransactionType.BLOB))); + when(parentHeader.getExcessBlobGas()).thenReturn(Optional.of(BlobGas.of(1000))); + when(blockchain.getBlockByHash(blockHash)).thenReturn(Optional.of(block)); + mockProtocolSpec(header); + when(blockchain.getTransactionLocation(receiptHash)) + .thenReturn(Optional.of(transactionLocation)); + } + + private void mockProtocolSpec(final BlockHeader blockHeader) { + FeeMarket feeMarket = mock(CancunFeeMarket.class); + when(feeMarket.blobGasPricePerGas(any())).thenCallRealMethod(); + ProtocolSpec spec = mock(ProtocolSpec.class); + when(spec.getFeeMarket()).thenReturn(feeMarket); + when(spec.getGasCalculator()).thenReturn(new CancunGasCalculator()); + when(protocolSchedule.getByBlockHeader(blockHeader)).thenReturn(spec); + } + private BlockHeader blockHeader(final long number) { return new BlockHeaderTestFixture().number(number).buildHeader(); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockHashAndIndexTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockHashAndIndexTest.java index 6f59f146d39..07f8364615c 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockHashAndIndexTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockHashAndIndexTest.java @@ -44,13 +44,13 @@ import java.util.List; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EthGetUncleByBlockHashAndIndexTest { private final BlockHeaderTestFixture blockHeaderTestFixture = new BlockHeaderTestFixture(); @@ -61,7 +61,7 @@ public class EthGetUncleByBlockHashAndIndexTest { @Mock private BlockchainQueries blockchainQueries; - @Before + @BeforeEach public void before() { this.method = new EthGetUncleByBlockHashAndIndex(blockchainQueries); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockNumberAndIndexTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockNumberAndIndexTest.java index f07d55178f6..59b20d58466 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockNumberAndIndexTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockNumberAndIndexTest.java @@ -45,13 +45,13 @@ import java.util.List; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EthGetUncleByBlockNumberAndIndexTest { private final BlockHeaderTestFixture blockHeaderTestFixture = new BlockHeaderTestFixture(); @@ -61,7 +61,7 @@ public class EthGetUncleByBlockNumberAndIndexTest { @Mock private BlockchainQueries blockchainQueries; - @Before + @BeforeEach public void before() { this.method = new EthGetUncleByBlockNumberAndIndex(blockchainQueries); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetWorkTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetWorkTest.java index c49f032eca8..abd37b0b3e0 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetWorkTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetWorkTest.java @@ -19,10 +19,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator; import org.hyperledger.besu.ethereum.mainnet.DirectAcyclicGraphSeed; import org.hyperledger.besu.ethereum.mainnet.EpochCalculator; @@ -34,13 +34,13 @@ import com.google.common.io.BaseEncoding; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EthGetWorkTest { private EthGetWork method; @@ -50,7 +50,7 @@ public class EthGetWorkTest { @Mock private PoWMiningCoordinator miningCoordinator; - @Before + @BeforeEach public void setUp() { when(miningCoordinator.getEpochCalculator()) .thenReturn(new EpochCalculator.DefaultEpochCalculator()); @@ -136,7 +136,7 @@ public void shouldReturnCorrectResultOnHighBlockSeedEcip1099() { public void shouldReturnErrorOnNoneMiningNode() { final JsonRpcRequestContext request = requestWithParams(); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.NO_MINING_WORK_FOUND); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.NO_MINING_WORK_FOUND); when(miningCoordinator.getWorkDefinition()).thenReturn(Optional.empty()); final JsonRpcResponse actualResponse = method.response(request); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthHashrateTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthHashrateTest.java index d4ada3f2779..1b14ec5cf6e 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthHashrateTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthHashrateTest.java @@ -25,13 +25,13 @@ import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EthHashrateTest { @Mock private PoWMiningCoordinator miningCoordinator; @@ -39,7 +39,7 @@ public class EthHashrateTest { private final String JSON_RPC_VERSION = "2.0"; private final String ETH_METHOD = "eth_hashrate"; - @Before + @BeforeEach public void setUp() { method = new EthHashrate(miningCoordinator); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMiningTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMiningTest.java index c118e0c7be8..ae7fa8a8245 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMiningTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMiningTest.java @@ -25,13 +25,13 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EthMiningTest { @Mock private PoWMiningCoordinator miningCoordinator; @@ -39,7 +39,7 @@ public class EthMiningTest { private final String JSON_RPC_VERSION = "2.0"; private final String ETH_METHOD = "eth_mining"; - @Before + @BeforeEach public void setUp() { method = new EthMining(miningCoordinator); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthNewBlockFilterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthNewBlockFilterTest.java index 082873e566c..f2da08de17e 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthNewBlockFilterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthNewBlockFilterTest.java @@ -25,20 +25,20 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EthNewBlockFilterTest { @Mock private FilterManager filterManager; private EthNewBlockFilter method; private final String ETH_METHOD = "eth_newBlockFilter"; - @Before + @BeforeEach public void setUp() { method = new EthNewBlockFilter(filterManager); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthNewFilterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthNewFilterTest.java index 2102add6c72..edaf60d765a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthNewFilterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthNewFilterTest.java @@ -30,10 +30,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.LogsQuery; import org.hyperledger.besu.evm.log.LogTopic; @@ -41,20 +41,20 @@ import java.util.List; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EthNewFilterTest { @Mock private FilterManager filterManager; private EthNewFilter method; private final String ETH_METHOD = "eth_newFilter"; - @Before + @BeforeEach public void setUp() { method = new EthNewFilter(filterManager); } @@ -182,7 +182,7 @@ public void filterWithInvalidParameters() { final JsonRpcRequestContext request = ethNewFilter(invalidFilter); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(null, RpcErrorType.INVALID_PARAMS); final JsonRpcResponse response = method.response(request); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthProtocolVersionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthProtocolVersionTest.java index 1c0a19fe304..4b7f0df83b8 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthProtocolVersionTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthProtocolVersionTest.java @@ -26,7 +26,7 @@ import java.util.HashSet; import java.util.Set; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class EthProtocolVersionTest { private EthProtocolVersion method; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendRawTransactionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendRawTransactionTest.java index 33521b25446..16cbbe3649a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendRawTransactionTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendRawTransactionTest.java @@ -21,22 +21,22 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EthSendRawTransactionTest { private static final String VALID_TRANSACTION = @@ -45,7 +45,7 @@ public class EthSendRawTransactionTest { @Mock private TransactionPool transactionPool; private EthSendRawTransaction method; - @Before + @BeforeEach public void before() { method = new EthSendRawTransaction(transactionPool); } @@ -57,7 +57,7 @@ public void requestIsMissingParameter() { new JsonRpcRequest("2.0", "eth_sendRawTransaction", new String[] {})); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actualResponse = method.response(request); @@ -70,7 +70,7 @@ public void requestHasNullObjectParameter() { new JsonRpcRequestContext(new JsonRpcRequest("2.0", "eth_sendRawTransaction", null)); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actualResponse = method.response(request); @@ -84,7 +84,7 @@ public void requestHasNullArrayParameter() { new JsonRpcRequest("2.0", "eth_sendRawTransaction", new String[] {null})); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actualResponse = method.response(request); @@ -100,7 +100,7 @@ public void invalidTransactionRlpDecoding() { new JsonRpcRequest("2.0", "eth_sendRawTransaction", new String[] {rawTransaction})); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actualResponse = method.response(request); @@ -130,61 +130,61 @@ public void validTransactionIsSentToTransactionPool() { @Test public void transactionWithNonceBelowAccountNonceIsRejected() { verifyErrorForInvalidTransaction( - TransactionInvalidReason.NONCE_TOO_LOW, JsonRpcError.NONCE_TOO_LOW); + TransactionInvalidReason.NONCE_TOO_LOW, RpcErrorType.NONCE_TOO_LOW); } @Test public void transactionWithNonceAboveAccountNonceIsRejected() { verifyErrorForInvalidTransaction( - TransactionInvalidReason.NONCE_TOO_HIGH, JsonRpcError.NONCE_TOO_HIGH); + TransactionInvalidReason.NONCE_TOO_HIGH, RpcErrorType.NONCE_TOO_HIGH); } @Test public void transactionWithInvalidSignatureIsRejected() { verifyErrorForInvalidTransaction( - TransactionInvalidReason.INVALID_SIGNATURE, JsonRpcError.INVALID_TRANSACTION_SIGNATURE); + TransactionInvalidReason.INVALID_SIGNATURE, RpcErrorType.INVALID_TRANSACTION_SIGNATURE); } @Test public void transactionWithIntrinsicGasExceedingGasLimitIsRejected() { verifyErrorForInvalidTransaction( TransactionInvalidReason.INTRINSIC_GAS_EXCEEDS_GAS_LIMIT, - JsonRpcError.INTRINSIC_GAS_EXCEEDS_LIMIT); + RpcErrorType.INTRINSIC_GAS_EXCEEDS_LIMIT); } @Test public void transactionWithUpfrontGasExceedingAccountBalanceIsRejected() { verifyErrorForInvalidTransaction( TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE, - JsonRpcError.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE); + RpcErrorType.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE); } @Test public void transactionWithGasLimitExceedingBlockGasLimitIsRejected() { verifyErrorForInvalidTransaction( - TransactionInvalidReason.EXCEEDS_BLOCK_GAS_LIMIT, JsonRpcError.EXCEEDS_BLOCK_GAS_LIMIT); + TransactionInvalidReason.EXCEEDS_BLOCK_GAS_LIMIT, RpcErrorType.EXCEEDS_BLOCK_GAS_LIMIT); } @Test public void transactionWithNotWhitelistedSenderAccountIsRejected() { verifyErrorForInvalidTransaction( - TransactionInvalidReason.TX_SENDER_NOT_AUTHORIZED, JsonRpcError.TX_SENDER_NOT_AUTHORIZED); + TransactionInvalidReason.TX_SENDER_NOT_AUTHORIZED, RpcErrorType.TX_SENDER_NOT_AUTHORIZED); } @Test public void transactionWithIncorrectTransactionTypeIsRejected() { verifyErrorForInvalidTransaction( - TransactionInvalidReason.INVALID_TRANSACTION_FORMAT, JsonRpcError.INVALID_TRANSACTION_TYPE); + TransactionInvalidReason.INVALID_TRANSACTION_FORMAT, RpcErrorType.INVALID_TRANSACTION_TYPE); } @Test public void transactionWithFeeCapExceededIsRejected() { verifyErrorForInvalidTransaction( - TransactionInvalidReason.TX_FEECAP_EXCEEDED, JsonRpcError.TX_FEECAP_EXCEEDED); + TransactionInvalidReason.TX_FEECAP_EXCEEDED, RpcErrorType.TX_FEECAP_EXCEEDED); } private void verifyErrorForInvalidTransaction( - final TransactionInvalidReason transactionInvalidReason, final JsonRpcError expectedError) { + final TransactionInvalidReason transactionInvalidReason, final RpcErrorType expectedError) { when(transactionPool.addTransactionViaApi(any(Transaction.class))) .thenReturn(ValidationResult.invalid(transactionInvalidReason)); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendTransactionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendTransactionTest.java index 7f0f5fad084..2ddb7405bcd 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendTransactionTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendTransactionTest.java @@ -18,18 +18,18 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class EthSendTransactionTest { private JsonRpcMethod method; - @Before + @BeforeEach public void before() { method = new EthSendTransaction(); } @@ -47,7 +47,7 @@ public void requestIsMissingParameter() { final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.ETH_SEND_TX_NOT_AVAILABLE); + request.getRequest().getId(), RpcErrorType.ETH_SEND_TX_NOT_AVAILABLE); final JsonRpcResponse actualResponse = method.response(request); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSubmitWorkTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSubmitWorkTest.java index b63bcc84919..ab5ac2479cc 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSubmitWorkTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSubmitWorkTest.java @@ -22,10 +22,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator; import org.hyperledger.besu.ethereum.mainnet.PoWSolution; import org.hyperledger.besu.ethereum.mainnet.PoWSolverInputs; @@ -34,13 +34,13 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EthSubmitWorkTest { private EthSubmitWork method; @@ -50,7 +50,7 @@ public class EthSubmitWorkTest { @Mock private PoWMiningCoordinator miningCoordinator; - @Before + @BeforeEach public void setUp() { method = new EthSubmitWork(miningCoordinator); } @@ -65,7 +65,7 @@ public void shouldFailIfNoMiningEnabled() { final JsonRpcRequestContext request = requestWithParams(); final JsonRpcResponse actualResponse = method.response(request); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.NO_MINING_WORK_FOUND); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.NO_MINING_WORK_FOUND); assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); } @@ -119,7 +119,7 @@ public void shouldReturnTrueIfGivenCorrectResult() { public void shouldReturnErrorOnNoneMiningNode() { final JsonRpcRequestContext request = requestWithParams(); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.NO_MINING_WORK_FOUND); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.NO_MINING_WORK_FOUND); when(miningCoordinator.getWorkDefinition()).thenReturn(Optional.empty()); final JsonRpcResponse actualResponse = method.response(request); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSyncingTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSyncingTest.java index 1f3db3ab376..cccf591f4c7 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSyncingTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSyncingTest.java @@ -30,13 +30,13 @@ import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EthSyncingTest { @Mock private Synchronizer synchronizer; @@ -44,7 +44,7 @@ public class EthSyncingTest { private final String JSON_RPC_VERSION = "2.0"; private final String ETH_METHOD = "eth_syncing"; - @Before + @BeforeEach public void setUp() { method = new EthSyncing(synchronizer); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/NetEnodeTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/NetEnodeTest.java index 826f4aac23c..a0c3bb6edf5 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/NetEnodeTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/NetEnodeTest.java @@ -20,10 +20,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork; import org.hyperledger.besu.ethereum.p2p.peers.DefaultPeer; import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl; @@ -33,13 +33,13 @@ import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class NetEnodeTest { private NetEnode method; @@ -61,7 +61,7 @@ public class NetEnodeTest { @Mock private P2PNetwork p2PNetwork; - @Before + @BeforeEach public void before() { this.method = new NetEnode(p2PNetwork); } @@ -91,7 +91,7 @@ public void shouldReturnErrorWhenP2pDisabled() { final JsonRpcRequestContext request = netEnodeRequest(); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.P2P_DISABLED); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.P2P_DISABLED); Assertions.assertThat(method.response(request)) .usingRecursiveComparison() @@ -106,7 +106,7 @@ public void shouldReturnErrorWhenP2PEnabledButNoEnodeFound() { final JsonRpcRequestContext request = netEnodeRequest(); final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.P2P_NETWORK_NOT_RUNNING); + request.getRequest().getId(), RpcErrorType.P2P_NETWORK_NOT_RUNNING); Assertions.assertThat(method.response(request)) .usingRecursiveComparison() diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/NetListeningTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/NetListeningTest.java index 4660ddf2880..195ac78922b 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/NetListeningTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/NetListeningTest.java @@ -26,20 +26,20 @@ import java.util.List; import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class NetListeningTest { private NetListening method; @Mock private P2PNetwork p2PNetwork; - @Before + @BeforeEach public void before() { this.method = new NetListening(p2PNetwork); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/NetVersionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/NetVersionTest.java index d80e4023329..6927cf5733f 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/NetVersionTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/NetVersionTest.java @@ -24,15 +24,15 @@ import java.math.BigInteger; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class NetVersionTest { private NetVersion method; private final BigInteger NETWORK_ID = BigInteger.ONE; - @Before + @BeforeEach public void setUp() { method = new NetVersion(Optional.of(NETWORK_ID)); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/RpcModulesTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/RpcModulesTest.java index b2339685748..4bb75fadb0d 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/RpcModulesTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/RpcModulesTest.java @@ -24,8 +24,8 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class RpcModulesTest { @@ -34,7 +34,7 @@ public class RpcModulesTest { private RpcModules method; - @Before + @BeforeEach public void setUp() { method = new RpcModules(ImmutableList.of(RpcApis.DEBUG.name())); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuPendingTransactionsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuPendingTransactionsTest.java index 09b4752fae3..738cae30970 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuPendingTransactionsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuPendingTransactionsTest.java @@ -26,7 +26,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionPendingResult; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import java.util.HashMap; import java.util.Map; @@ -34,27 +34,30 @@ import java.util.Set; import java.util.stream.Collectors; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; @SuppressWarnings("unchecked") -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class TxPoolBesuPendingTransactionsTest { - @Mock private PendingTransactions pendingTransactions; + @Mock private TransactionPool transactionPool; private TxPoolBesuPendingTransactions method; private final String JSON_RPC_VERSION = "2.0"; private final String TXPOOL_PENDING_TRANSACTIONS_METHOD = "txpool_besuPendingTransactions"; private Set listTrx; - @Before + @BeforeEach public void setUp() { - listTrx = getPendingTransactions(); - method = new TxPoolBesuPendingTransactions(pendingTransactions); - when(this.pendingTransactions.getPendingTransactions()).thenReturn(listTrx); + listTrx = getTransactionPool(); + method = new TxPoolBesuPendingTransactions(transactionPool); + when(transactionPool.getPendingTransactions()).thenReturn(listTrx); } @Test @@ -72,7 +75,7 @@ public void shouldReturnPendingTransactions() { final JsonRpcSuccessResponse actualResponse = (JsonRpcSuccessResponse) method.response(request); final Set result = (Set) actualResponse.getResult(); - assertThat(result.size()).isEqualTo(getPendingTransactions().size()); + assertThat(result.size()).isEqualTo(getTransactionPool().size()); } @Test @@ -253,7 +256,7 @@ public void shouldReturnsErrorIfInvalidPredicateUsedForToField() { .hasMessageContaining("The `to` filter only supports the `eq` or `action` operator"); } - private Set getPendingTransactions() { + private Set getTransactionPool() { final BlockDataGenerator gen = new BlockDataGenerator(); return gen.transactionsWithAllTypes(4).stream() diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuStatisticsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuStatisticsTest.java index b9646e18ff3..b333a0dffca 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuStatisticsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuStatisticsTest.java @@ -23,26 +23,26 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.PendingTransactionsStatisticsResult; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import com.google.common.collect.Sets; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class TxPoolBesuStatisticsTest { - @Mock private PendingTransactions pendingTransactions; + @Mock private TransactionPool transactionPool; private TxPoolBesuStatistics method; private final String JSON_RPC_VERSION = "2.0"; private final String TXPOOL_PENDING_TRANSACTIONS_METHOD = "txpool_besuStatistics"; - @Before + @BeforeEach public void setUp() { - method = new TxPoolBesuStatistics(pendingTransactions); + method = new TxPoolBesuStatistics(transactionPool); } @Test @@ -60,8 +60,8 @@ public void shouldGiveStatistics() { final PendingTransaction local = createTransactionInfo(true); final PendingTransaction secondLocal = createTransactionInfo(true); final PendingTransaction remote = createTransactionInfo(false); - when(pendingTransactions.maxSize()).thenReturn(123L); - when(pendingTransactions.getPendingTransactions()) + when(transactionPool.maxSize()).thenReturn(123L); + when(transactionPool.getPendingTransactions()) .thenReturn(Sets.newHashSet(local, secondLocal, remote)); final JsonRpcSuccessResponse actualResponse = (JsonRpcSuccessResponse) method.response(request); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuTransactionsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuTransactionsTest.java index 8af90115964..e384beb0fd1 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuTransactionsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuTransactionsTest.java @@ -25,30 +25,30 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.PendingTransactionResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.PendingTransactionsResult; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import java.time.Instant; import com.google.common.collect.Sets; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class TxPoolBesuTransactionsTest { - @Mock private PendingTransactions pendingTransactions; + @Mock private TransactionPool transactionPool; private TxPoolBesuTransactions method; private final String JSON_RPC_VERSION = "2.0"; private final String TXPOOL_PENDING_TRANSACTIONS_METHOD = "txpool_besuTransactions"; private static final String TRANSACTION_HASH = "0xbac263fb39f2a51053fb5e1e52aeb4e980fba9e151aa7e4f12eca95a697aeac9"; - @Before + @BeforeEach public void setUp() { - method = new TxPoolBesuTransactions(pendingTransactions); + method = new TxPoolBesuTransactions(transactionPool); } @Test @@ -68,8 +68,7 @@ public void shouldReturnPendingTransactions() { when(pendingTransaction.getHash()).thenReturn(Hash.fromHexString(TRANSACTION_HASH)); when(pendingTransaction.isReceivedFromLocalSource()).thenReturn(true); when(pendingTransaction.getAddedAt()).thenReturn(addedAt); - when(pendingTransactions.getPendingTransactions()) - .thenReturn(Sets.newHashSet(pendingTransaction)); + when(transactionPool.getPendingTransactions()).thenReturn(Sets.newHashSet(pendingTransaction)); final JsonRpcSuccessResponse actualResponse = (JsonRpcSuccessResponse) method.response(request); final PendingTransactionsResult result = (PendingTransactionsResult) actualResponse.getResult(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/Web3ClientVersionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/Web3ClientVersionTest.java index 833ceb1a0c6..e30d274b127 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/Web3ClientVersionTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/Web3ClientVersionTest.java @@ -21,7 +21,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class Web3ClientVersionTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/Web3Sha3Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/Web3Sha3Test.java index 72417114600..83310ead028 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/Web3Sha3Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/Web3Sha3Test.java @@ -18,12 +18,12 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class Web3Sha3Test { @@ -70,7 +70,7 @@ public void shouldReturnErrorOnOddLengthParam() { new JsonRpcRequest("2", "web3_sha3", new Object[] {"0x68656c6c6f20776f726c6"})); final JsonRpcResponse expected = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actual = method.response(request); assertThat(actual).usingRecursiveComparison().isEqualTo(expected); @@ -83,7 +83,7 @@ public void shouldReturnErrorOnNonHexParam() { new JsonRpcRequest("2", "web3_sha3", new Object[] {"0x68656c6c6fThisIsNotHex"})); final JsonRpcResponse expected = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actual = method.response(request); assertThat(actual).usingRecursiveComparison().isEqualTo(expected); @@ -96,7 +96,7 @@ public void shouldReturnErrorOnNoPrefixParam() { new JsonRpcRequest("2", "web3_sha3", new Object[] {"68656c6c6f20776f726c64"})); final JsonRpcResponse expected = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actual = method.response(request); assertThat(actual).usingRecursiveComparison().isEqualTo(expected); @@ -109,7 +109,7 @@ public void shouldReturnErrorOnNoPrefixNonHexParam() { new JsonRpcRequest("2", "web3_sha3", new Object[] {"68656c6c6fThisIsNotHex"})); final JsonRpcResponse expected = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actual = method.response(request); assertThat(actual).usingRecursiveComparison().isEqualTo(expected); @@ -123,7 +123,7 @@ public void shouldReturnErrorOnExtraParam() { "2", "web3_sha3", new Object[] {"0x68656c6c6f20776f726c64", "{encode:'hex'}"})); final JsonRpcResponse expected = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actual = method.response(request); assertThat(actual).usingRecursiveComparison().isEqualTo(expected); @@ -135,7 +135,7 @@ public void shouldReturnErrorOnNoParam() { new JsonRpcRequestContext(new JsonRpcRequest("2", "web3_sha3", new Object[] {})); final JsonRpcResponse expected = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS); final JsonRpcResponse actual = method.response(request); assertThat(actual).usingRecursiveComparison().isEqualTo(expected); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdatedTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdatedTest.java index 5eadc6c8ba0..b45b221a9bd 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdatedTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdatedTest.java @@ -42,11 +42,11 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EngineForkchoiceUpdatedParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePayloadAttributesParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponseType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineUpdateForkchoiceResult; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -63,14 +63,14 @@ import io.vertx.core.Vertx; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public abstract class AbstractEngineForkchoiceUpdatedTest { @FunctionalInterface @@ -111,7 +111,7 @@ public AbstractEngineForkchoiceUpdatedTest(final MethodFactory methodFactory) { @Mock private EngineCallListener engineCallListener; - @Before + @BeforeEach public void before() { when(protocolContext.safeConsensusContext(Mockito.any())).thenReturn(Optional.of(mergeContext)); when(protocolContext.getBlockchain()).thenReturn(blockchain); @@ -731,8 +731,8 @@ protected boolean validateTerminalPoWBlock() { return false; } - protected JsonRpcError expectedInvalidPayloadError() { - return JsonRpcError.INVALID_PARAMS; + protected RpcErrorType expectedInvalidPayloadError() { + return RpcErrorType.INVALID_PARAMS; } private JsonRpcResponse resp( @@ -758,15 +758,15 @@ private EngineUpdateForkchoiceResult fromSuccessResp(final JsonRpcResponse resp) } private void assertInvalidForkchoiceState(final JsonRpcResponse resp) { - assertInvalidForkchoiceState(resp, JsonRpcError.INVALID_FORKCHOICE_STATE); + assertInvalidForkchoiceState(resp, RpcErrorType.INVALID_FORKCHOICE_STATE); } private void assertInvalidForkchoiceState( - final JsonRpcResponse resp, final JsonRpcError jsonRpcError) { + final JsonRpcResponse resp, final RpcErrorType jsonRpcError) { assertThat(resp.getType()).isEqualTo(JsonRpcResponseType.ERROR); var errorResp = (JsonRpcErrorResponse) resp; - assertThat(errorResp.getError()).isEqualTo(jsonRpcError); + assertThat(errorResp.getErrorType()).isEqualTo(jsonRpcError); assertThat(errorResp.getError().getMessage()).isEqualTo(jsonRpcError.getMessage()); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayloadTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayloadTest.java index e31c96871b1..64b00b57360 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayloadTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayloadTest.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -22,6 +23,9 @@ import org.hyperledger.besu.consensus.merge.MergeContext; import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; import org.hyperledger.besu.consensus.merge.blockcreation.PayloadIdentifier; +import org.hyperledger.besu.crypto.KeyPair; +import org.hyperledger.besu.crypto.SignatureAlgorithm; +import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.ProtocolContext; @@ -35,22 +39,30 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.BlockWithReceipts; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import java.util.Collections; import java.util.Optional; +import java.util.function.Supplier; +import com.google.common.base.Suppliers; import io.vertx.core.Vertx; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public abstract class AbstractEngineGetPayloadTest { + private static final Supplier SIGNATURE_ALGORITHM = + Suppliers.memoize(SignatureAlgorithmFactory::getInstance); + protected static final KeyPair senderKeys = SIGNATURE_ALGORITHM.get().generateKeyPair(); + @FunctionalInterface interface MethodFactory { AbstractEngineGetPayload create( @@ -68,7 +80,11 @@ public AbstractEngineGetPayloadTest(final MethodFactory methodFactory) { this.methodFactory = methodFactory; } - private static final Vertx vertx = Vertx.vertx(); + public AbstractEngineGetPayloadTest() { + this.methodFactory = null; + } + + protected static final Vertx vertx = Vertx.vertx(); protected static final BlockResultFactory factory = new BlockResultFactory(); protected static final PayloadIdentifier mockPid = PayloadIdentifier.forPayloadParams( @@ -77,7 +93,7 @@ public AbstractEngineGetPayloadTest(final MethodFactory methodFactory) { new BlockHeaderTestFixture().prevRandao(Bytes32.random()).buildHeader(); private static final Block mockBlock = new Block(mockHeader, new BlockBody(Collections.emptyList(), Collections.emptyList())); - private static final BlockWithReceipts mockBlockWithReceipts = + protected static final BlockWithReceipts mockBlockWithReceipts = new BlockWithReceipts(mockBlock, Collections.emptyList()); private static final Block mockBlockWithWithdrawals = new Block( @@ -101,17 +117,23 @@ public AbstractEngineGetPayloadTest(final MethodFactory methodFactory) { protected static final BlockWithReceipts mockBlockWithReceiptsAndDeposits = new BlockWithReceipts(mockBlockWithDeposits, Collections.emptyList()); - @Mock private ProtocolContext protocolContext; + @Mock protected ProtocolContext protocolContext; @Mock protected MergeContext mergeContext; - @Mock private MergeMiningCoordinator mergeMiningCoordinator; + @Mock protected MergeMiningCoordinator mergeMiningCoordinator; @Mock protected EngineCallListener engineCallListener; - @Before + @Mock protected ProtocolSchedule protocolSchedule; + + protected static final long SHANGHAI_AT = 1337L; + + @BeforeEach public void before() { when(mergeContext.retrieveBlockById(mockPid)).thenReturn(Optional.of(mockBlockWithReceipts)); when(protocolContext.safeConsensusContext(Mockito.any())).thenReturn(Optional.of(mergeContext)); + when(protocolSchedule.hardforkFor(any())) + .thenReturn(Optional.of(new ScheduledProtocolSpec.Hardfork("shanghai", SHANGHAI_AT))); this.method = methodFactory.create( vertx, protocolContext, mergeMiningCoordinator, factory, engineCallListener); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java index e8fb1409e4d..3461782aed4 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java @@ -19,10 +19,9 @@ import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.INVALID; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.SYNCING; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.VALID; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.DepositParameterTestFixture.DEPOSIT_PARAM_1; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameterTestFixture.WITHDRAWAL_PARAM_1; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INVALID_PARAMS; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -32,13 +31,13 @@ import org.hyperledger.besu.consensus.merge.MergeContext; import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; -import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.BlockProcessingOutputs; import org.hyperledger.besu.ethereum.BlockProcessingResult; import org.hyperledger.besu.ethereum.ProtocolContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod; @@ -61,9 +60,11 @@ import org.hyperledger.besu.ethereum.core.Withdrawal; import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.mainnet.BodyValidation; +import org.hyperledger.besu.ethereum.mainnet.DefaultProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.DepositsValidator; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.WithdrawalsValidator; import org.hyperledger.besu.ethereum.trie.MerkleTrieException; import org.hyperledger.besu.plugin.services.exception.StorageException; @@ -72,21 +73,32 @@ import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.function.Predicate; import io.vertx.core.Vertx; import org.apache.tuweni.bytes.Bytes32; -import org.jetbrains.annotations.NotNull; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public abstract class AbstractEngineNewPayloadTest { + protected final ScheduledProtocolSpec.Hardfork londonHardfork = + new ScheduledProtocolSpec.Hardfork("London", 0); + protected final ScheduledProtocolSpec.Hardfork parisHardfork = + new ScheduledProtocolSpec.Hardfork("Paris", 10); + protected final ScheduledProtocolSpec.Hardfork shanghaiHardfork = + new ScheduledProtocolSpec.Hardfork("Shanghai", 20); + protected final ScheduledProtocolSpec.Hardfork cancunHardfork = + new ScheduledProtocolSpec.Hardfork("Cancun", 30); + protected final ScheduledProtocolSpec.Hardfork experimentalHardfork = + new ScheduledProtocolSpec.Hardfork("Experimental", 40); + @FunctionalInterface interface MethodFactory { AbstractEngineNewPayload create( @@ -98,50 +110,64 @@ AbstractEngineNewPayload create( final EngineCallListener engineCallListener); } - private final MethodFactory methodFactory; - protected AbstractEngineNewPayload method; + static class HardforkMatcher implements ArgumentMatcher> { + private final ScheduledProtocolSpec.Hardfork fork; + private final ScheduledProtocolSpec spec; - public AbstractEngineNewPayloadTest(final MethodFactory methodFactory) { - this.methodFactory = methodFactory; + public HardforkMatcher(final ScheduledProtocolSpec.Hardfork hardfork) { + this.fork = hardfork; + this.spec = mock(ScheduledProtocolSpec.class); + when(spec.fork()).thenReturn(fork); + } + + @Override + public boolean matches(final Predicate value) { + if (value == null) { + return false; + } + return value.test(spec); + } } + // private final MethodFactory methodFactory; + protected AbstractEngineNewPayload method; + + public AbstractEngineNewPayloadTest() {} - private static final Vertx vertx = Vertx.vertx(); - private static final Hash mockHash = Hash.hash(Bytes32.fromHexStringLenient("0x1337deadbeef")); - private static final Address depositContractAddress = - Address.fromHexString("0x00000000219ab540356cbb839cbe05303d7705fa"); + protected static final Vertx vertx = Vertx.vertx(); + protected static final Hash mockHash = Hash.hash(Bytes32.fromHexStringLenient("0x1337deadbeef")); - @Mock private ProtocolSpec protocolSpec; - @Mock private ProtocolSchedule protocolSchedule; - @Mock private ProtocolContext protocolContext; + @Mock protected ProtocolSpec protocolSpec; + @Mock protected DefaultProtocolSchedule protocolSchedule; + @Mock protected ProtocolContext protocolContext; - @Mock private MergeContext mergeContext; + @Mock protected MergeContext mergeContext; @Mock protected MergeMiningCoordinator mergeCoordinator; @Mock protected MutableBlockchain blockchain; - @Mock private EthPeers ethPeers; + @Mock protected EthPeers ethPeers; @Mock protected EngineCallListener engineCallListener; - @Before + @BeforeEach public void before() { when(protocolContext.safeConsensusContext(Mockito.any())).thenReturn(Optional.of(mergeContext)); when(protocolContext.getBlockchain()).thenReturn(blockchain); - when(protocolSpec.getWithdrawalsValidator()) + lenient() + .when(protocolSpec.getWithdrawalsValidator()) .thenReturn(new WithdrawalsValidator.ProhibitedWithdrawals()); - when(protocolSpec.getDepositsValidator()) + lenient() + .when(protocolSpec.getDepositsValidator()) .thenReturn(new DepositsValidator.ProhibitedDeposits()); - when(protocolSchedule.getByBlockHeader(any())).thenReturn(protocolSpec); - when(ethPeers.peerCount()).thenReturn(1); - this.method = - methodFactory.create( - vertx, - protocolSchedule, - protocolContext, - mergeCoordinator, - ethPeers, - engineCallListener); + lenient().when(protocolSchedule.getByBlockHeader(any())).thenReturn(protocolSpec); + lenient().when(ethPeers.peerCount()).thenReturn(1); + lenient() + .when(protocolSchedule.hardforkFor(argThat(new HardforkMatcher(cancunHardfork)))) + .thenReturn(Optional.of(cancunHardfork)); + lenient() + .when(protocolSchedule.hardforkFor(argThat(new HardforkMatcher(shanghaiHardfork)))) + .thenReturn(Optional.of(shanghaiHardfork)); } @Test @@ -154,7 +180,9 @@ public void shouldReturnValid() { new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), Optional.empty(), Optional.empty()); - + lenient() + .when(blockchain.getBlockHeader(mockHeader.getParentHash())) + .thenReturn(Optional.of(mock(BlockHeader.class))); var resp = resp(mockPayload(mockHeader, Collections.emptyList())); assertValidResponse(mockHeader, resp); @@ -165,7 +193,9 @@ public void shouldReturnInvalidOnBlockExecutionError() { BlockHeader mockHeader = setupValidPayload( new BlockProcessingResult("error 42"), Optional.empty(), Optional.empty()); - + lenient() + .when(blockchain.getBlockHeader(mockHeader.getParentHash())) + .thenReturn(Optional.of(mock(BlockHeader.class))); var resp = resp(mockPayload(mockHeader, Collections.emptyList())); EnginePayloadStatusResult res = fromSuccessResp(resp); @@ -184,7 +214,8 @@ public void shouldReturnAcceptedOnLatestValidAncestorEmpty() { when(mergeCoordinator.getLatestValidAncestor(any(BlockHeader.class))) .thenReturn(Optional.empty()); if (validateTerminalPoWBlock()) { - when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(any(BlockHeader.class))) + lenient() + .when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(any(BlockHeader.class))) .thenReturn(true); } @@ -199,7 +230,7 @@ public void shouldReturnAcceptedOnLatestValidAncestorEmpty() { @Test public void shouldReturnSuccessOnAlreadyPresent() { - BlockHeader mockHeader = new BlockHeaderTestFixture().baseFeePerGas(Wei.ONE).buildHeader(); + BlockHeader mockHeader = createBlockHeader(Optional.empty(), Optional.empty()); Block mockBlock = new Block(mockHeader, new BlockBody(Collections.emptyList(), Collections.emptyList())); @@ -235,7 +266,9 @@ public void shouldNotReturnInvalidOnStorageException() { new BlockProcessingResult(Optional.empty(), new StorageException("database bedlam")), Optional.empty(), Optional.empty()); - + lenient() + .when(blockchain.getBlockHeader(mockHeader.getParentHash())) + .thenReturn(Optional.of(mock(BlockHeader.class))); var resp = resp(mockPayload(mockHeader, Collections.emptyList())); fromErrorResp(resp); @@ -252,6 +285,9 @@ public void shouldNotReturnInvalidOnHandledMerkleTrieException() { Optional.empty(), Optional.empty()); + lenient() + .when(blockchain.getBlockHeader(mockHeader.getParentHash())) + .thenReturn(Optional.of(mock(BlockHeader.class))); var resp = resp(mockPayload(mockHeader, Collections.emptyList())); verify(engineCallListener, times(1)).executionEngineCalled(); @@ -269,7 +305,8 @@ public void shouldNotReturnInvalidOnThrownMerkleTrieException() { when(mergeCoordinator.getLatestValidAncestor(any(BlockHeader.class))) .thenReturn(Optional.of(mockHash)); if (validateTerminalPoWBlock()) { - when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(any(BlockHeader.class))) + lenient() + .when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(any(BlockHeader.class))) .thenReturn(true); } when(mergeCoordinator.rememberBlock(any())).thenThrow(new MerkleTrieException("missing leaf")); @@ -284,19 +321,27 @@ public void shouldNotReturnInvalidOnThrownMerkleTrieException() { @Test public void shouldReturnInvalidBlockHashOnBadHashParameter() { - BlockHeader mockHeader = new BlockHeaderTestFixture().buildHeader(); - + BlockHeader mockHeader = spy(createBlockHeader(Optional.empty(), Optional.empty())); + lenient() + .when(mergeCoordinator.getLatestValidAncestor(mockHeader.getBlockHash())) + .thenReturn(Optional.empty()); + lenient() + .when(blockchain.getBlockHeader(mockHeader.getParentHash())) + .thenReturn(Optional.of(mock(BlockHeader.class))); + lenient() + .when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(any(BlockHeader.class))) + .thenReturn(true); + lenient().when(mockHeader.getHash()).thenReturn(Hash.fromHexStringLenient("0x1337")); var resp = resp(mockPayload(mockHeader, Collections.emptyList())); EnginePayloadStatusResult res = fromSuccessResp(resp); - assertThat(res.getLatestValidHash()).isEmpty(); assertThat(res.getStatusAsString()).isEqualTo(getExpectedInvalidBlockHashStatus().name()); verify(engineCallListener, times(1)).executionEngineCalled(); } @Test public void shouldCheckBlockValidityBeforeCheckingByHashForExisting() { - BlockHeader realHeader = new BlockHeaderTestFixture().baseFeePerGas(Wei.ONE).buildHeader(); + BlockHeader realHeader = createBlockHeader(Optional.empty(), Optional.empty()); BlockHeader paramHeader = spy(realHeader); when(paramHeader.getHash()).thenReturn(Hash.fromHexStringLenient("0x1337")); @@ -310,7 +355,7 @@ public void shouldCheckBlockValidityBeforeCheckingByHashForExisting() { @Test public void shouldReturnInvalidOnMalformedTransactions() { - BlockHeader mockHeader = new BlockHeaderTestFixture().buildHeader(); + BlockHeader mockHeader = createBlockHeader(Optional.empty(), Optional.empty()); when(mergeCoordinator.getLatestValidAncestor(any(Hash.class))) .thenReturn(Optional.of(mockHash)); @@ -323,31 +368,9 @@ public void shouldReturnInvalidOnMalformedTransactions() { verify(engineCallListener, times(1)).executionEngineCalled(); } - @Test - public void shouldReturnInvalidOnOldTimestampInBlock() { - BlockHeader parent = new BlockHeaderTestFixture().baseFeePerGas(Wei.ONE).buildHeader(); - BlockHeader mockHeader = - new BlockHeaderTestFixture() - .baseFeePerGas(Wei.ONE) - .parentHash(parent.getHash()) - .timestamp(parent.getTimestamp()) - .buildHeader(); - when(blockchain.getBlockByHash(mockHeader.getHash())).thenReturn(Optional.empty()); - when(blockchain.getBlockHeader(parent.getHash())).thenReturn(Optional.of(parent)); - var resp = resp(mockPayload(mockHeader, Collections.emptyList())); - - assertThat(resp.getType()).isEqualTo(JsonRpcResponseType.SUCCESS); - var res = ((JsonRpcSuccessResponse) resp).getResult(); - assertThat(res).isInstanceOf(EnginePayloadStatusResult.class); - var payloadStatusResult = (EnginePayloadStatusResult) res; - assertThat(payloadStatusResult.getStatus()).isEqualTo(INVALID); - assertThat(payloadStatusResult.getError()).isEqualTo("block timestamp not greater than parent"); - verify(engineCallListener, times(1)).executionEngineCalled(); - } - @Test public void shouldRespondWithSyncingDuringForwardSync() { - BlockHeader mockHeader = new BlockHeaderTestFixture().baseFeePerGas(Wei.ONE).buildHeader(); + BlockHeader mockHeader = createBlockHeader(Optional.empty(), Optional.empty()); when(mergeContext.isSyncing()).thenReturn(Boolean.TRUE); var resp = resp(mockPayload(mockHeader, Collections.emptyList())); @@ -360,7 +383,7 @@ public void shouldRespondWithSyncingDuringForwardSync() { @Test public void shouldRespondWithSyncingDuringBackwardsSync() { - BlockHeader mockHeader = new BlockHeaderTestFixture().baseFeePerGas(Wei.ONE).buildHeader(); + BlockHeader mockHeader = createBlockHeader(Optional.empty(), Optional.empty()); when(mergeCoordinator.appendNewPayloadToSync(any())) .thenReturn(CompletableFuture.completedFuture(null)); var resp = resp(mockPayload(mockHeader, Collections.emptyList())); @@ -372,17 +395,9 @@ public void shouldRespondWithSyncingDuringBackwardsSync() { verify(engineCallListener, times(1)).executionEngineCalled(); } - @Test - @Ignore - public void shouldRespondWithInvalidTerminalPowBlock() { - // TODO: implement this as part of https://github.com/hyperledger/besu/issues/3141 - // mergeContext is a mock - // assertThat(mergeContext.getTerminalTotalDifficulty()).isNull(); - } - @Test public void shouldRespondWithInvalidIfExtraDataIsNull() { - BlockHeader realHeader = new BlockHeaderTestFixture().baseFeePerGas(Wei.ONE).buildHeader(); + BlockHeader realHeader = createBlockHeader(Optional.empty(), Optional.empty()); BlockHeader paramHeader = spy(realHeader); when(paramHeader.getHash()).thenReturn(Hash.fromHexStringLenient("0x1337")); when(paramHeader.getExtraData().toHexString()).thenReturn(null); @@ -399,9 +414,10 @@ public void shouldRespondWithInvalidIfExtraDataIsNull() { @Test public void shouldReturnInvalidWhenBadBlock() { when(mergeCoordinator.isBadBlock(any(Hash.class))).thenReturn(true); - BlockHeader mockHeader = new BlockHeaderTestFixture().baseFeePerGas(Wei.ONE).buildHeader(); + BlockHeader mockHeader = createBlockHeader(Optional.empty(), Optional.empty()); var resp = resp(mockPayload(mockHeader, Collections.emptyList())); - + when(protocolSpec.getWithdrawalsValidator()) + .thenReturn(new WithdrawalsValidator.AllowedWithdrawals()); EnginePayloadStatusResult res = fromSuccessResp(resp); assertThat(res.getLatestValidHash()).contains(Hash.ZERO); assertThat(res.getStatusAsString()).isEqualTo(INVALID.name()); @@ -409,146 +425,6 @@ public void shouldReturnInvalidWhenBadBlock() { verify(engineCallListener, times(1)).executionEngineCalled(); } - @Test - public void shouldReturnInvalidIfWithdrawalsIsNotNull_WhenWithdrawalsProhibited() { - final List withdrawals = List.of(); - when(protocolSpec.getWithdrawalsValidator()) - .thenReturn(new WithdrawalsValidator.ProhibitedWithdrawals()); - - var resp = - resp( - mockPayload( - createBlockHeader(Optional.of(Collections.emptyList()), Optional.empty()), - Collections.emptyList(), - withdrawals, - null)); - - final JsonRpcError jsonRpcError = fromErrorResp(resp); - assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode()); - verify(engineCallListener, times(1)).executionEngineCalled(); - } - - @Test - public void shouldReturnValidIfWithdrawalsIsNull_WhenWithdrawalsProhibited() { - final List withdrawals = null; - when(protocolSpec.getWithdrawalsValidator()) - .thenReturn(new WithdrawalsValidator.ProhibitedWithdrawals()); - BlockHeader mockHeader = - setupValidPayload( - new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), - Optional.empty(), - Optional.empty()); - - var resp = resp(mockPayload(mockHeader, Collections.emptyList(), withdrawals, null)); - - assertValidResponse(mockHeader, resp); - } - - @Test - public void shouldReturnInvalidIfWithdrawalsIsNull_WhenWithdrawalsAllowed() { - final List withdrawals = null; - when(protocolSpec.getWithdrawalsValidator()) - .thenReturn(new WithdrawalsValidator.AllowedWithdrawals()); - - var resp = - resp( - mockPayload( - createBlockHeader(Optional.empty(), Optional.empty()), - Collections.emptyList(), - withdrawals, - null)); - - assertThat(fromErrorResp(resp).getCode()).isEqualTo(INVALID_PARAMS.getCode()); - verify(engineCallListener, times(1)).executionEngineCalled(); - } - - @Test - public void shouldReturnValidIfWithdrawalsIsNotNull_WhenWithdrawalsAllowed() { - final List withdrawalsParam = List.of(WITHDRAWAL_PARAM_1); - final List withdrawals = List.of(WITHDRAWAL_PARAM_1.toWithdrawal()); - when(protocolSpec.getWithdrawalsValidator()) - .thenReturn(new WithdrawalsValidator.AllowedWithdrawals()); - BlockHeader mockHeader = - setupValidPayload( - new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), - Optional.of(withdrawals), - Optional.empty()); - - var resp = resp(mockPayload(mockHeader, Collections.emptyList(), withdrawalsParam, null)); - - assertValidResponse(mockHeader, resp); - } - - @Test - public void shouldReturnInvalidIfDepositsIsNotNull_WhenDepositsProhibited() { - final List deposits = List.of(); - when(protocolSpec.getDepositsValidator()) - .thenReturn(new DepositsValidator.ProhibitedDeposits()); - - var resp = - resp( - mockPayload( - createBlockHeader(Optional.empty(), Optional.of(Collections.emptyList())), - Collections.emptyList(), - null, - deposits)); - - final JsonRpcError jsonRpcError = fromErrorResp(resp); - assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode()); - verify(engineCallListener, times(1)).executionEngineCalled(); - } - - @Test - public void shouldReturnValidIfDepositsIsNull_WhenDepositsProhibited() { - final List deposits = null; - when(protocolSpec.getDepositsValidator()) - .thenReturn(new DepositsValidator.ProhibitedDeposits()); - BlockHeader mockHeader = - setupValidPayload( - new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), - Optional.empty(), - Optional.empty()); - - var resp = resp(mockPayload(mockHeader, Collections.emptyList(), null, deposits)); - - assertValidResponse(mockHeader, resp); - } - - @Test - public void shouldReturnInvalidIfDepositsIsNull_WhenDepositsAllowed() { - final List deposits = null; - when(protocolSpec.getDepositsValidator()) - .thenReturn(new DepositsValidator.AllowedDeposits(depositContractAddress)); - - var resp = - resp( - mockPayload( - createBlockHeader(Optional.empty(), Optional.empty()), - Collections.emptyList(), - null, - deposits)); - - assertThat(fromErrorResp(resp).getCode()).isEqualTo(INVALID_PARAMS.getCode()); - verify(engineCallListener, times(1)).executionEngineCalled(); - } - - @Test - public void shouldReturnValidIfDepositsIsNotNull_WhenDepositsAllowed() { - final List depositsParam = List.of(DEPOSIT_PARAM_1); - final List deposits = List.of(DEPOSIT_PARAM_1.toDeposit()); - when(protocolSpec.getDepositsValidator()) - .thenReturn(new DepositsValidator.AllowedDeposits(depositContractAddress)); - BlockHeader mockHeader = - setupValidPayload( - new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), - Optional.empty(), - Optional.of(deposits)); - - var resp = resp(mockPayload(mockHeader, Collections.emptyList(), null, depositsParam)); - - assertValidResponse(mockHeader, resp); - } - @Test public void shouldReturnValidIfProtocolScheduleIsEmpty() { when(protocolSchedule.getByBlockHeader(any())).thenReturn(null); @@ -557,7 +433,9 @@ public void shouldReturnValidIfProtocolScheduleIsEmpty() { new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), Optional.empty(), Optional.empty()); - + lenient() + .when(blockchain.getBlockHeader(mockHeader.getParentHash())) + .thenReturn(Optional.of(mock(BlockHeader.class))); var resp = resp(mockPayload(mockHeader, Collections.emptyList())); assertValidResponse(mockHeader, resp); @@ -566,35 +444,32 @@ public void shouldReturnValidIfProtocolScheduleIsEmpty() { protected JsonRpcResponse resp(final EnginePayloadParameter payload) { return method.response( new JsonRpcRequestContext( - new JsonRpcRequest( - "2.0", RpcMethod.ENGINE_NEW_PAYLOAD_V2.getMethodName(), new Object[] {payload}))); + new JsonRpcRequest("2.0", this.method.getName(), new Object[] {payload}))); } protected EnginePayloadParameter mockPayload(final BlockHeader header, final List txs) { - return new EnginePayloadParameter( - header.getHash(), - header.getParentHash(), - header.getCoinbase(), - header.getStateRoot(), - new UnsignedLongParameter(header.getNumber()), - header.getBaseFee().map(w -> w.toHexString()).orElse("0x0"), - new UnsignedLongParameter(header.getGasLimit()), - new UnsignedLongParameter(header.getGasUsed()), - new UnsignedLongParameter(header.getTimestamp()), - header.getExtraData() == null ? null : header.getExtraData().toHexString(), - header.getReceiptsRoot(), - header.getLogsBloom(), - header.getPrevRandao().map(Bytes32::toHexString).orElse("0x0"), - txs, - null, - null); + return mockPayload(header, txs, null, null, null); } - private EnginePayloadParameter mockPayload( + protected EnginePayloadParameter mockPayload( final BlockHeader header, final List txs, final List withdrawals, final List deposits) { + return mockPayload( + header, + txs, + withdrawals, + deposits, + List.of(VersionedHash.DEFAULT_VERSIONED_HASH.toBytes())); + } + + protected EnginePayloadParameter mockPayload( + final BlockHeader header, + final List txs, + final List withdrawals, + final List deposits, + final List versionedHashes) { return new EnginePayloadParameter( header.getHash(), header.getParentHash(), @@ -611,22 +486,26 @@ private EnginePayloadParameter mockPayload( header.getPrevRandao().map(Bytes32::toHexString).orElse("0x0"), txs, withdrawals, + header.getBlobGasUsed().map(UnsignedLongParameter::new).orElse(null), + header.getExcessBlobGas().map(BlobGas::toHexString).orElse(null), + versionedHashes, deposits); } - @NotNull - private BlockHeader setupValidPayload( + protected BlockHeader setupValidPayload( final BlockProcessingResult value, final Optional> maybeWithdrawals, final Optional> maybeDeposits) { + BlockHeader mockHeader = createBlockHeader(maybeWithdrawals, maybeDeposits); when(blockchain.getBlockByHash(mockHeader.getHash())).thenReturn(Optional.empty()); - when(blockchain.getBlockHeader(mockHeader.getParentHash())) - .thenReturn(Optional.of(mock(BlockHeader.class))); + // when(blockchain.getBlockHeader(mockHeader.getParentHash())) + // .thenReturn(Optional.of(mock(BlockHeader.class))); when(mergeCoordinator.getLatestValidAncestor(any(BlockHeader.class))) .thenReturn(Optional.of(mockHash)); if (validateTerminalPoWBlock()) { - when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(any(BlockHeader.class))) + lenient() + .when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(any(BlockHeader.class))) .thenReturn(true); } when(mergeCoordinator.rememberBlock(any())).thenReturn(value); @@ -650,7 +529,7 @@ protected EnginePayloadStatusResult fromSuccessResp(final JsonRpcResponse resp) .get(); } - private JsonRpcError fromErrorResp(final JsonRpcResponse resp) { + protected JsonRpcError fromErrorResp(final JsonRpcResponse resp) { assertThat(resp.getType()).isEqualTo(JsonRpcResponseType.ERROR); return Optional.of(resp) .map(JsonRpcErrorResponse.class::cast) @@ -675,7 +554,7 @@ protected BlockHeader createBlockHeader( return mockHeader; } - private void assertValidResponse(final BlockHeader mockHeader, final JsonRpcResponse resp) { + protected void assertValidResponse(final BlockHeader mockHeader, final JsonRpcResponse resp) { EnginePayloadStatusResult res = fromSuccessResp(resp); assertThat(res.getLatestValidHash().get()).isEqualTo(mockHeader.getHash()); assertThat(res.getStatusAsString()).isEqualTo(VALID.name()); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeCapabilitiesTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeCapabilitiesTest.java index 2a30a2e5dcb..41a024c09c6 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeCapabilitiesTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeCapabilitiesTest.java @@ -31,13 +31,13 @@ import java.util.Optional; import io.vertx.core.Vertx; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EngineExchangeCapabilitiesTest { private EngineExchangeCapabilities method; private static final Vertx vertx = Vertx.vertx(); @@ -46,7 +46,7 @@ public class EngineExchangeCapabilitiesTest { @Mock private EngineCallListener engineCallListener; - @Before + @BeforeEach public void setUp() { this.method = new EngineExchangeCapabilities(vertx, protocolContext, engineCallListener); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java index 0180d0269c7..bc78e4d0564 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java @@ -50,14 +50,14 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EngineExchangeTransitionConfigurationTest { private EngineExchangeTransitionConfiguration method; private static final Vertx vertx = Vertx.vertx(); @@ -68,7 +68,7 @@ public class EngineExchangeTransitionConfigurationTest { @Mock private EngineCallListener engineCallListener; - @Before + @BeforeEach public void setUp() { when(protocolContext.safeConsensusContext(Mockito.any())).thenReturn(Optional.of(mergeContext)); @@ -252,6 +252,7 @@ private BlockHeader createBlockHeader(final Hash blockHash, final long blockNumb null, null, null, + null, new BlockHeaderFunctions() { @Override public Hash hash(final BlockHeader header) { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV1Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV1Test.java index 0433b55bae1..37e84ea1582 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV1Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV1Test.java @@ -23,16 +23,19 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EngineForkchoiceUpdatedParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.core.BlockHeader; import java.util.Optional; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class EngineForkchoiceUpdatedV1Test extends AbstractEngineForkchoiceUpdatedTest { public EngineForkchoiceUpdatedV1Test() { @@ -71,7 +74,7 @@ protected boolean validateTerminalPoWBlock() { } @Override - protected JsonRpcError expectedInvalidPayloadError() { - return JsonRpcError.INVALID_PAYLOAD_ATTRIBUTES; + protected RpcErrorType expectedInvalidPayloadError() { + return RpcErrorType.INVALID_PAYLOAD_ATTRIBUTES; } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV2Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV2Test.java index 695325762fe..77249934113 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV2Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV2Test.java @@ -18,11 +18,14 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class EngineForkchoiceUpdatedV2Test extends AbstractEngineForkchoiceUpdatedTest { public EngineForkchoiceUpdatedV2Test() { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1Test.java index 8f202199681..9c3cd8f45ff 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1Test.java @@ -15,7 +15,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; import static org.assertj.core.api.Assertions.assertThat; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INVALID_RANGE_REQUEST_TOO_LARGE; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INVALID_RANGE_REQUEST_TOO_LARGE; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -29,11 +29,11 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponseType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetPayloadBodiesResultV1; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; @@ -48,13 +48,16 @@ import io.vertx.core.Vertx; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt64; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class EngineGetPayloadBodiesByHashV1Test { private EngineGetPayloadBodiesByHashV1 method; private static final Vertx vertx = Vertx.vertx(); @@ -63,7 +66,7 @@ public class EngineGetPayloadBodiesByHashV1Test { @Mock private EngineCallListener engineCallListener; @Mock private MutableBlockchain blockchain; - @Before + @BeforeEach public void before() { when(protocolContext.getBlockchain()).thenReturn(blockchain); this.method = @@ -260,11 +263,11 @@ private EngineGetPayloadBodiesResultV1 fromSuccessResp(final JsonRpcResponse res .get(); } - private JsonRpcError fromErrorResp(final JsonRpcResponse resp) { + private RpcErrorType fromErrorResp(final JsonRpcResponse resp) { assertThat(resp.getType()).isEqualTo(JsonRpcResponseType.ERROR); return Optional.of(resp) .map(JsonRpcErrorResponse.class::cast) - .map(JsonRpcErrorResponse::getError) + .map(JsonRpcErrorResponse::getErrorType) .get(); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByRangeV1Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByRangeV1Test.java index 66821f9f49a..16964458648 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByRangeV1Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByRangeV1Test.java @@ -15,8 +15,8 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; import static org.assertj.core.api.Assertions.assertThat; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INVALID_PARAMS; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INVALID_RANGE_REQUEST_TOO_LARGE; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INVALID_PARAMS; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INVALID_RANGE_REQUEST_TOO_LARGE; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -49,13 +49,16 @@ import io.vertx.core.Vertx; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt64; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class EngineGetPayloadBodiesByRangeV1Test { private EngineGetPayloadBodiesByRangeV1 method; private static final Vertx vertx = Vertx.vertx(); @@ -64,7 +67,7 @@ public class EngineGetPayloadBodiesByRangeV1Test { @Mock private EngineCallListener engineCallListener; @Mock private MutableBlockchain blockchain; - @Before + @BeforeEach public void before() { when(protocolContext.getBlockchain()).thenReturn(blockchain); this.method = diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV1Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV1Test.java index 43a0ae44968..5fbf89413f2 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV1Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV1Test.java @@ -25,11 +25,14 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class EngineGetPayloadV1Test extends AbstractEngineGetPayloadTest { public EngineGetPayloadV1Test() { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV2Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV2Test.java index 2250f63e718..0ba7380496e 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV2Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV2Test.java @@ -27,11 +27,14 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class EngineGetPayloadV2Test extends AbstractEngineGetPayloadTest { public EngineGetPayloadV2Test() { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3Test.java new file mode 100644 index 00000000000..d024ac9fe15 --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3Test.java @@ -0,0 +1,169 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.consensus.merge.blockcreation.PayloadIdentifier; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.BlobGas; +import org.hyperledger.besu.datatypes.BlobsWithCommitments; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetPayloadResultV3; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; +import org.hyperledger.besu.ethereum.core.BlobTestFixture; +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockBody; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; +import org.hyperledger.besu.ethereum.core.BlockWithReceipts; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.core.TransactionReceipt; +import org.hyperledger.besu.ethereum.core.TransactionTestFixture; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; + +import java.math.BigInteger; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith( + MockitoExtension.class) // mocks in parent class may not be used, throwing unnecessary stubbing +public class EngineGetPayloadV3Test extends AbstractEngineGetPayloadTest { + + private static final long CANCUN_AT = 31337L; + + public EngineGetPayloadV3Test() { + super(); + } + + @BeforeEach + @Override + public void before() { + lenient() + .when(mergeContext.retrieveBlockById(mockPid)) + .thenReturn(Optional.of(mockBlockWithReceipts)); + when(protocolContext.safeConsensusContext(Mockito.any())).thenReturn(Optional.of(mergeContext)); + when(protocolSchedule.hardforkFor(any())) + .thenReturn(Optional.of(new ScheduledProtocolSpec.Hardfork("shanghai", SHANGHAI_AT))); + this.method = + new EngineGetPayloadV3( + vertx, + protocolContext, + mergeMiningCoordinator, + factory, + engineCallListener, + protocolSchedule); + } + + @Override + @Test + public void shouldReturnExpectedMethodName() { + assertThat(method.getName()).isEqualTo("engine_getPayloadV3"); + } + + @Override + @Test + public void shouldReturnBlockForKnownPayloadId() { + + BlockHeader cancunHeader = + new BlockHeaderTestFixture() + .prevRandao(Bytes32.random()) + .timestamp(CANCUN_AT + 1) + .excessBlobGas(BlobGas.of(10L)) + .buildHeader(); + // should return withdrawals and excessGas for a post-cancun block + PayloadIdentifier postCancunPid = + PayloadIdentifier.forPayloadParams( + Hash.ZERO, + CANCUN_AT, + Bytes32.random(), + Address.fromHexString("0x42"), + Optional.empty()); + + BlobTestFixture blobTestFixture = new BlobTestFixture(); + BlobsWithCommitments bwc = blobTestFixture.createBlobsWithCommitments(1); + Transaction blobTx = + new TransactionTestFixture() + .to(Optional.of(Address.fromHexString("0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"))) + .type(TransactionType.BLOB) + .chainId(Optional.of(BigInteger.ONE)) + .maxFeePerGas(Optional.of(Wei.of(15))) + .maxFeePerBlobGas(Optional.of(Wei.of(128))) + .maxPriorityFeePerGas(Optional.of(Wei.of(1))) + .blobsWithCommitments(Optional.of(bwc)) + .versionedHashes(Optional.of(bwc.getVersionedHashes())) + .createTransaction(senderKeys); + TransactionReceipt blobReceipt = mock(TransactionReceipt.class); + when(blobReceipt.getCumulativeGasUsed()).thenReturn(100L); + BlockWithReceipts postCancunBlock = + new BlockWithReceipts( + new Block( + cancunHeader, + new BlockBody( + List.of(blobTx), + Collections.emptyList(), + Optional.of(Collections.emptyList()), + Optional.empty())), + List.of(blobReceipt)); + + when(mergeContext.retrieveBlockById(postCancunPid)).thenReturn(Optional.of(postCancunBlock)); + + final var resp = resp(RpcMethod.ENGINE_GET_PAYLOAD_V3.getMethodName(), postCancunPid); + assertThat(resp).isInstanceOf(JsonRpcSuccessResponse.class); + Optional.of(resp) + .map(JsonRpcSuccessResponse.class::cast) + .ifPresent( + r -> { + assertThat(r.getResult()).isInstanceOf(EngineGetPayloadResultV3.class); + final EngineGetPayloadResultV3 res = (EngineGetPayloadResultV3) r.getResult(); + assertThat(res.getExecutionPayload().getWithdrawals()).isNotNull(); + assertThat(res.getExecutionPayload().getHash()) + .isEqualTo(cancunHeader.getHash().toString()); + assertThat(res.getBlockValue()).isEqualTo(Quantity.create(0)); + assertThat(res.getExecutionPayload().getPrevRandao()) + .isEqualTo(cancunHeader.getPrevRandao().map(Bytes32::toString).orElse("")); + // excessBlobGas: QUANTITY, 256 bits + String expectedQuantityOf10 = Bytes32.leftPad(Bytes.of(10)).toQuantityHexString(); + assertThat(res.getExecutionPayload().getExcessBlobGas()).isNotEmpty(); + assertThat(res.getExecutionPayload().getExcessBlobGas()) + .isEqualTo(expectedQuantityOf10); + }); + verify(engineCallListener, times(1)).executionEngineCalled(); + } + + @Override + protected String getMethodName() { + return RpcMethod.ENGINE_GET_PAYLOAD_V3.getMethodName(); + } +} diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadEIP6110Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadEIP6110Test.java new file mode 100644 index 00000000000..a00b868ff30 --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadEIP6110Test.java @@ -0,0 +1,189 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.DepositParameterTestFixture.DEPOSIT_PARAM_1; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INVALID_PARAMS; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.BlobGas; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.BlockProcessingOutputs; +import org.hyperledger.besu.ethereum.BlockProcessingResult; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.DepositParameter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; +import org.hyperledger.besu.ethereum.core.Deposit; +import org.hyperledger.besu.ethereum.core.Withdrawal; +import org.hyperledger.besu.ethereum.mainnet.BodyValidation; +import org.hyperledger.besu.ethereum.mainnet.DepositsValidator; +import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class EngineNewPayloadEIP6110Test extends EngineNewPayloadV3Test { + private static final Address depositContractAddress = + Address.fromHexString("0x00000000219ab540356cbb839cbe05303d7705fa"); + + public EngineNewPayloadEIP6110Test() {} + + @BeforeEach + @Override + public void before() { + super.before(); + this.method = + new EngineNewPayloadV3( + vertx, + protocolSchedule, + protocolContext, + mergeCoordinator, + ethPeers, + engineCallListener); + lenient() + .when(protocolSchedule.hardforkFor(any())) + .thenReturn(Optional.of(super.cancunHardfork)); + lenient().when(protocolSpec.getGasCalculator()).thenReturn(new CancunGasCalculator()); + } + + @Override + public void shouldReturnExpectedMethodName() { + assertThat(method.getName()).isEqualTo("engine_newPayloadV3"); + } + + @Test + public void shouldReturnValidIfDepositsIsNull_WhenDepositsProhibited() { + final List deposits = null; + when(protocolSpec.getDepositsValidator()) + .thenReturn(new DepositsValidator.ProhibitedDeposits()); + + BlockHeader mockHeader = + setupValidPayload( + new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), + Optional.empty(), + Optional.empty()); + when(blockchain.getBlockHeader(mockHeader.getParentHash())) + .thenReturn(Optional.of(mock(BlockHeader.class))); + when(mergeCoordinator.getLatestValidAncestor(mockHeader)) + .thenReturn(Optional.of(mockHeader.getHash())); + when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(mockHeader)).thenReturn(true); + + var resp = resp(mockPayload(mockHeader, Collections.emptyList(), null, deposits, null)); + + assertValidResponse(mockHeader, resp); + } + + @Test + public void shouldReturnInvalidIfDepositsIsNull_WhenDepositsAllowed() { + final List deposits = null; + lenient() + .when(protocolSpec.getDepositsValidator()) + .thenReturn(new DepositsValidator.AllowedDeposits(depositContractAddress)); + + var resp = + resp( + mockPayload( + createBlockHeader(Optional.empty(), Optional.empty()), + Collections.emptyList(), + null, + deposits)); + + assertThat(fromErrorResp(resp).getCode()).isEqualTo(INVALID_PARAMS.getCode()); + verify(engineCallListener, times(1)).executionEngineCalled(); + } + + @Test + public void shouldReturnValidIfDepositsIsNotNull_WhenDepositsAllowed() { + final List depositsParam = List.of(DEPOSIT_PARAM_1); + final List deposits = List.of(DEPOSIT_PARAM_1.toDeposit()); + when(protocolSpec.getDepositsValidator()) + .thenReturn(new DepositsValidator.AllowedDeposits(depositContractAddress)); + BlockHeader mockHeader = + setupValidPayload( + new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), + Optional.empty(), + Optional.of(deposits)); + when(blockchain.getBlockHeader(mockHeader.getParentHash())) + .thenReturn(Optional.of(mock(BlockHeader.class))); + when(mergeCoordinator.getLatestValidAncestor(mockHeader)) + .thenReturn(Optional.of(mockHeader.getHash())); + when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(mockHeader)).thenReturn(true); + var resp = resp(mockPayload(mockHeader, Collections.emptyList(), null, depositsParam)); + + assertValidResponse(mockHeader, resp); + } + + @Test + public void shouldReturnInvalidIfDepositsIsNotNull_WhenDepositsProhibited() { + final List deposits = List.of(); + lenient() + .when(protocolSpec.getDepositsValidator()) + .thenReturn(new DepositsValidator.ProhibitedDeposits()); + + var resp = + resp( + mockPayload( + createBlockHeader(Optional.empty(), Optional.of(Collections.emptyList())), + Collections.emptyList(), + null, + deposits)); + + final JsonRpcError jsonRpcError = fromErrorResp(resp); + assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode()); + verify(engineCallListener, times(1)).executionEngineCalled(); + } + + @Override + protected BlockHeader createBlockHeader( + final Optional> maybeWithdrawals, + final Optional> maybeDeposits) { + BlockHeader parentBlockHeader = + new BlockHeaderTestFixture() + .baseFeePerGas(Wei.ONE) + .timestamp(super.experimentalHardfork.milestone()) + .excessBlobGas(BlobGas.ZERO) + .blobGasUsed(100L) + .buildHeader(); + + BlockHeader mockHeader = + new BlockHeaderTestFixture() + .baseFeePerGas(Wei.ONE) + .parentHash(parentBlockHeader.getParentHash()) + .number(parentBlockHeader.getNumber() + 1) + .timestamp(parentBlockHeader.getTimestamp() + 1) + .withdrawalsRoot(maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null)) + .excessBlobGas(BlobGas.ZERO) + .blobGasUsed(100L) + .depositsRoot(maybeDeposits.map(BodyValidation::depositsRoot).orElse(null)) + .buildHeader(); + return mockHeader; + } +} diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV1Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV1Test.java index f9a9200d57e..65c6d271f1a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV1Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV1Test.java @@ -32,15 +32,31 @@ import java.util.Collections; import java.util.Optional; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class EngineNewPayloadV1Test extends AbstractEngineNewPayloadTest { - public EngineNewPayloadV1Test() { - super(EngineNewPayloadV1::new); + public EngineNewPayloadV1Test() {} + + @Override + @BeforeEach + public void before() { + super.before(); + this.method = + new EngineNewPayloadV1( + vertx, + protocolSchedule, + protocolContext, + mergeCoordinator, + ethPeers, + engineCallListener); } @Override diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java index 5de4ede7340..cc51d7349b6 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java @@ -15,16 +15,53 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.INVALID; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameterTestFixture.WITHDRAWAL_PARAM_1; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INVALID_PARAMS; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.hyperledger.besu.ethereum.BlockProcessingOutputs; +import org.hyperledger.besu.ethereum.BlockProcessingResult; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.Withdrawal; +import org.hyperledger.besu.ethereum.mainnet.WithdrawalsValidator; -@RunWith(MockitoJUnitRunner.class) +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest { - public EngineNewPayloadV2Test() { - super(EngineNewPayloadV2::new); + public EngineNewPayloadV2Test() {} + + @Override + @BeforeEach + public void before() { + super.before(); + this.method = + new EngineNewPayloadV2( + vertx, + protocolSchedule, + protocolContext, + mergeCoordinator, + ethPeers, + engineCallListener); } @Override @@ -32,4 +69,90 @@ public EngineNewPayloadV2Test() { public void shouldReturnExpectedMethodName() { assertThat(method.getName()).isEqualTo("engine_newPayloadV2"); } + + @Test + public void shouldReturnValidIfWithdrawalsIsNotNull_WhenWithdrawalsAllowed() { + final List withdrawalsParam = List.of(WITHDRAWAL_PARAM_1); + final List withdrawals = List.of(WITHDRAWAL_PARAM_1.toWithdrawal()); + when(protocolSpec.getWithdrawalsValidator()) + .thenReturn(new WithdrawalsValidator.AllowedWithdrawals()); + BlockHeader mockHeader = + setupValidPayload( + new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), + Optional.of(withdrawals), + Optional.empty()); + lenient() + .when(blockchain.getBlockHeader(mockHeader.getParentHash())) + .thenReturn(Optional.of(mock(BlockHeader.class))); + var resp = resp(mockPayload(mockHeader, Collections.emptyList(), withdrawalsParam, null)); + + assertValidResponse(mockHeader, resp); + } + + @Test + public void shouldReturnValidIfWithdrawalsIsNull_WhenWithdrawalsProhibited() { + final List withdrawals = null; + when(protocolSpec.getWithdrawalsValidator()) + .thenReturn(new WithdrawalsValidator.ProhibitedWithdrawals()); + BlockHeader mockHeader = + setupValidPayload( + new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), + Optional.empty(), + Optional.empty()); + lenient() + .when(blockchain.getBlockHeader(mockHeader.getParentHash())) + .thenReturn(Optional.of(mock(BlockHeader.class))); + var resp = resp(mockPayload(mockHeader, Collections.emptyList(), withdrawals, null, null)); + + assertValidResponse(mockHeader, resp); + } + + @Test + public void shouldReturnInvalidIfWithdrawalsIsNotNull_WhenWithdrawalsProhibited() { + final List withdrawals = List.of(); + lenient() + .when(protocolSpec.getWithdrawalsValidator()) + .thenReturn(new WithdrawalsValidator.ProhibitedWithdrawals()); + + var resp = + resp( + mockPayload( + createBlockHeader(Optional.of(Collections.emptyList()), Optional.empty()), + Collections.emptyList(), + withdrawals, + null, + null)); + + final JsonRpcError jsonRpcError = fromErrorResp(resp); + assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode()); + verify(engineCallListener, times(1)).executionEngineCalled(); + } + + @Test + public void shouldReturnInvalidIfWithdrawalsIsNull_WhenWithdrawalsAllowed() { + final List withdrawals = null; + when(protocolSpec.getWithdrawalsValidator()) + .thenReturn(new WithdrawalsValidator.AllowedWithdrawals()); + + var resp = + resp( + mockPayload( + createBlockHeader(Optional.empty(), Optional.empty()), + Collections.emptyList(), + withdrawals, + null)); + + assertThat(fromErrorResp(resp).getCode()).isEqualTo(INVALID_PARAMS.getCode()); + verify(engineCallListener, times(1)).executionEngineCalled(); + } + + @Override + protected boolean validateTerminalPoWBlock() { + return false; + } + + @Override + protected ExecutionEngineJsonRpcMethod.EngineStatus getExpectedInvalidBlockHashStatus() { + return INVALID; + } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java new file mode 100644 index 00000000000..2cb130b2bbd --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java @@ -0,0 +1,126 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.INVALID; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.datatypes.BlobGas; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePayloadParameter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EnginePayloadStatusResult; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; +import org.hyperledger.besu.ethereum.core.Deposit; +import org.hyperledger.besu.ethereum.core.Withdrawal; +import org.hyperledger.besu.ethereum.mainnet.BodyValidation; +import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; + +import java.util.List; +import java.util.Optional; + +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test { + + public EngineNewPayloadV3Test() {} + + @Override + @Test + public void shouldReturnExpectedMethodName() { + assertThat(method.getName()).isEqualTo("engine_newPayloadV3"); + } + + @BeforeEach + @Override + public void before() { + super.before(); + this.method = + new EngineNewPayloadV3( + vertx, + protocolSchedule, + protocolContext, + mergeCoordinator, + ethPeers, + engineCallListener); + lenient().when(protocolSpec.getGasCalculator()).thenReturn(new CancunGasCalculator()); + } + + @Test + public void shouldInvalidPayloadOnShortVersionedHash() { + Bytes shortHash = Bytes.fromHexString("0x" + "69".repeat(31)); + + EnginePayloadParameter payload = mock(EnginePayloadParameter.class); + when(payload.getTimestamp()).thenReturn(30l); + when(payload.getExcessBlobGas()).thenReturn("99"); + when(payload.getBlobGasUsed()).thenReturn(9l); + + JsonRpcResponse badParam = + method.response( + new JsonRpcRequestContext( + new JsonRpcRequest( + "2.0", + RpcMethod.ENGINE_NEW_PAYLOAD_V3.getMethodName(), + new Object[] {payload, List.of(shortHash.toHexString())}))); + EnginePayloadStatusResult res = fromSuccessResp(badParam); + assertThat(res.getStatusAsString()).isEqualTo(INVALID.name()); + assertThat(res.getError()).isEqualTo("Invalid versionedHash"); + } + + @Override + protected BlockHeader createBlockHeader( + final Optional> maybeWithdrawals, + final Optional> maybeDeposits) { + BlockHeader parentBlockHeader = + new BlockHeaderTestFixture() + .baseFeePerGas(Wei.ONE) + .timestamp(super.cancunHardfork.milestone()) + .buildHeader(); + // protocolContext.getBlockchain().getBlockHeader(blockParam.getParentHash()); + when(blockchain.getBlockHeader(parentBlockHeader.getBlockHash())) + .thenReturn(Optional.of(parentBlockHeader)); + when(protocolContext.getBlockchain()).thenReturn(blockchain); + BlockHeader mockHeader = + new BlockHeaderTestFixture() + .baseFeePerGas(Wei.ONE) + .parentHash(parentBlockHeader.getParentHash()) + .number(parentBlockHeader.getNumber() + 1) + .timestamp(parentBlockHeader.getTimestamp() + 12) + .withdrawalsRoot(maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null)) + .depositsRoot(maybeDeposits.map(BodyValidation::depositsRoot).orElse(null)) + .excessBlobGas(BlobGas.ZERO) + .blobGasUsed(0L) + .buildHeader(); + return mockHeader; + } + + @Override + @Test + public void shouldReturnValidIfProtocolScheduleIsEmpty() { + // no longer the case, blob validation requires a protocol schedule + } +} diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebugTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebugTest.java index c89df2fff80..0611813696c 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebugTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebugTest.java @@ -34,14 +34,14 @@ import java.util.Optional; import io.vertx.core.Vertx; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Answers; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EnginePreparePayloadDebugTest { private static final Vertx vertx = Vertx.vertx(); EnginePreparePayloadDebug method; @@ -55,7 +55,7 @@ public class EnginePreparePayloadDebugTest { @Mock private EnginePreparePayloadParameter param; - @Before + @BeforeEach public void setUp() { when(protocolContext.safeConsensusContext(MergeContext.class)) .thenReturn(Optional.of(mergeContext)); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineQosTimerTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineQosTimerTest.java index 6eedc70819e..b25fd7e3d0b 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineQosTimerTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineQosTimerTest.java @@ -24,34 +24,34 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.QosTimer; import io.vertx.core.Vertx; -import io.vertx.ext.unit.Async; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import io.vertx.junit5.VertxExtension; +import io.vertx.junit5.VertxTestContext; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; -@RunWith(VertxUnitRunner.class) +@ExtendWith(VertxExtension.class) public class EngineQosTimerTest { private EngineQosTimer engineQosTimer; private Vertx vertx; + private VertxTestContext testContext; - @Before + @BeforeEach public void setUp() throws Exception { vertx = Vertx.vertx(); + testContext = new VertxTestContext(); engineQosTimer = new EngineQosTimer(vertx); } - @After + @AfterEach public void cleanUp() { vertx.close(); } @Test - public void shouldNotWarnWhenCalledWithinTimeout(final TestContext ctx) { + public void shouldNotWarnWhenCalledWithinTimeout() { final long TEST_QOS_TIMEOUT = 75L; - final Async async = ctx.async(); final var spyEngineQosTimer = spy(engineQosTimer); final var spyTimer = spy(new QosTimer(vertx, TEST_QOS_TIMEOUT, z -> spyEngineQosTimer.logTimeoutWarning())); @@ -68,17 +68,16 @@ public void shouldNotWarnWhenCalledWithinTimeout(final TestContext ctx) { verify(spyTimer, atLeast(2)).resetTimer(); // should not warn verify(spyEngineQosTimer, never()).logTimeoutWarning(); - async.complete(); + testContext.completeNow(); } catch (Exception ex) { - ctx.fail(ex); + testContext.failNow(ex); } }); } @Test - public void shouldWarnWhenNotCalledWithinTimeout(final TestContext ctx) { + public void shouldWarnWhenNotCalledWithinTimeout() { final long TEST_QOS_TIMEOUT = 75L; - final Async async = ctx.async(); final var spyEngineQosTimer = spy(engineQosTimer); final var spyTimer = spy(new QosTimer(vertx, TEST_QOS_TIMEOUT, z -> spyEngineQosTimer.logTimeoutWarning())); @@ -92,9 +91,9 @@ public void shouldWarnWhenNotCalledWithinTimeout(final TestContext ctx) { verify(spyTimer, atLeastOnce()).resetTimer(); // should warn verify(spyEngineQosTimer, atLeastOnce()).logTimeoutWarning(); - async.complete(); + testContext.completeNow(); } catch (Exception ex) { - ctx.fail(ex); + testContext.failNow(ex); } }); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerChangeTargetGasLimitTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerChangeTargetGasLimitTest.java index 2039aef1821..f31ac5e986f 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerChangeTargetGasLimitTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerChangeTargetGasLimitTest.java @@ -20,12 +20,12 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Mock; public class MinerChangeTargetGasLimitTest { @@ -33,7 +33,7 @@ public class MinerChangeTargetGasLimitTest { @Mock MiningCoordinator miningCoordinator; private MinerChangeTargetGasLimit minerChangeTargetGasLimit; - @Before + @BeforeEach public void setUp() { initMocks(this); minerChangeTargetGasLimit = new MinerChangeTargetGasLimit(miningCoordinator); @@ -50,7 +50,7 @@ public void failsWithInvalidValue() { assertThat(minerChangeTargetGasLimit.response(request)) .isEqualTo( - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS)); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_PARAMS)); } @Test @@ -66,7 +66,7 @@ public void failsWithInvalidGasCalculator() { .isEqualTo( new JsonRpcErrorResponse( request.getRequest().getId(), - JsonRpcError.TARGET_GAS_LIMIT_MODIFICATION_UNSUPPORTED)); + RpcErrorType.TARGET_GAS_LIMIT_MODIFICATION_UNSUPPORTED)); } private JsonRpcRequestContext request(final long longParam) { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerSetCoinbaseTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerSetCoinbaseTest.java index 9df4e5688de..a50a9576b08 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerSetCoinbaseTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerSetCoinbaseTest.java @@ -25,26 +25,26 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class MinerSetCoinbaseTest { private MinerSetCoinbase method; @Mock private MiningCoordinator miningCoordinator; - @Before + @BeforeEach public void before() { this.method = new MinerSetCoinbase(miningCoordinator); } @@ -89,7 +89,7 @@ public void shouldSetCoinbaseWhenRequestHasAddress() { public void shouldReturnAnInvalidRequestIfUnderlyingOperationThrowsUnsupportedOperation() { final JsonRpcRequestContext request = minerSetCoinbaseRequest("0x0"); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_REQUEST); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_REQUEST); doAnswer( invocation -> { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerSetEtherbaseTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerSetEtherbaseTest.java index e4eb3c23797..d43e54a04a1 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerSetEtherbaseTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerSetEtherbaseTest.java @@ -21,21 +21,21 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class MinerSetEtherbaseTest { private MinerSetEtherbase method; @Mock private MinerSetCoinbase minerSetCoinbase; - @Before + @BeforeEach public void before() { this.method = new MinerSetEtherbase(minerSetCoinbase); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStartTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStartTest.java index eb09f5f6666..203948f6739 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStartTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStartTest.java @@ -20,27 +20,27 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.blockcreation.CoinbaseNotSetException; import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class MinerStartTest { private MinerStart method; @Mock private PoWMiningCoordinator miningCoordinator; - @Before + @BeforeEach public void before() { method = new MinerStart(miningCoordinator); } @@ -76,7 +76,7 @@ public void shouldReturnFalseWhenMiningDoesNotStart() { public void shouldReturnCoinbaseNotSetErrorWhenCoinbaseHasNotBeenSet() { final JsonRpcRequestContext request = minerStart(); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.COINBASE_NOT_SET); + new JsonRpcErrorResponse(null, RpcErrorType.COINBASE_NOT_SET); doThrow(new CoinbaseNotSetException("")).when(miningCoordinator).enable(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStopTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStopTest.java index f5c443d3a52..28e3198c9c6 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStopTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStopTest.java @@ -23,20 +23,20 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class MinerStopTest { private MinerStop method; @Mock private PoWMiningCoordinator miningCoordinator; - @Before + @BeforeEach public void before() { method = new MinerStop(miningCoordinator); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddAccountsToAllowlistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddAccountsToAllowlistTest.java index 2eb4cb038b5..0892cc5c647 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddAccountsToAllowlistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddAccountsToAllowlistTest.java @@ -23,10 +23,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.permissioning.AccountLocalConfigPermissioningController; import org.hyperledger.besu.ethereum.permissioning.AllowlistOperationResult; @@ -34,19 +34,19 @@ import java.util.Arrays; import java.util.List; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PermAddAccountsToAllowlistTest { @Mock private AccountLocalConfigPermissioningController accountWhitelist; private PermAddAccountsToAllowlist method; - @Before + @BeforeEach public void before() { method = new PermAddAccountsToAllowlist(java.util.Optional.of(accountWhitelist)); } @@ -70,7 +70,7 @@ public void whenAccountsAreAddedToWhitelistShouldReturnSuccess() { @Test public void whenAccountIsInvalidShouldReturnInvalidAccountErrorResponse() { JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.ACCOUNT_ALLOWLIST_INVALID_ENTRY); + new JsonRpcErrorResponse(null, RpcErrorType.ACCOUNT_ALLOWLIST_INVALID_ENTRY); when(accountWhitelist.addAccounts(any())) .thenReturn(AllowlistOperationResult.ERROR_INVALID_ENTRY); @@ -82,7 +82,7 @@ public void whenAccountIsInvalidShouldReturnInvalidAccountErrorResponse() { @Test public void whenAccountExistsShouldReturnExistingEntryErrorResponse() { JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.ACCOUNT_ALLOWLIST_EXISTING_ENTRY); + new JsonRpcErrorResponse(null, RpcErrorType.ACCOUNT_ALLOWLIST_EXISTING_ENTRY); when(accountWhitelist.addAccounts(any())) .thenReturn(AllowlistOperationResult.ERROR_EXISTING_ENTRY); @@ -94,7 +94,7 @@ public void whenAccountExistsShouldReturnExistingEntryErrorResponse() { @Test public void whenInputHasDuplicatedAccountsShouldReturnDuplicatedEntryErrorResponse() { JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.ACCOUNT_ALLOWLIST_DUPLICATED_ENTRY); + new JsonRpcErrorResponse(null, RpcErrorType.ACCOUNT_ALLOWLIST_DUPLICATED_ENTRY); when(accountWhitelist.addAccounts(any())) .thenReturn(AllowlistOperationResult.ERROR_DUPLICATED_ENTRY); @@ -106,7 +106,7 @@ public void whenInputHasDuplicatedAccountsShouldReturnDuplicatedEntryErrorRespon @Test public void whenEmptyListOnRequestShouldReturnEmptyEntryErrorResponse() { JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.ACCOUNT_ALLOWLIST_EMPTY_ENTRY); + new JsonRpcErrorResponse(null, RpcErrorType.ACCOUNT_ALLOWLIST_EMPTY_ENTRY); when(accountWhitelist.addAccounts(eq(new ArrayList<>()))) .thenReturn(AllowlistOperationResult.ERROR_EMPTY_ENTRY); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddAccountsToWhitelistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddAccountsToWhitelistTest.java index f423402b429..0dd4fb73d46 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddAccountsToWhitelistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddAccountsToWhitelistTest.java @@ -23,10 +23,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.permissioning.AccountLocalConfigPermissioningController; import org.hyperledger.besu.ethereum.permissioning.AllowlistOperationResult; @@ -34,20 +34,20 @@ import java.util.Arrays; import java.util.List; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; @Deprecated -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PermAddAccountsToWhitelistTest { @Mock private AccountLocalConfigPermissioningController accountWhitelist; private PermAddAccountsToWhitelist method; - @Before + @BeforeEach public void before() { method = new PermAddAccountsToWhitelist(java.util.Optional.of(accountWhitelist)); } @@ -71,7 +71,7 @@ public void whenAccountsAreAddedToWhitelistShouldReturnSuccess() { @Test public void whenAccountIsInvalidShouldReturnInvalidAccountErrorResponse() { JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.ACCOUNT_ALLOWLIST_INVALID_ENTRY); + new JsonRpcErrorResponse(null, RpcErrorType.ACCOUNT_ALLOWLIST_INVALID_ENTRY); when(accountWhitelist.addAccounts(any())) .thenReturn(AllowlistOperationResult.ERROR_INVALID_ENTRY); @@ -83,7 +83,7 @@ public void whenAccountIsInvalidShouldReturnInvalidAccountErrorResponse() { @Test public void whenAccountExistsShouldReturnExistingEntryErrorResponse() { JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.ACCOUNT_ALLOWLIST_EXISTING_ENTRY); + new JsonRpcErrorResponse(null, RpcErrorType.ACCOUNT_ALLOWLIST_EXISTING_ENTRY); when(accountWhitelist.addAccounts(any())) .thenReturn(AllowlistOperationResult.ERROR_EXISTING_ENTRY); @@ -95,7 +95,7 @@ public void whenAccountExistsShouldReturnExistingEntryErrorResponse() { @Test public void whenInputHasDuplicatedAccountsShouldReturnDuplicatedEntryErrorResponse() { JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.ACCOUNT_ALLOWLIST_DUPLICATED_ENTRY); + new JsonRpcErrorResponse(null, RpcErrorType.ACCOUNT_ALLOWLIST_DUPLICATED_ENTRY); when(accountWhitelist.addAccounts(any())) .thenReturn(AllowlistOperationResult.ERROR_DUPLICATED_ENTRY); @@ -107,7 +107,7 @@ public void whenInputHasDuplicatedAccountsShouldReturnDuplicatedEntryErrorRespon @Test public void whenEmptyListOnRequestShouldReturnEmptyEntryErrorResponse() { JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.ACCOUNT_ALLOWLIST_EMPTY_ENTRY); + new JsonRpcErrorResponse(null, RpcErrorType.ACCOUNT_ALLOWLIST_EMPTY_ENTRY); when(accountWhitelist.addAccounts(eq(new ArrayList<>()))) .thenReturn(AllowlistOperationResult.ERROR_EMPTY_ENTRY); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddNodesToAllowlistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddNodesToAllowlistTest.java index 500b7090336..a4930c2b959 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddNodesToAllowlistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddNodesToAllowlistTest.java @@ -25,10 +25,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.permissioning.AllowlistOperationResult; import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController; @@ -39,13 +39,13 @@ import org.assertj.core.api.Assertions; import org.assertj.core.util.Lists; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PermAddNodesToAllowlistTest { private PermAddNodesToAllowlist method; @@ -61,7 +61,7 @@ public class PermAddNodesToAllowlistTest { @Mock private NodeLocalConfigPermissioningController nodeLocalConfigPermissioningController; - @Before + @BeforeEach public void setUp() { method = new PermAddNodesToAllowlist(Optional.of(nodeLocalConfigPermissioningController)); } @@ -77,7 +77,7 @@ public void shouldThrowInvalidJsonRpcParametersExceptionWhenOnlyBadEnode() { final JsonRpcRequestContext request = buildRequest(enodeList); final JsonRpcResponse expected = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_INVALID_ENTRY); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_INVALID_ENTRY); when(nodeLocalConfigPermissioningController.addNodes(eq(enodeList))) .thenThrow(IllegalArgumentException.class); @@ -93,7 +93,7 @@ public void shouldThrowInvalidJsonRpcParametersExceptionWhenBadEnodeInList() { final JsonRpcRequestContext request = buildRequest(enodeList); final JsonRpcResponse expected = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_INVALID_ENTRY); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_INVALID_ENTRY); when(nodeLocalConfigPermissioningController.addNodes(eq(enodeList))) .thenThrow(IllegalArgumentException.class); @@ -108,7 +108,7 @@ public void shouldThrowInvalidJsonRpcParametersExceptionWhenEmptyEnode() { final JsonRpcRequestContext request = buildRequest(Collections.emptyList()); final JsonRpcResponse expected = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_EMPTY_ENTRY); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_EMPTY_ENTRY); when(nodeLocalConfigPermissioningController.addNodes(Collections.emptyList())) .thenReturn(new NodesAllowlistResult(AllowlistOperationResult.ERROR_EMPTY_ENTRY)); @@ -123,7 +123,7 @@ public void whenRequestContainsDuplicatedNodesShouldReturnDuplicatedEntryError() final JsonRpcRequestContext request = buildRequest(Lists.newArrayList(enode1, enode1)); final JsonRpcResponse expected = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_DUPLICATED_ENTRY); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_DUPLICATED_ENTRY); when(nodeLocalConfigPermissioningController.addNodes(any())) .thenReturn(new NodesAllowlistResult(AllowlistOperationResult.ERROR_DUPLICATED_ENTRY)); @@ -138,7 +138,7 @@ public void whenRequestContainsEmptyListOfNodesShouldReturnEmptyEntryError() { final JsonRpcRequestContext request = buildRequest(new ArrayList<>()); final JsonRpcResponse expected = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_EMPTY_ENTRY); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_EMPTY_ENTRY); when(nodeLocalConfigPermissioningController.addNodes(eq(new ArrayList<>()))) .thenReturn(new NodesAllowlistResult(AllowlistOperationResult.ERROR_EMPTY_ENTRY)); @@ -188,7 +188,7 @@ public void shouldFailWhenP2pDisabled() { ; final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_NOT_ENABLED); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_NOT_ENABLED); Assertions.assertThat(method.response(request)) .usingRecursiveComparison() diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddNodesToWhitelistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddNodesToWhitelistTest.java index 09eacb8220c..237094b90c8 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddNodesToWhitelistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddNodesToWhitelistTest.java @@ -25,10 +25,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.permissioning.AllowlistOperationResult; import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController; @@ -39,14 +39,14 @@ import org.assertj.core.api.Assertions; import org.assertj.core.util.Lists; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; @Deprecated -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PermAddNodesToWhitelistTest { private PermAddNodesToWhitelist method; @@ -62,7 +62,7 @@ public class PermAddNodesToWhitelistTest { @Mock private NodeLocalConfigPermissioningController nodeLocalConfigPermissioningController; - @Before + @BeforeEach public void setUp() { method = new PermAddNodesToWhitelist(Optional.of(nodeLocalConfigPermissioningController)); } @@ -78,7 +78,7 @@ public void shouldThrowInvalidJsonRpcParametersExceptionWhenOnlyBadEnode() { final JsonRpcRequestContext request = buildRequest(enodeList); final JsonRpcResponse expected = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_INVALID_ENTRY); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_INVALID_ENTRY); when(nodeLocalConfigPermissioningController.addNodes(eq(enodeList))) .thenThrow(IllegalArgumentException.class); @@ -94,7 +94,7 @@ public void shouldThrowInvalidJsonRpcParametersExceptionWhenBadEnodeInList() { final JsonRpcRequestContext request = buildRequest(enodeList); final JsonRpcResponse expected = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_INVALID_ENTRY); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_INVALID_ENTRY); when(nodeLocalConfigPermissioningController.addNodes(eq(enodeList))) .thenThrow(IllegalArgumentException.class); @@ -109,7 +109,7 @@ public void shouldThrowInvalidJsonRpcParametersExceptionWhenEmptyEnode() { final JsonRpcRequestContext request = buildRequest(Collections.emptyList()); final JsonRpcResponse expected = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_EMPTY_ENTRY); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_EMPTY_ENTRY); when(nodeLocalConfigPermissioningController.addNodes(Collections.emptyList())) .thenReturn(new NodesAllowlistResult(AllowlistOperationResult.ERROR_EMPTY_ENTRY)); @@ -124,7 +124,7 @@ public void whenRequestContainsDuplicatedNodesShouldReturnDuplicatedEntryError() final JsonRpcRequestContext request = buildRequest(Lists.newArrayList(enode1, enode1)); final JsonRpcResponse expected = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_DUPLICATED_ENTRY); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_DUPLICATED_ENTRY); when(nodeLocalConfigPermissioningController.addNodes(any())) .thenReturn(new NodesAllowlistResult(AllowlistOperationResult.ERROR_DUPLICATED_ENTRY)); @@ -139,7 +139,7 @@ public void whenRequestContainsEmptyListOfNodesShouldReturnEmptyEntryError() { final JsonRpcRequestContext request = buildRequest(new ArrayList<>()); final JsonRpcResponse expected = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_EMPTY_ENTRY); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_EMPTY_ENTRY); when(nodeLocalConfigPermissioningController.addNodes(eq(new ArrayList<>()))) .thenReturn(new NodesAllowlistResult(AllowlistOperationResult.ERROR_EMPTY_ENTRY)); @@ -189,7 +189,7 @@ public void shouldFailWhenP2pDisabled() { ; final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_NOT_ENABLED); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_NOT_ENABLED); Assertions.assertThat(method.response(request)) .usingRecursiveComparison() diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetAccountsAllowlistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetAccountsAllowlistTest.java index d7ffc872fb8..1e1a8adee73 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetAccountsAllowlistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetAccountsAllowlistTest.java @@ -27,13 +27,13 @@ import java.util.Arrays; import java.util.List; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PermGetAccountsAllowlistTest { private static final JsonRpcRequestContext request = @@ -42,7 +42,7 @@ public class PermGetAccountsAllowlistTest { @Mock private AccountLocalConfigPermissioningController accountAllowlist; private PermGetAccountsAllowlist method; - @Before + @BeforeEach public void before() { method = new PermGetAccountsAllowlist(java.util.Optional.of(accountAllowlist)); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetAccountsWhitelistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetAccountsWhitelistTest.java index 55300293d7a..024349d8b23 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetAccountsWhitelistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetAccountsWhitelistTest.java @@ -27,14 +27,14 @@ import java.util.Arrays; import java.util.List; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; @Deprecated -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PermGetAccountsWhitelistTest { private static final JsonRpcRequestContext request = @@ -43,7 +43,7 @@ public class PermGetAccountsWhitelistTest { @Mock private AccountLocalConfigPermissioningController accountWhitelist; private PermGetAccountsWhitelist method; - @Before + @BeforeEach public void before() { method = new PermGetAccountsWhitelist(java.util.Optional.of(accountWhitelist)); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetNodesAllowlistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetNodesAllowlistTest.java index 38b6c12cfbb..b3a121c5b95 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetNodesAllowlistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetNodesAllowlistTest.java @@ -22,10 +22,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController; import java.util.Collections; @@ -34,13 +34,13 @@ import org.assertj.core.api.Assertions; import org.assertj.core.util.Lists; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PermGetNodesAllowlistTest { private PermGetNodesAllowlist method; @@ -55,7 +55,7 @@ public class PermGetNodesAllowlistTest { @Mock private NodeLocalConfigPermissioningController nodeLocalConfigPermissioningController; - @Before + @BeforeEach public void setUp() { method = new PermGetNodesAllowlist(Optional.of(nodeLocalConfigPermissioningController)); } @@ -106,7 +106,7 @@ public void shouldFailWhenP2pDisabled() { final JsonRpcRequestContext request = buildRequest(); final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_NOT_ENABLED); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_NOT_ENABLED); Assertions.assertThat(method.response(request)) .usingRecursiveComparison() diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetNodesWhitelistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetNodesWhitelistTest.java index 914caedbc0d..9981cb27e74 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetNodesWhitelistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetNodesWhitelistTest.java @@ -22,10 +22,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController; import java.util.Collections; @@ -34,14 +34,14 @@ import org.assertj.core.api.Assertions; import org.assertj.core.util.Lists; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; @Deprecated -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PermGetNodesWhitelistTest { private PermGetNodesWhitelist method; @@ -56,7 +56,7 @@ public class PermGetNodesWhitelistTest { @Mock private NodeLocalConfigPermissioningController nodeLocalConfigPermissioningController; - @Before + @BeforeEach public void setUp() { method = new PermGetNodesWhitelist(Optional.of(nodeLocalConfigPermissioningController)); } @@ -107,7 +107,7 @@ public void shouldFailWhenP2pDisabled() { final JsonRpcRequestContext request = buildRequest(); final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_NOT_ENABLED); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_NOT_ENABLED); Assertions.assertThat(method.response(request)) .usingRecursiveComparison() diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermReloadPermissionsFromFileTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermReloadPermissionsFromFileTest.java index cbc957aa5c8..54dce93daa4 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermReloadPermissionsFromFileTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermReloadPermissionsFromFileTest.java @@ -20,29 +20,29 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.permissioning.AccountLocalConfigPermissioningController; import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PermReloadPermissionsFromFileTest { @Mock private AccountLocalConfigPermissioningController accountLocalConfigPermissioningController; @Mock private NodeLocalConfigPermissioningController nodeLocalConfigPermissioningController; private PermReloadPermissionsFromFile method; - @Before + @BeforeEach public void before() { method = new PermReloadPermissionsFromFile( @@ -58,7 +58,7 @@ public void getNameShouldReturnExpectedName() { @Test public void whenBothControllersAreNotPresentMethodShouldReturnPermissioningDisabled() { JsonRpcResponse expectedErrorResponse = - new JsonRpcErrorResponse(null, JsonRpcError.PERMISSIONING_NOT_ENABLED); + new JsonRpcErrorResponse(null, RpcErrorType.PERMISSIONING_NOT_ENABLED); method = new PermReloadPermissionsFromFile(Optional.empty(), Optional.empty()); @@ -81,7 +81,7 @@ public void whenControllersReloadSucceedsMethodShouldReturnSuccess() { public void whenControllerReloadFailsMethodShouldReturnError() { doThrow(new RuntimeException()).when(accountLocalConfigPermissioningController).reload(); JsonRpcResponse expectedErrorResponse = - new JsonRpcErrorResponse(null, JsonRpcError.ALLOWLIST_RELOAD_ERROR); + new JsonRpcErrorResponse(null, RpcErrorType.ALLOWLIST_RELOAD_ERROR); JsonRpcResponse response = method.response(reloadRequest()); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveAccountsFromAllowlistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveAccountsFromAllowlistTest.java index 60d3f7a8f8e..a70ac9e4b3a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveAccountsFromAllowlistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveAccountsFromAllowlistTest.java @@ -23,10 +23,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.permissioning.AccountLocalConfigPermissioningController; import org.hyperledger.besu.ethereum.permissioning.AllowlistOperationResult; @@ -34,19 +34,19 @@ import java.util.Arrays; import java.util.List; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PermRemoveAccountsFromAllowlistTest { @Mock private AccountLocalConfigPermissioningController accountAllowlist; private PermRemoveAccountsFromAllowlist method; - @Before + @BeforeEach public void before() { method = new PermRemoveAccountsFromAllowlist(java.util.Optional.of(accountAllowlist)); } @@ -71,7 +71,7 @@ public void whenAccountsAreRemovedFromAllowlistShouldReturnSuccess() { @Test public void whenAccountIsInvalidShouldReturnInvalidAccountErrorResponse() { JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.ACCOUNT_ALLOWLIST_INVALID_ENTRY); + new JsonRpcErrorResponse(null, RpcErrorType.ACCOUNT_ALLOWLIST_INVALID_ENTRY); when(accountAllowlist.removeAccounts(any())) .thenReturn(AllowlistOperationResult.ERROR_INVALID_ENTRY); @@ -83,7 +83,7 @@ public void whenAccountIsInvalidShouldReturnInvalidAccountErrorResponse() { @Test public void whenAccountIsAbsentShouldReturnAbsentAccountErrorResponse() { JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.ACCOUNT_ALLOWLIST_ABSENT_ENTRY); + new JsonRpcErrorResponse(null, RpcErrorType.ACCOUNT_ALLOWLIST_ABSENT_ENTRY); when(accountAllowlist.removeAccounts(any())) .thenReturn(AllowlistOperationResult.ERROR_ABSENT_ENTRY); @@ -95,7 +95,7 @@ public void whenAccountIsAbsentShouldReturnAbsentAccountErrorResponse() { @Test public void whenInputHasDuplicatedAccountsShouldReturnDuplicatedEntryErrorResponse() { JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.ACCOUNT_ALLOWLIST_DUPLICATED_ENTRY); + new JsonRpcErrorResponse(null, RpcErrorType.ACCOUNT_ALLOWLIST_DUPLICATED_ENTRY); when(accountAllowlist.removeAccounts(any())) .thenReturn(AllowlistOperationResult.ERROR_DUPLICATED_ENTRY); @@ -107,7 +107,7 @@ public void whenInputHasDuplicatedAccountsShouldReturnDuplicatedEntryErrorRespon @Test public void whenEmptyListOnRequestShouldReturnEmptyEntryErrorResponse() { JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.ACCOUNT_ALLOWLIST_EMPTY_ENTRY); + new JsonRpcErrorResponse(null, RpcErrorType.ACCOUNT_ALLOWLIST_EMPTY_ENTRY); when(accountAllowlist.removeAccounts(eq(new ArrayList<>()))) .thenReturn(AllowlistOperationResult.ERROR_EMPTY_ENTRY); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveAccountsFromWhitelistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveAccountsFromWhitelistTest.java index dd70d9458a9..934329052dc 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveAccountsFromWhitelistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveAccountsFromWhitelistTest.java @@ -23,10 +23,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.permissioning.AccountLocalConfigPermissioningController; import org.hyperledger.besu.ethereum.permissioning.AllowlistOperationResult; @@ -34,20 +34,20 @@ import java.util.Arrays; import java.util.List; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; @Deprecated -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PermRemoveAccountsFromWhitelistTest { @Mock private AccountLocalConfigPermissioningController accountWhitelist; private PermRemoveAccountsFromWhitelist method; - @Before + @BeforeEach public void before() { method = new PermRemoveAccountsFromWhitelist(java.util.Optional.of(accountWhitelist)); } @@ -72,7 +72,7 @@ public void whenAccountsAreRemovedFromWhitelistShouldReturnSuccess() { @Test public void whenAccountIsInvalidShouldReturnInvalidAccountErrorResponse() { JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.ACCOUNT_ALLOWLIST_INVALID_ENTRY); + new JsonRpcErrorResponse(null, RpcErrorType.ACCOUNT_ALLOWLIST_INVALID_ENTRY); when(accountWhitelist.removeAccounts(any())) .thenReturn(AllowlistOperationResult.ERROR_INVALID_ENTRY); @@ -84,7 +84,7 @@ public void whenAccountIsInvalidShouldReturnInvalidAccountErrorResponse() { @Test public void whenAccountIsAbsentShouldReturnAbsentAccountErrorResponse() { JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.ACCOUNT_ALLOWLIST_ABSENT_ENTRY); + new JsonRpcErrorResponse(null, RpcErrorType.ACCOUNT_ALLOWLIST_ABSENT_ENTRY); when(accountWhitelist.removeAccounts(any())) .thenReturn(AllowlistOperationResult.ERROR_ABSENT_ENTRY); @@ -96,7 +96,7 @@ public void whenAccountIsAbsentShouldReturnAbsentAccountErrorResponse() { @Test public void whenInputHasDuplicatedAccountsShouldReturnDuplicatedEntryErrorResponse() { JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.ACCOUNT_ALLOWLIST_DUPLICATED_ENTRY); + new JsonRpcErrorResponse(null, RpcErrorType.ACCOUNT_ALLOWLIST_DUPLICATED_ENTRY); when(accountWhitelist.removeAccounts(any())) .thenReturn(AllowlistOperationResult.ERROR_DUPLICATED_ENTRY); @@ -108,7 +108,7 @@ public void whenInputHasDuplicatedAccountsShouldReturnDuplicatedEntryErrorRespon @Test public void whenEmptyListOnRequestShouldReturnEmptyEntryErrorResponse() { JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.ACCOUNT_ALLOWLIST_EMPTY_ENTRY); + new JsonRpcErrorResponse(null, RpcErrorType.ACCOUNT_ALLOWLIST_EMPTY_ENTRY); when(accountWhitelist.removeAccounts(eq(new ArrayList<>()))) .thenReturn(AllowlistOperationResult.ERROR_EMPTY_ENTRY); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromAllowlistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromAllowlistTest.java index 5fdd9b86cfa..a07becc2518 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromAllowlistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromAllowlistTest.java @@ -25,10 +25,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.permissioning.AllowlistOperationResult; import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController; @@ -39,13 +39,13 @@ import org.assertj.core.api.Assertions; import org.assertj.core.util.Lists; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PermRemoveNodesFromAllowlistTest { private PermRemoveNodesFromAllowlist method; @@ -61,7 +61,7 @@ public class PermRemoveNodesFromAllowlistTest { @Mock private NodeLocalConfigPermissioningController nodeLocalConfigPermissioningController; - @Before + @BeforeEach public void setUp() { method = new PermRemoveNodesFromAllowlist(Optional.of(nodeLocalConfigPermissioningController)); } @@ -76,7 +76,7 @@ public void shouldThrowInvalidJsonRpcParametersExceptionWhenBadEnode() { final JsonRpcRequestContext request = buildRequest(Lists.newArrayList(badEnode)); final JsonRpcResponse expected = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_INVALID_ENTRY); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_INVALID_ENTRY); when(nodeLocalConfigPermissioningController.removeNodes(eq(Lists.newArrayList(badEnode)))) .thenThrow(IllegalArgumentException.class); @@ -91,7 +91,7 @@ public void shouldThrowInvalidJsonRpcParametersExceptionWhenEmptyList() { final JsonRpcRequestContext request = buildRequest(Collections.emptyList()); final JsonRpcResponse expected = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_EMPTY_ENTRY); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_EMPTY_ENTRY); when(nodeLocalConfigPermissioningController.removeNodes(Collections.emptyList())) .thenReturn(new NodesAllowlistResult(AllowlistOperationResult.ERROR_EMPTY_ENTRY)); @@ -139,7 +139,7 @@ public void shouldFailWhenP2pDisabled() { final JsonRpcRequestContext request = buildRequest(Lists.newArrayList(enode1, enode2, enode3)); final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_NOT_ENABLED); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_NOT_ENABLED); Assertions.assertThat(method.response(request)) .usingRecursiveComparison() @@ -151,7 +151,7 @@ public void whenRequestContainsDuplicatedNodesShouldReturnDuplicatedEntryError() final JsonRpcRequestContext request = buildRequest(Lists.newArrayList(enode1, enode1)); final JsonRpcResponse expected = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_DUPLICATED_ENTRY); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_DUPLICATED_ENTRY); when(nodeLocalConfigPermissioningController.removeNodes(any())) .thenReturn(new NodesAllowlistResult(AllowlistOperationResult.ERROR_DUPLICATED_ENTRY)); @@ -166,7 +166,7 @@ public void whenRequestContainsEmptyListOfNodesShouldReturnEmptyEntryError() { final JsonRpcRequestContext request = buildRequest(new ArrayList<>()); final JsonRpcResponse expected = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_EMPTY_ENTRY); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_EMPTY_ENTRY); when(nodeLocalConfigPermissioningController.removeNodes(eq(new ArrayList<>()))) .thenReturn(new NodesAllowlistResult(AllowlistOperationResult.ERROR_EMPTY_ENTRY)); @@ -181,7 +181,7 @@ public void shouldReturnCantRemoveBootnodeWhenRemovingBootnode() { final JsonRpcRequestContext request = buildRequest(Lists.newArrayList(enode1)); final JsonRpcResponse expected = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_FIXED_NODE_CANNOT_BE_REMOVED); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_FIXED_NODE_CANNOT_BE_REMOVED); when(nodeLocalConfigPermissioningController.removeNodes(any())) .thenReturn( diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromWhitelistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromWhitelistTest.java index 79c4a7271a2..45630a25ad1 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromWhitelistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromWhitelistTest.java @@ -25,10 +25,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.permissioning.AllowlistOperationResult; import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController; @@ -39,14 +39,14 @@ import org.assertj.core.api.Assertions; import org.assertj.core.util.Lists; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; @Deprecated -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PermRemoveNodesFromWhitelistTest { private PermRemoveNodesFromWhitelist method; @@ -62,7 +62,7 @@ public class PermRemoveNodesFromWhitelistTest { @Mock private NodeLocalConfigPermissioningController nodeLocalConfigPermissioningController; - @Before + @BeforeEach public void setUp() { method = new PermRemoveNodesFromWhitelist(Optional.of(nodeLocalConfigPermissioningController)); } @@ -77,7 +77,7 @@ public void shouldThrowInvalidJsonRpcParametersExceptionWhenBadEnode() { final JsonRpcRequestContext request = buildRequest(Lists.newArrayList(badEnode)); final JsonRpcResponse expected = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_INVALID_ENTRY); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_INVALID_ENTRY); when(nodeLocalConfigPermissioningController.removeNodes(eq(Lists.newArrayList(badEnode)))) .thenThrow(IllegalArgumentException.class); @@ -92,7 +92,7 @@ public void shouldThrowInvalidJsonRpcParametersExceptionWhenEmptyList() { final JsonRpcRequestContext request = buildRequest(Collections.emptyList()); final JsonRpcResponse expected = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_EMPTY_ENTRY); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_EMPTY_ENTRY); when(nodeLocalConfigPermissioningController.removeNodes(Collections.emptyList())) .thenReturn(new NodesAllowlistResult(AllowlistOperationResult.ERROR_EMPTY_ENTRY)); @@ -140,7 +140,7 @@ public void shouldFailWhenP2pDisabled() { final JsonRpcRequestContext request = buildRequest(Lists.newArrayList(enode1, enode2, enode3)); final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_NOT_ENABLED); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_NOT_ENABLED); Assertions.assertThat(method.response(request)) .usingRecursiveComparison() @@ -152,7 +152,7 @@ public void whenRequestContainsDuplicatedNodesShouldReturnDuplicatedEntryError() final JsonRpcRequestContext request = buildRequest(Lists.newArrayList(enode1, enode1)); final JsonRpcResponse expected = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_DUPLICATED_ENTRY); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_DUPLICATED_ENTRY); when(nodeLocalConfigPermissioningController.removeNodes(any())) .thenReturn(new NodesAllowlistResult(AllowlistOperationResult.ERROR_DUPLICATED_ENTRY)); @@ -167,7 +167,7 @@ public void whenRequestContainsEmptyListOfNodesShouldReturnEmptyEntryError() { final JsonRpcRequestContext request = buildRequest(new ArrayList<>()); final JsonRpcResponse expected = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_EMPTY_ENTRY); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_EMPTY_ENTRY); when(nodeLocalConfigPermissioningController.removeNodes(eq(new ArrayList<>()))) .thenReturn(new NodesAllowlistResult(AllowlistOperationResult.ERROR_EMPTY_ENTRY)); @@ -182,7 +182,7 @@ public void shouldReturnCantRemoveBootnodeWhenRemovingBootnode() { final JsonRpcRequestContext request = buildRequest(Lists.newArrayList(enode1)); final JsonRpcResponse expected = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.NODE_ALLOWLIST_FIXED_NODE_CANNOT_BE_REMOVED); + request.getRequest().getId(), RpcErrorType.NODE_ALLOWLIST_FIXED_NODE_CANNOT_BE_REMOVED); when(nodeLocalConfigPermissioningController.removeNodes(any())) .thenReturn( diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockParameterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockParameterTest.java index fa0899ee2c7..3e8d534e70f 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockParameterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockParameterTest.java @@ -17,7 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class BlockParameterTest { @Test diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/DepositParameterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/DepositParameterTest.java index 6d2d383759b..3d59adbf2c1 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/DepositParameterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/DepositParameterTest.java @@ -26,7 +26,7 @@ import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt64; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class DepositParameterTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadAttributesParameterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadAttributesParameterTest.java index 56bee9fa279..20386bb4345 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadAttributesParameterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadAttributesParameterTest.java @@ -25,7 +25,7 @@ import java.util.List; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class EnginePayloadAttributesParameterTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/FilterParameterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/FilterParameterTest.java index 73521ce6678..18912c8ceb6 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/FilterParameterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/FilterParameterTest.java @@ -34,7 +34,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.Lists; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class FilterParameterTest { private static final String TOPIC_FORMAT = "0x%064d"; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/TraceTypeParameterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/TraceTypeParameterTest.java index af1b734ebe0..2c12cc6935a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/TraceTypeParameterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/TraceTypeParameterTest.java @@ -22,7 +22,7 @@ import java.util.List; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class TraceTypeParameterTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/WithdrawalParameterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/WithdrawalParameterTest.java index 450ffd76762..80aa67fdea7 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/WithdrawalParameterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/WithdrawalParameterTest.java @@ -23,7 +23,7 @@ import org.hyperledger.besu.ethereum.core.Withdrawal; import org.apache.tuweni.units.bigints.UInt64; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class WithdrawalParameterTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/MultiTenancyRpcMethodDecoratorTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/MultiTenancyRpcMethodDecoratorTest.java index 2b1bc68e3f6..8803540392c 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/MultiTenancyRpcMethodDecoratorTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/MultiTenancyRpcMethodDecoratorTest.java @@ -20,22 +20,22 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponseType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcUnauthorizedResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import io.vertx.core.json.JsonObject; import io.vertx.ext.auth.User; import io.vertx.ext.auth.impl.UserImpl; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class MultiTenancyRpcMethodDecoratorTest { @Mock private JsonRpcMethod jsonRpcMethod; @@ -75,7 +75,7 @@ public void failsWhenHasNoToken() { final JsonRpcResponse response = tokenRpcDecorator.response(rpcRequestContext); assertThat(response.getType()).isEqualTo(JsonRpcResponseType.UNAUTHORIZED); final JsonRpcUnauthorizedResponse errorResponse = (JsonRpcUnauthorizedResponse) response; - assertThat(errorResponse.getError()).isEqualTo(JsonRpcError.UNAUTHORIZED); + assertThat(errorResponse.getErrorType()).isEqualTo(RpcErrorType.UNAUTHORIZED); } @Test @@ -91,6 +91,6 @@ public void failsWhenTokenDoesNotHavePrivacyPublicKey() { final JsonRpcResponse response = tokenRpcDecorator.response(rpcRequestContext); assertThat(response.getType()).isEqualTo(JsonRpcResponseType.ERROR); final JsonRpcErrorResponse errorResponse = (JsonRpcErrorResponse) response; - assertThat(errorResponse.getError()).isEqualTo(JsonRpcError.INVALID_REQUEST); + assertThat(errorResponse.getErrorType()).isEqualTo(RpcErrorType.INVALID_REQUEST); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/MultiTenancyUserUtilTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/MultiTenancyUserUtilTest.java index 372612d27dc..ff4e5294799 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/MultiTenancyUserUtilTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/MultiTenancyUserUtilTest.java @@ -23,7 +23,7 @@ import io.vertx.core.json.JsonObject; import io.vertx.ext.auth.User; import io.vertx.ext.auth.impl.UserImpl; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class MultiTenancyUserUtilTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransactionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransactionTest.java index 4ad29c1931c..4d209b847ba 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransactionTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransactionTest.java @@ -28,20 +28,20 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.privacy.MultiTenancyValidationException; import org.hyperledger.besu.ethereum.privacy.PrivateTransaction; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EeaSendRawTransactionTest extends BaseEeaSendRawTransaction { // RLP encode fails creating a transaction without privateFrom so must be manually encoded @@ -58,7 +58,7 @@ public class EeaSendRawTransactionTest extends BaseEeaSendRawTransaction { RestrictedOffchainEeaSendRawTransaction method; - @Before + @BeforeEach public void before() { method = @@ -111,7 +111,7 @@ public void invalidTransactionRlpDecoding() { new JsonRpcRequest("2.0", "eea_sendRawTransaction", new String[] {rawTransaction})); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.DECODE_ERROR); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.DECODE_ERROR); final JsonRpcResponse actualResponse = method.response(request); @@ -128,7 +128,7 @@ public void invalidTransactionWithoutPrivateFromFieldFailsWithDecodeError() { new String[] {PRIVATE_TRANSACTION_RLP_PRIVACY_GROUP_NO_PRIVATE_FROM})); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.DECODE_ERROR); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.DECODE_ERROR); final JsonRpcResponse actualResponse = method.response(request); @@ -144,7 +144,7 @@ public void invalidTransactionIsNotSentToEnclaveAndIsNotAddedToTransactionPool() final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( validPrivateForTransactionRequest.getRequest().getId(), - JsonRpcError.PRIVATE_TRANSACTION_INVALID); + RpcErrorType.PRIVATE_TRANSACTION_INVALID); final JsonRpcResponse actualResponse = method.response(validPrivateForTransactionRequest); @@ -163,7 +163,7 @@ public void invalidTransactionFailingWithMultiTenancyValidationErrorReturnsUnaut final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( - validPrivateForTransactionRequest.getRequest().getId(), JsonRpcError.ENCLAVE_ERROR); + validPrivateForTransactionRequest.getRequest().getId(), RpcErrorType.ENCLAVE_ERROR); final JsonRpcResponse actualResponse = method.response(validPrivateForTransactionRequest); @@ -174,49 +174,49 @@ public void invalidTransactionFailingWithMultiTenancyValidationErrorReturnsUnaut @Test public void transactionWithNonceBelowAccountNonceIsRejected() { verifyErrorForInvalidTransaction( - TransactionInvalidReason.NONCE_TOO_LOW, JsonRpcError.NONCE_TOO_LOW); + TransactionInvalidReason.NONCE_TOO_LOW, RpcErrorType.NONCE_TOO_LOW); } @Test public void transactionWithNonceAboveAccountNonceIsRejected() { verifyErrorForInvalidTransaction( - TransactionInvalidReason.NONCE_TOO_HIGH, JsonRpcError.NONCE_TOO_HIGH); + TransactionInvalidReason.NONCE_TOO_HIGH, RpcErrorType.NONCE_TOO_HIGH); } @Test public void transactionWithInvalidSignatureIsRejected() { verifyErrorForInvalidTransaction( - TransactionInvalidReason.INVALID_SIGNATURE, JsonRpcError.INVALID_TRANSACTION_SIGNATURE); + TransactionInvalidReason.INVALID_SIGNATURE, RpcErrorType.INVALID_TRANSACTION_SIGNATURE); } @Test public void transactionWithIntrinsicGasExceedingGasLimitIsRejected() { verifyErrorForInvalidTransaction( TransactionInvalidReason.INTRINSIC_GAS_EXCEEDS_GAS_LIMIT, - JsonRpcError.PMT_FAILED_INTRINSIC_GAS_EXCEEDS_LIMIT); + RpcErrorType.PMT_FAILED_INTRINSIC_GAS_EXCEEDS_LIMIT); } @Test public void transactionWithUpfrontGasExceedingAccountBalanceIsRejected() { verifyErrorForInvalidTransaction( TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE, - JsonRpcError.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE); + RpcErrorType.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE); } @Test public void transactionWithGasLimitExceedingBlockGasLimitIsRejected() { verifyErrorForInvalidTransaction( - TransactionInvalidReason.EXCEEDS_BLOCK_GAS_LIMIT, JsonRpcError.EXCEEDS_BLOCK_GAS_LIMIT); + TransactionInvalidReason.EXCEEDS_BLOCK_GAS_LIMIT, RpcErrorType.EXCEEDS_BLOCK_GAS_LIMIT); } @Test public void transactionWithNotWhitelistedSenderAccountIsRejected() { verifyErrorForInvalidTransaction( - TransactionInvalidReason.TX_SENDER_NOT_AUTHORIZED, JsonRpcError.TX_SENDER_NOT_AUTHORIZED); + TransactionInvalidReason.TX_SENDER_NOT_AUTHORIZED, RpcErrorType.TX_SENDER_NOT_AUTHORIZED); } private void verifyErrorForInvalidTransaction( - final TransactionInvalidReason transactionInvalidReason, final JsonRpcError expectedError) { + final TransactionInvalidReason transactionInvalidReason, final RpcErrorType expectedError) { when(privacyController.createPrivateMarkerTransactionPayload(any(), any(), any())) .thenReturn(MOCK_ORION_KEY); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/PluginEeaSendRawTransactionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/PluginEeaSendRawTransactionTest.java index 78e1b7876b6..43eeccc46e0 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/PluginEeaSendRawTransactionTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/PluginEeaSendRawTransactionTest.java @@ -23,17 +23,17 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PluginEeaSendRawTransactionTest extends BaseEeaSendRawTransaction { PluginEeaSendRawTransaction method; - @Before + @BeforeEach public void before() { method = new PluginEeaSendRawTransaction( diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/RestrictedFlexibleEeaSendRawTransactionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/RestrictedFlexibleEeaSendRawTransactionTest.java index 7d11084308e..a2e2d80eb4a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/RestrictedFlexibleEeaSendRawTransactionTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/RestrictedFlexibleEeaSendRawTransactionTest.java @@ -21,22 +21,22 @@ import org.hyperledger.besu.enclave.types.PrivacyGroup; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import java.util.Arrays; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class RestrictedFlexibleEeaSendRawTransactionTest extends BaseEeaSendRawTransaction { static final String ENCLAVE_PUBLIC_KEY = "S28yYlZxRCtuTmxOWUw1RUU3eTNJZE9udmlmdGppaXo="; @@ -44,7 +44,7 @@ public class RestrictedFlexibleEeaSendRawTransactionTest extends BaseEeaSendRawT RestrictedFlexibleEeaSendRawTransaction method; - @Before + @BeforeEach public void before() { method = new RestrictedFlexibleEeaSendRawTransaction( @@ -92,7 +92,7 @@ public void transactionFailsForLegacyPrivateTransaction() { final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( validPrivateForTransactionRequest.getRequest().getId(), - JsonRpcError.FLEXIBLE_PRIVACY_GROUP_ID_NOT_AVAILABLE); + RpcErrorType.FLEXIBLE_PRIVACY_GROUP_ID_NOT_AVAILABLE); final JsonRpcResponse actualResponse = method.response(validPrivateForTransactionRequest); @@ -109,7 +109,7 @@ public void offchainPrivacyGroupTransactionFailsWhenFlexiblePrivacyGroupFeatureI final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( validPrivacyGroupTransactionRequest.getRequest().getId(), - JsonRpcError.FLEXIBLE_PRIVACY_GROUP_DOES_NOT_EXIST); + RpcErrorType.FLEXIBLE_PRIVACY_GROUP_DOES_NOT_EXIST); final JsonRpcResponse actualResponse = method.response(validPrivacyGroupTransactionRequest); @@ -124,7 +124,7 @@ public void flexiblePrivacyGroupTransactionFailsWhenGroupDoesNotExist() { final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( validPrivacyGroupTransactionRequest.getRequest().getId(), - JsonRpcError.FLEXIBLE_PRIVACY_GROUP_DOES_NOT_EXIST); + RpcErrorType.FLEXIBLE_PRIVACY_GROUP_DOES_NOT_EXIST); final JsonRpcResponse actualResponse = method.response(validPrivacyGroupTransactionRequest); @@ -140,7 +140,7 @@ public void flexiblePrivacyGroupTransactionFailsWhenGroupDoesNotExist() { final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( validPrivacyGroupTransactionRequest.getRequest().getId(), - JsonRpcError.UNSUPPORTED_PRIVATE_TRANSACTION_TYPE); + RpcErrorType.UNSUPPORTED_PRIVATE_TRANSACTION_TYPE); assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); } @@ -154,7 +154,7 @@ public void flexiblePrivacyGroupTransactionFailsWhenGroupDoesNotExist() { final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( validPrivacyGroupTransactionRequest.getRequest().getId(), - JsonRpcError.UNSUPPORTED_PRIVATE_TRANSACTION_TYPE); + RpcErrorType.UNSUPPORTED_PRIVATE_TRANSACTION_TYPE); assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/RestrictedOffchainEeaSendRawTransactionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/RestrictedOffchainEeaSendRawTransactionTest.java index 897346620f4..0004469d4d2 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/RestrictedOffchainEeaSendRawTransactionTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/RestrictedOffchainEeaSendRawTransactionTest.java @@ -22,20 +22,20 @@ import org.hyperledger.besu.enclave.types.PrivacyGroup; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class RestrictedOffchainEeaSendRawTransactionTest extends BaseEeaSendRawTransaction { static final String ENCLAVE_PUBLIC_KEY = "S28yYlZxRCtuTmxOWUw1RUU3eTNJZE9udmlmdGppaXo="; @@ -43,7 +43,7 @@ public class RestrictedOffchainEeaSendRawTransactionTest extends BaseEeaSendRawT RestrictedOffchainEeaSendRawTransaction method; - @Before + @BeforeEach public void before() { method = new RestrictedOffchainEeaSendRawTransaction( @@ -108,7 +108,7 @@ public void validPantheonPrivacyGroupTransactionIsSentToTransactionPool() { final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( validPrivacyGroupTransactionRequest.getRequest().getId(), - JsonRpcError.UNSUPPORTED_PRIVATE_TRANSACTION_TYPE); + RpcErrorType.UNSUPPORTED_PRIVATE_TRANSACTION_TYPE); assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); } @@ -122,7 +122,7 @@ public void validPantheonPrivacyGroupTransactionIsSentToTransactionPool() { final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( validPrivacyGroupTransactionRequest.getRequest().getId(), - JsonRpcError.UNSUPPORTED_PRIVATE_TRANSACTION_TYPE); + RpcErrorType.UNSUPPORTED_PRIVATE_TRANSACTION_TYPE); assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCallTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCallTest.java index 1c447360b74..d36291e25c6 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCallTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCallTest.java @@ -43,13 +43,13 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PrivCallTest { private PrivCall method; @@ -62,7 +62,7 @@ public class PrivCallTest { private final PrivacyController privacyController = mock(RestrictedDefaultPrivacyController.class); - @Before + @BeforeEach public void setUp() { method = new PrivCall(blockchainQueries, privacyController, privacyIdProvider); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCreatePrivacyGroupTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCreatePrivacyGroupTest.java index 3b565f9f045..9be3122c1e4 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCreatePrivacyGroupTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCreatePrivacyGroupTest.java @@ -29,9 +29,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.parameters.CreatePrivacyGroupParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.privacy.PrivacyController; @@ -41,8 +41,8 @@ import io.vertx.ext.auth.User; import io.vertx.ext.auth.impl.UserImpl; import org.assertj.core.util.Lists; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; @SuppressWarnings("MockNotUsedInProduction") public class PrivCreatePrivacyGroupTest { @@ -60,7 +60,7 @@ public class PrivCreatePrivacyGroupTest { new UserImpl(new JsonObject().put("privacyPublicKey", ENCLAVE_PUBLIC_KEY), new JsonObject()); private final PrivacyIdProvider privacyIdProvider = (user) -> ENCLAVE_PUBLIC_KEY; - @Before + @BeforeEach public void setUp() { when(privacyParameters.getEnclave()).thenReturn(enclave); when(privacyParameters.isEnabled()).thenReturn(true); @@ -270,8 +270,8 @@ public void returnsCorrectErrorEnclaveError() { final JsonRpcErrorResponse response = (JsonRpcErrorResponse) privCreatePrivacyGroup.response(request); - final JsonRpcError result = response.getError(); + final RpcErrorType result = response.getErrorType(); - assertThat(result).isEqualTo(JsonRpcError.ENCLAVE_ERROR); + assertThat(result).isEqualTo(RpcErrorType.ENCLAVE_ERROR); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDebugGetStateRootTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDebugGetStateRootTest.java index c199408a4a2..7c2b6162665 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDebugGetStateRootTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDebugGetStateRootTest.java @@ -17,8 +17,8 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.FIND_PRIVACY_GROUP_ERROR; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INTERNAL_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.FIND_PRIVACY_GROUP_ERROR; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INTERNAL_ERROR; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; @@ -43,8 +43,8 @@ import java.util.Optional; import org.bouncycastle.util.encoders.Base64; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class PrivDebugGetStateRootTest { @@ -64,7 +64,7 @@ public class PrivDebugGetStateRootTest { private final PrivacyController privacyController = mock(RestrictedDefaultPrivacyController.class); - @Before + @BeforeEach public void setUp() { method = new PrivDebugGetStateRoot(blockchainQueries, privacyIdProvider, privacyController); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDeletePrivacyGroupTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDeletePrivacyGroupTest.java index d08c27f79cc..e85eb242994 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDeletePrivacyGroupTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDeletePrivacyGroupTest.java @@ -23,18 +23,18 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.privacy.MultiTenancyValidationException; import org.hyperledger.besu.ethereum.privacy.PrivacyController; import io.vertx.core.json.JsonObject; import io.vertx.ext.auth.User; import io.vertx.ext.auth.impl.UserImpl; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class PrivDeletePrivacyGroupTest { private static final String ENCLAVE_PUBLIC_KEY = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; @@ -46,7 +46,7 @@ public class PrivDeletePrivacyGroupTest { private final PrivacyIdProvider privacyIdProvider = (user) -> ENCLAVE_PUBLIC_KEY; private JsonRpcRequestContext request; - @Before + @BeforeEach public void setUp() { request = new JsonRpcRequestContext( @@ -79,7 +79,7 @@ public void failsWithDeletePrivacyGroupErrorIfEnclaveFails() { final JsonRpcErrorResponse response = (JsonRpcErrorResponse) privDeletePrivacyGroup.response(request); - assertThat(response.getError()).isEqualTo(JsonRpcError.DELETE_PRIVACY_GROUP_ERROR); + assertThat(response.getErrorType()).isEqualTo(RpcErrorType.DELETE_PRIVACY_GROUP_ERROR); verify(privacyController).deletePrivacyGroup(PRIVACY_GROUP_ID, ENCLAVE_PUBLIC_KEY); } @@ -93,7 +93,7 @@ public void failsWithUnauthorizedErrorIfMultiTenancyValidationFails() { final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.DELETE_PRIVACY_GROUP_ERROR); + request.getRequest().getId(), RpcErrorType.DELETE_PRIVACY_GROUP_ERROR); final JsonRpcResponse response = privDeletePrivacyGroup.response(request); assertThat(response).isInstanceOf(JsonRpcErrorResponse.class); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransactionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransactionTest.java index 4976487e23c..2ca2f71a8bc 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransactionTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransactionTest.java @@ -24,10 +24,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.privacy.MultiTenancyValidationException; import org.hyperledger.besu.ethereum.privacy.PrivacyController; @@ -39,13 +39,13 @@ import io.vertx.ext.auth.User; import io.vertx.ext.auth.impl.UserImpl; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PrivDistributeRawTransactionTest { private static final String VALID_PRIVATE_TRANSACTION_RLP_PRIVACY_GROUP = @@ -66,7 +66,7 @@ public class PrivDistributeRawTransactionTest { private PrivDistributeRawTransaction method; @Mock private PrivacyController privacyController; - @Before + @BeforeEach public void before() { method = new PrivDistributeRawTransaction(privacyController, privacyIdProvider, false); } @@ -120,7 +120,7 @@ public void invalidTransactionFailingWithMultiTenancyValidationErrorReturnsUnaut user); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.ENCLAVE_ERROR); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.ENCLAVE_ERROR); final JsonRpcResponse actualResponse = method.response(request); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivFindPrivacyGroupTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivFindPrivacyGroupTest.java index 250f10638c8..5f79661bb4c 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivFindPrivacyGroupTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivFindPrivacyGroupTest.java @@ -26,10 +26,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.privacy.MultiTenancyValidationException; import org.hyperledger.besu.ethereum.privacy.PrivacyController; @@ -40,8 +40,8 @@ import io.vertx.ext.auth.User; import io.vertx.ext.auth.impl.UserImpl; import org.assertj.core.util.Lists; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; @SuppressWarnings("MockNotUsedInProduction") public class PrivFindPrivacyGroupTest { @@ -61,7 +61,7 @@ public class PrivFindPrivacyGroupTest { private JsonRpcRequestContext request; private PrivacyGroup privacyGroup; - @Before + @BeforeEach public void setUp() { when(privacyParameters.getEnclave()).thenReturn(enclave); when(privacyParameters.isEnabled()).thenReturn(true); @@ -101,7 +101,7 @@ public void failsWithFindPrivacyGroupErrorIfEnclaveFails() { final JsonRpcErrorResponse response = (JsonRpcErrorResponse) privFindPrivacyGroup.response(request); - assertThat(response.getError()).isEqualTo(JsonRpcError.FIND_PRIVACY_GROUP_ERROR); + assertThat(response.getErrorType()).isEqualTo(RpcErrorType.FIND_PRIVACY_GROUP_ERROR); verify(privacyController).findPrivacyGroupByMembers(ADDRESSES, ENCLAVE_PUBLIC_KEY); } @@ -114,7 +114,7 @@ public void failsWithUnauthorizedErrorIfMultiTenancyValidationFails() { final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.FIND_PRIVACY_GROUP_ERROR); + request.getRequest().getId(), RpcErrorType.FIND_PRIVACY_GROUP_ERROR); final JsonRpcResponse response = privFindPrivacyGroup.response(request); assertThat(response).isEqualTo(expectedResponse); verify(privacyController).findPrivacyGroupByMembers(ADDRESSES, ENCLAVE_PUBLIC_KEY); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetCodeTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetCodeTest.java index c1890b8063c..6482b3e6b8f 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetCodeTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetCodeTest.java @@ -35,13 +35,16 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class PrivGetCodeTest { @Mock private PrivacyController privacyController; @@ -58,7 +61,7 @@ public class PrivGetCodeTest { private PrivGetCode method; private JsonRpcRequestContext privGetCodeRequest; - @Before + @BeforeEach public void before() { when(privacyIdProvider.getPrivacyUserId(any())).thenReturn(enclavePublicKey); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetEeaTransactionCountTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetEeaTransactionCountTest.java index d87d125569d..6539d2f1ae1 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetEeaTransactionCountTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetEeaTransactionCountTest.java @@ -26,10 +26,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.privacy.MultiTenancyValidationException; import org.hyperledger.besu.ethereum.privacy.PrivacyController; @@ -91,8 +91,8 @@ void nonceProviderThrowsRuntimeExceptionProducesErrorResponse() { assertThat(response).isInstanceOf(JsonRpcErrorResponse.class); final JsonRpcErrorResponse errorResponse = (JsonRpcErrorResponse) response; - assertThat(errorResponse.getError()) - .isEqualTo(JsonRpcError.GET_PRIVATE_TRANSACTION_NONCE_ERROR); + assertThat(errorResponse.getErrorType()) + .isEqualTo(RpcErrorType.GET_PRIVATE_TRANSACTION_NONCE_ERROR); } @Test @@ -107,8 +107,8 @@ void nonceProviderThrowsAnExceptionProducesErrorResponse() { assertThat(response).isInstanceOf(JsonRpcErrorResponse.class); final JsonRpcErrorResponse errorResponse = (JsonRpcErrorResponse) response; - assertThat(errorResponse.getError()) - .isEqualTo(JsonRpcError.GET_PRIVATE_TRANSACTION_NONCE_ERROR); + assertThat(errorResponse.getErrorType()) + .isEqualTo(RpcErrorType.GET_PRIVATE_TRANSACTION_NONCE_ERROR); } @Test @@ -123,8 +123,8 @@ void failsWithUnauthorizedErrorIfMultiTenancyValidationFails() { assertThat(response).isInstanceOf(JsonRpcErrorResponse.class); final JsonRpcErrorResponse errorResponse = (JsonRpcErrorResponse) response; - assertThat(errorResponse.getError()) - .isEqualTo(JsonRpcError.GET_PRIVATE_TRANSACTION_NONCE_ERROR); + assertThat(errorResponse.getErrorType()) + .isEqualTo(RpcErrorType.GET_PRIVATE_TRANSACTION_NONCE_ERROR); } private static Stream provideNonces() { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetFilterChangesTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetFilterChangesTest.java index d7a7c5caa7e..5d4d381c1ef 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetFilterChangesTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetFilterChangesTest.java @@ -31,10 +31,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivGetFilterChanges; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult; import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.privacy.MultiTenancyPrivacyController; @@ -46,13 +46,13 @@ import com.google.common.collect.Lists; import io.vertx.ext.auth.User; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PrivGetFilterChangesTest { private final String FILTER_ID = "0xdbdb02abb65a2ba57a1cc0336c17ef75"; @@ -65,7 +65,7 @@ public class PrivGetFilterChangesTest { private PrivGetFilterChanges method; - @Before + @BeforeEach public void before() { method = new PrivGetFilterChanges(filterManager, privacyController, privacyIdProvider); } @@ -150,7 +150,7 @@ public void returnFilterNotFoundWhenLogsReturnIsNull() { when(filterManager.logsChanges(eq(FILTER_ID))).thenReturn(null); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.FILTER_NOT_FOUND); + new JsonRpcErrorResponse(null, RpcErrorType.FILTER_NOT_FOUND); final JsonRpcRequestContext request = privGetFilterChangesRequest(PRIVACY_GROUP_ID, FILTER_ID); final JsonRpcResponse response = method.response(request); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetFilterLogsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetFilterLogsTest.java index feb3ac34321..1bd983ffd74 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetFilterLogsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetFilterLogsTest.java @@ -28,10 +28,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivGetFilterLogs; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult; import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.privacy.PrivacyController; @@ -41,13 +41,13 @@ import com.google.common.collect.Lists; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PrivGetFilterLogsTest { private final String FILTER_ID = "0xdbdb02abb65a2ba57a1cc0336c17ef75"; @@ -59,7 +59,7 @@ public class PrivGetFilterLogsTest { private PrivGetFilterLogs method; - @Before + @BeforeEach public void before() { method = new PrivGetFilterLogs(filterManager, privacyController, privacyIdProvider); } @@ -127,7 +127,7 @@ public void returnFilterNotFoundWhenLogsReturnIsNull() { when(filterManager.logs(eq(FILTER_ID))).thenReturn(null); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.LOGS_FILTER_NOT_FOUND); + new JsonRpcErrorResponse(null, RpcErrorType.LOGS_FILTER_NOT_FOUND); final JsonRpcRequestContext request = privGetFilterLogsRequest(PRIVACY_GROUP_ID, FILTER_ID); final JsonRpcResponse response = method.response(request); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetLogsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetLogsTest.java index d800cc277fe..09eb8b00895 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetLogsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetLogsTest.java @@ -30,10 +30,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.query.LogsQuery; @@ -52,13 +52,13 @@ import com.google.common.collect.Lists; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PrivGetLogsTest { private final String PRIVACY_GROUP_ID = "B1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; @@ -70,7 +70,7 @@ public class PrivGetLogsTest { private PrivGetLogs method; - @Before + @BeforeEach public void before() { method = new PrivGetLogs(blockchainQueries, privacyQueries, privacyController, privacyIdProvider); @@ -116,7 +116,7 @@ public void filterWithInvalidParameters() { final JsonRpcRequestContext request = privGetLogRequest(PRIVACY_GROUP_ID, invalidFilter); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(null, RpcErrorType.INVALID_PARAMS); final JsonRpcResponse response = method.response(request); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivacyPrecompileAddressTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivacyPrecompileAddressTest.java index 88cf1e29f03..52542f40c9c 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivacyPrecompileAddressTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivacyPrecompileAddressTest.java @@ -27,7 +27,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.core.PrivacyParameters; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PrivGetPrivacyPrecompileAddressTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransactionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransactionTest.java index 580a3388dad..8b8f858699a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransactionTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransactionTest.java @@ -24,10 +24,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.PrivateTransactionGroupResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.PrivateTransactionLegacyResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.PrivateTransactionResult; @@ -42,13 +42,13 @@ import io.vertx.core.json.JsonObject; import io.vertx.ext.auth.User; import io.vertx.ext.auth.impl.UserImpl; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PrivGetPrivateTransactionTest { @Mock private PrivacyController privacyController; @@ -63,7 +63,7 @@ public class PrivGetPrivateTransactionTest { private PrivGetPrivateTransaction privGetPrivateTransaction; private Transaction markerTransaction; - @Before + @BeforeEach public void before() { privGetPrivateTransaction = new PrivGetPrivateTransaction(privacyController, privacyIdProvider); @@ -125,7 +125,7 @@ public void returnNullWhenPrivateMarkerTransactionDoesNotExist() { public void failsWithEnclaveErrorOnEnclaveError() { final JsonRpcRequestContext request = createRequestContext(); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.ENCLAVE_ERROR); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.ENCLAVE_ERROR); when(privacyController.findPrivateTransactionByPmtHash(any(), any())) .thenThrow(new EnclaveClientException(500, "enclave failure")); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionCountTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionCountTest.java index d4be2da546a..8549b8e6fb9 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionCountTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionCountTest.java @@ -25,10 +25,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.privacy.MultiTenancyValidationException; import org.hyperledger.besu.ethereum.privacy.PrivacyController; @@ -92,7 +92,7 @@ void failsWithNonceErrorIfExceptionIsThrown() { final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.GET_PRIVATE_TRANSACTION_NONCE_ERROR); + request.getRequest().getId(), RpcErrorType.GET_PRIVATE_TRANSACTION_NONCE_ERROR); final JsonRpcResponse response = privGetTransactionCount.response(request); assertThat(response).isEqualTo(expectedResponse); } @@ -112,7 +112,7 @@ void failsWithUnauthorizedErrorIfMultiTenancyValidationFails() { final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.GET_PRIVATE_TRANSACTION_NONCE_ERROR); + request.getRequest().getId(), RpcErrorType.GET_PRIVATE_TRANSACTION_NONCE_ERROR); final JsonRpcResponse response = privGetTransactionCount.response(request); assertThat(response).isEqualTo(expectedResponse); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceiptTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceiptTest.java index 00ebff2352e..fc0ba883f6d 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceiptTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceiptTest.java @@ -49,13 +49,16 @@ import io.vertx.ext.auth.impl.UserImpl; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class PrivGetTransactionReceiptTest { final Bytes internalPrivacyGroupId = Bytes.random(32); @@ -72,7 +75,7 @@ public class PrivGetTransactionReceiptTest { private final PrivacyIdProvider privacyIdProvider = (user) -> VALID_BASE64_ENCLAVE_KEY.toBase64String(); - @Before + @BeforeEach public void setUp() { final PrivateTransactionReceipt receipt = new PrivateTransactionReceipt(1, Collections.emptyList(), Bytes.EMPTY, Optional.empty()); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivNewFilterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivNewFilterTest.java index dad2bdd3247..f9e9795f1cd 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivNewFilterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivNewFilterTest.java @@ -31,9 +31,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.query.LogsQuery; import org.hyperledger.besu.ethereum.privacy.PrivacyController; import org.hyperledger.besu.evm.log.LogTopic; @@ -44,13 +44,13 @@ import io.vertx.ext.auth.User; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PrivNewFilterTest { private final String ENCLAVE_KEY = "enclave_key"; @@ -62,7 +62,7 @@ public class PrivNewFilterTest { private PrivNewFilter method; - @Before + @BeforeEach public void before() { method = new PrivNewFilter(filterManager, privacyController, privacyIdProvider); } @@ -107,7 +107,7 @@ public void filterWithInvalidParameters() { final JsonRpcRequestContext request = privNewFilterRequest(PRIVACY_GROUP_ID, invalidFilter); final JsonRpcResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(null, RpcErrorType.INVALID_PARAMS); final JsonRpcResponse response = method.response(request); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivUninstallFilterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivUninstallFilterTest.java index f5287a8104a..a0e28aab163 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivUninstallFilterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivUninstallFilterTest.java @@ -27,13 +27,13 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; import org.hyperledger.besu.ethereum.privacy.PrivacyController; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PrivUninstallFilterTest { private final String FILTER_ID = "0xdbdb02abb65a2ba57a1cc0336c17ef75"; @@ -45,7 +45,7 @@ public class PrivUninstallFilterTest { private PrivUninstallFilter method; - @Before + @BeforeEach public void before() { method = new PrivUninstallFilter(filterManager, privacyController, privacyIdProvider); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/privx/PrivxFindFlexiblePrivacyGroupTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/privx/PrivxFindFlexiblePrivacyGroupTest.java index 8dacbaabdd1..15efc2e8b6a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/privx/PrivxFindFlexiblePrivacyGroupTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/privx/PrivxFindFlexiblePrivacyGroupTest.java @@ -24,10 +24,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.privacy.MultiTenancyValidationException; import org.hyperledger.besu.ethereum.privacy.PrivacyController; @@ -37,8 +37,8 @@ import io.vertx.ext.auth.User; import io.vertx.ext.auth.impl.UserImpl; import org.assertj.core.util.Lists; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class PrivxFindFlexiblePrivacyGroupTest { private static final String ENCLAVE_PUBLIC_KEY = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; @@ -57,7 +57,7 @@ public class PrivxFindFlexiblePrivacyGroupTest { private PrivacyGroup privacyGroup; private PrivxFindFlexiblePrivacyGroup privxFindFlexiblePrivacyGroup; - @Before + @BeforeEach public void setUp() { request = new JsonRpcRequestContext( @@ -94,7 +94,7 @@ public void failsWithFindPrivacyGroupErrorIfEnclaveFails() { final JsonRpcErrorResponse response = (JsonRpcErrorResponse) privxFindFlexiblePrivacyGroup.response(request); - assertThat(response.getError()).isEqualTo(JsonRpcError.FIND_FLEXIBLE_PRIVACY_GROUP_ERROR); + assertThat(response.getErrorType()).isEqualTo(RpcErrorType.FIND_FLEXIBLE_PRIVACY_GROUP_ERROR); verify(privacyController).findPrivacyGroupByMembers(ADDRESSES, ENCLAVE_PUBLIC_KEY); } @@ -105,7 +105,7 @@ public void failsWithUnauthorizedErrorIfMultiTenancyValidationFails() { final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse( - request.getRequest().getId(), JsonRpcError.FIND_FLEXIBLE_PRIVACY_GROUP_ERROR); + request.getRequest().getId(), RpcErrorType.FIND_FLEXIBLE_PRIVACY_GROUP_ERROR); final JsonRpcResponse response = privxFindFlexiblePrivacyGroup.response(request); assertThat(response).isEqualTo(expectedResponse); verify(privacyController).findPrivacyGroupByMembers(ADDRESSES, ENCLAVE_PUBLIC_KEY); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracerTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracerTest.java index e2124a67c3f..70c6812c5cd 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracerTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracerTest.java @@ -16,7 +16,10 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -35,6 +38,7 @@ import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; import org.hyperledger.besu.ethereum.vm.DebugOperationTracer; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; import org.hyperledger.besu.evm.tracing.StandardJsonTracer; import org.hyperledger.besu.evm.worldstate.StackedUpdater; import org.hyperledger.besu.evm.worldstate.WorldUpdater; @@ -49,18 +53,20 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class TransactionTracerTest { - @Rule public TemporaryFolder traceDir = new TemporaryFolder(); + @TempDir private static Path traceDir; @Mock private ProtocolSchedule protocolSchedule; @Mock private Blockchain blockchain; @@ -78,6 +84,7 @@ public class TransactionTracerTest { @Mock private DebugOperationTracer tracer; @Mock private ProtocolSpec protocolSpec; + @Mock private GasCalculator gasCalculator; @Mock private Tracer.TraceableState mutableWorldState; @@ -98,7 +105,7 @@ public class TransactionTracerTest { private final Hash invalidBlockHash = Hash.fromHexString("1111111111111111111111111111111111111111111111111111111111111111"); - @Before + @BeforeEach public void setUp() throws Exception { transactionTracer = new TransactionTracer(new BlockReplay(protocolSchedule, blockchain)); when(transaction.getHash()).thenReturn(transactionHash); @@ -112,6 +119,8 @@ public void setUp() throws Exception { when(protocolSpec.getFeeMarket()).thenReturn(FeeMarket.london(0L)); when(blockchain.getChainHeadHeader()).thenReturn(blockHeader); when(protocolSpec.getBadBlocksManager()).thenReturn(new BadBlockManager()); + when(protocolSpec.getGasCalculator()).thenReturn(gasCalculator); + lenient().when(gasCalculator.computeExcessBlobGas(anyLong(), anyInt())).thenReturn(0L); } @Test @@ -230,7 +239,7 @@ public void traceTransactionToFileShouldReturnEmptyListWhenNoTransaction() { mutableWorldState, blockHash, Optional.of(ImmutableTransactionTraceParams.builder().build()), - traceDir.getRoot().toPath()); + traceDir); assertThat(transactionTraces).isEmpty(); } @@ -273,7 +282,7 @@ public void traceTransactionToFileShouldReturnResultFromProcessTransaction() thr mutableWorldState, blockHash, Optional.of(ImmutableTransactionTraceParams.builder().build()), - traceDir.getRoot().toPath()); + traceDir); assertThat(transactionTraces.size()).isEqualTo(1); assertThat(Files.readString(Path.of(transactionTraces.get(0)))) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlobsBundleV1Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlobsBundleV1Test.java new file mode 100644 index 00000000000..f38a3265046 --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlobsBundleV1Test.java @@ -0,0 +1,40 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.security.InvalidParameterException; +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class BlobsBundleV1Test { + @Test + public void blobsBundleV1MustHaveSameNumberOfElements() { + String actualMessage = + assertThrows( + InvalidParameterException.class, + () -> new BlobsBundleV1(List.of(""), List.of(""), List.of())) + .getMessage(); + final String expectedMessage = "There must be an equal number of blobs, commitments and proofs"; + assertThat(actualMessage).isEqualTo(expectedMessage); + } +} diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/NetworkResultTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/NetworkResultTest.java index 654b9044b09..876e795468f 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/NetworkResultTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/NetworkResultTest.java @@ -19,7 +19,7 @@ import java.net.InetSocketAddress; import java.net.SocketAddress; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class NetworkResultTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionCompleteResultTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionCompleteResultTest.java index 5c0a6c8f46f..41810226f7a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionCompleteResultTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionCompleteResultTest.java @@ -17,12 +17,12 @@ import static org.assertj.core.api.Assertions.assertThat; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.List; import java.util.Optional; @@ -30,7 +30,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.ImmutableList; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class TransactionCompleteResultTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/tracing/flat/FlatTraceGeneratorTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/tracing/flat/FlatTraceGeneratorTest.java index 3569cbd6fa5..3fc43cd62b2 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/tracing/flat/FlatTraceGeneratorTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/tracing/flat/FlatTraceGeneratorTest.java @@ -29,13 +29,13 @@ import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Assertions; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class FlatTraceGeneratorTest { @Mock private Transaction transaction; @Mock private TransactionProcessingResult transactionProcessingResult; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/tracing/flat/RewardTraceGeneratorTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/tracing/flat/RewardTraceGeneratorTest.java index ab8efc6c258..f8275182051 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/tracing/flat/RewardTraceGeneratorTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/tracing/flat/RewardTraceGeneratorTest.java @@ -40,13 +40,13 @@ import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class RewardTraceGeneratorTest { private final BlockDataGenerator gen = new BlockDataGenerator(); @@ -65,7 +65,7 @@ public class RewardTraceGeneratorTest { private final OptionalLong eraRounds = OptionalLong.of(5000000); private Block block; - @Before + @BeforeEach public void setUp() { final BlockBody blockBody = new BlockBody(Collections.emptyList(), List.of(ommerHeader)); final BlockHeader blockHeader = diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/transaction/pool/PendingTransactionFilterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/transaction/pool/PendingPermissionTransactionFilterTest.java similarity index 87% rename from ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/transaction/pool/PendingTransactionFilterTest.java rename to ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/transaction/pool/PendingPermissionTransactionFilterTest.java index 13c68f7c903..b08e5f7e8d2 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/transaction/pool/PendingTransactionFilterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/transaction/pool/PendingPermissionTransactionFilterTest.java @@ -38,16 +38,12 @@ import java.util.List; import java.util.Optional; import java.util.Set; -import java.util.stream.Collectors; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) -public class PendingTransactionFilterTest { +public class PendingPermissionTransactionFilterTest { - @Parameterized.Parameters public static Collection data() { return asList( new Object[][] { @@ -93,32 +89,20 @@ public static Collection data() { private final PendingTransactionFilter pendingTransactionFilter = new PendingTransactionFilter(); - private final List filters; - private final int limit; - private final List expectedListOfTransactionHash; - - public PendingTransactionFilterTest( + @ParameterizedTest + @MethodSource("data") + public void PendingPermissionTransactionFilterTest( final List filters, final int limit, final List expectedListOfTransactionHash) { - this.filters = filters; - this.limit = limit; - this.expectedListOfTransactionHash = - expectedListOfTransactionHash.stream() - .map(Hash::fromHexStringLenient) - .map(Hash::toHexString) - .collect(Collectors.toList()); - } - - @Test - public void localAndRemoteAddressShouldNotStartWithForwardSlash() { final Collection filteredList = pendingTransactionFilter.reduce(getPendingTransactions(), filters, limit); assertThat(filteredList.size()).isEqualTo(expectedListOfTransactionHash.size()); for (Transaction trx : filteredList) { - assertThat(expectedListOfTransactionHash).contains(trx.getHash().toHexString()); + assertThat(expectedListOfTransactionHash) + .contains(String.valueOf(trx.getHash().toBigInteger())); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PermJsonRpcMethodsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PermJsonRpcMethodsTest.java index 2dd89452517..a8f06f52650 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PermJsonRpcMethodsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PermJsonRpcMethodsTest.java @@ -46,13 +46,13 @@ import java.util.Map; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PermJsonRpcMethodsTest { @Mock private AccountLocalConfigPermissioningController accountLocalConfigPermissioningController; @@ -60,7 +60,7 @@ public class PermJsonRpcMethodsTest { private PermJsonRpcMethods permJsonRpcMethods; - @Before + @BeforeEach public void setup() { permJsonRpcMethods = new PermJsonRpcMethods( diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivJsonRpcMethodsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivJsonRpcMethodsTest.java index 98268eebdb7..249b2e7077e 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivJsonRpcMethodsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivJsonRpcMethodsTest.java @@ -30,13 +30,13 @@ import java.util.Map; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PrivJsonRpcMethodsTest { @Mock private BlockchainQueries blockchainQueries; @@ -47,7 +47,7 @@ public class PrivJsonRpcMethodsTest { private PrivJsonRpcMethods privJsonRpcMethods; - @Before + @BeforeEach public void setup() { privJsonRpcMethods = new PrivJsonRpcMethods( diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivacyApiGroupJsonRpcMethodsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivacyApiGroupJsonRpcMethodsTest.java index c546cbf6d57..ab7b90735b5 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivacyApiGroupJsonRpcMethodsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivacyApiGroupJsonRpcMethodsTest.java @@ -16,7 +16,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.PRIVACY_NOT_ENABLED; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.PRIVACY_NOT_ENABLED; import static org.mockito.Mockito.when; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis; @@ -42,13 +42,13 @@ import io.vertx.core.json.JsonObject; import io.vertx.ext.auth.User; import io.vertx.ext.auth.impl.UserImpl; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PrivacyApiGroupJsonRpcMethodsTest { private static final String DEFAULT_ENCLAVE_PUBLIC_KEY = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; @@ -61,7 +61,7 @@ public class PrivacyApiGroupJsonRpcMethodsTest { private TestPrivacyApiGroupJsonRpcMethods privacyApiGroupJsonRpcMethods; - @Before + @BeforeEach public void setup() { when(rpcMethod.getName()).thenReturn("priv_method"); @@ -143,7 +143,7 @@ public void rpcMethodsCreatedWhenPrivacyIsNotEnabledAreDisabled() { assertThat(response.getType()).isEqualTo(JsonRpcResponseType.ERROR); JsonRpcErrorResponse errorResponse = (JsonRpcErrorResponse) response; - assertThat(errorResponse.getError()).isEqualTo(PRIVACY_NOT_ENABLED); + assertThat(errorResponse.getErrorType()).isEqualTo(PRIVACY_NOT_ENABLED); } @Test diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivxJsonRpcMethodsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivxJsonRpcMethodsTest.java index f62257673eb..7f13a6b5834 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivxJsonRpcMethodsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivxJsonRpcMethodsTest.java @@ -30,13 +30,13 @@ import java.util.Map; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PrivxJsonRpcMethodsTest { @Mock private BlockchainQueries blockchainQueries; @@ -46,7 +46,7 @@ public class PrivxJsonRpcMethodsTest { private PrivxJsonRpcMethods privxJsonRpcMethods; - @Before + @BeforeEach public void setup() { privxJsonRpcMethods = new PrivxJsonRpcMethods( diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/parameters/TraceCallManyParameterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/parameters/TraceCallManyParameterTest.java index fe99b9a2779..4e236a12c1d 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/parameters/TraceCallManyParameterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/parameters/TraceCallManyParameterTest.java @@ -25,8 +25,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.exc.MismatchedInputException; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class TraceCallManyParameterTest { static final String emptyParamsJson = "[]"; @@ -57,7 +57,7 @@ public class TraceCallManyParameterTest { private ObjectMapper mapper; - @Before + @BeforeEach public void setup() { mapper = new ObjectMapper(); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/timeout/TimeoutHandlerTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/timeout/TimeoutHandlerTest.java index 7c485932e7c..c8047b806c7 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/timeout/TimeoutHandlerTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/timeout/TimeoutHandlerTest.java @@ -39,16 +39,12 @@ import io.vertx.core.Vertx; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.RoutingContext; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mockito; -@RunWith(Parameterized.class) public class TimeoutHandlerTest { - @Parameters public static Collection data() { return Arrays.asList( new Object[][] { @@ -59,24 +55,14 @@ public static Collection data() { } private static final TimeoutOptions DEFAULT_OPTS = TimeoutOptions.defaultOptions(); - private final Optional globalOptions; - private final RpcMethod method; - private final long timeoutSec; - private final boolean timerMustBeSet; - public TimeoutHandlerTest( + @ParameterizedTest + @MethodSource("data") + public void test( final Optional globalOptions, final RpcMethod method, final long timeoutSec, final boolean timerMustBeSet) { - this.globalOptions = globalOptions; - this.method = method; - this.timeoutSec = timeoutSec; - this.timerMustBeSet = timerMustBeSet; - } - - @Test - public void test() { final Map options; if (timerMustBeSet) { options = diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/JsonResponseStreamerTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/JsonResponseStreamerTest.java index 4228e6ed7d0..4ad036c2952 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/JsonResponseStreamerTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/JsonResponseStreamerTest.java @@ -28,21 +28,24 @@ import io.vertx.core.http.WebSocketFrame; import io.vertx.core.impl.future.FailedFuture; import io.vertx.core.impl.future.SucceededFuture; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentMatcher; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class JsonResponseStreamerTest { @Mock private ServerWebSocket response; @Mock private ServerWebSocket failedResponse; - @Before + @BeforeEach public void before() { when(response.writeFrame(any(WebSocketFrame.class))) .thenReturn(new SucceededFuture<>(null, null)); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/JsonRpcJWTTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/JsonRpcJWTTest.java index 66b82e73c6a..f44b490b82f 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/JsonRpcJWTTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/JsonRpcJWTTest.java @@ -44,6 +44,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.concurrent.TimeUnit; import io.vertx.core.MultiMap; import io.vertx.core.Vertx; @@ -55,24 +56,20 @@ import io.vertx.core.http.WebSocket; import io.vertx.core.http.WebSocketConnectOptions; import io.vertx.core.json.Json; -import io.vertx.ext.unit.Async; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import org.junit.After; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; - -@RunWith(VertxUnitRunner.class) +import io.vertx.junit5.VertxExtension; +import io.vertx.junit5.VertxTestContext; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +@ExtendWith(VertxExtension.class) public class JsonRpcJWTTest { - - @ClassRule public static final TemporaryFolder folder = new TemporaryFolder(); + private static final int VERTX_AWAIT_TIMEOUT_MILLIS = 10000; public static final String HOSTNAME = "127.0.0.1"; protected static Vertx vertx; - + private VertxTestContext testContext; private final JsonRpcConfiguration jsonRpcConfiguration = JsonRpcConfiguration.createEngineDefault(); private HttpClient httpClient; @@ -82,7 +79,7 @@ public class JsonRpcJWTTest { private Path bufferDir; private Map websocketMethods; - @Before + @BeforeEach public void initServerAndClient() { jsonRpcConfiguration.setPort(0); jsonRpcConfiguration.setHostsAllowlist(List.of("*")); @@ -93,6 +90,7 @@ public void initServerAndClient() { fail("couldn't load jwt key from jwt.hex in classpath"); } vertx = Vertx.vertx(); + testContext = new VertxTestContext(); websocketMethods = new WebSocketMethodsFactory( @@ -125,11 +123,11 @@ public boolean isHealthy(final ParamSource paramSource) { scheduler = new EthScheduler(1, 1, 1, new NoOpMetricsSystem()); } - @After + @AfterEach public void after() {} @Test - public void unauthenticatedWebsocketAllowedWithoutJWTAuth(final TestContext context) { + public void unauthenticatedWebsocketAllowedWithoutJWTAuth() throws InterruptedException { EngineJsonRpcService engineJsonRpcService = new EngineJsonRpcService( @@ -160,7 +158,6 @@ public void unauthenticatedWebsocketAllowedWithoutJWTAuth(final TestContext cont wsOpts.setHost(HOSTNAME); wsOpts.setURI("/"); - final Async async = context.async(); httpClient.webSocket( wsOpts, connected -> { @@ -178,18 +175,18 @@ public void unauthenticatedWebsocketAllowedWithoutJWTAuth(final TestContext cont MutableJsonRpcSuccessResponse messageReply = Json.decodeValue(resp.textData(), MutableJsonRpcSuccessResponse.class); assertThat(messageReply.getResult()).isEqualTo("0x1"); - async.complete(); + testContext.completeNow(); }); ws.writeTextMessage(Json.encode(req)); }); - async.awaitSuccess(10000); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); engineJsonRpcService.stop(); httpClient.close(); } @Test - public void httpRequestWithDefaultHeaderAndValidJWTIsAccepted(final TestContext context) { + public void httpRequestWithDefaultHeaderAndValidJWTIsAccepted() throws InterruptedException { EngineJsonRpcService engineJsonRpcService = new EngineJsonRpcService( @@ -223,7 +220,6 @@ public void httpRequestWithDefaultHeaderAndValidJWTIsAccepted(final TestContext "Authorization", "Bearer " + ((EngineAuthService) jwtAuth.get()).createToken()); wsOpts.addHeader(HttpHeaders.HOST, "anything"); - final Async async = context.async(); httpClient.webSocket( wsOpts, connected -> { @@ -242,18 +238,18 @@ public void httpRequestWithDefaultHeaderAndValidJWTIsAccepted(final TestContext MutableJsonRpcSuccessResponse messageReply = Json.decodeValue(resp.textData(), MutableJsonRpcSuccessResponse.class); assertThat(messageReply.getResult()).isEqualTo("0x1"); - async.complete(); + testContext.completeNow(); }); ws.writeTextMessage(Json.encode(req)); }); - async.awaitSuccess(10000); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); engineJsonRpcService.stop(); httpClient.close(); } @Test - public void wsRequestFromBadHostAndValidJWTIsDenied(final TestContext context) { + public void wsRequestFromBadHostAndValidJWTIsDenied() throws InterruptedException { JsonRpcConfiguration strictHost = JsonRpcConfiguration.createEngineDefault(); strictHost.setHostsAllowlist(List.of("localhost")); @@ -298,7 +294,6 @@ public void wsRequestFromBadHostAndValidJWTIsDenied(final TestContext context) { "Authorization", "Bearer " + ((EngineAuthService) jwtAuth.get()).createToken()); wsOpts.addHeader(HttpHeaders.HOST, "bogushost"); - final Async async = context.async(); httpClient.webSocket( wsOpts, connected -> { @@ -306,17 +301,17 @@ public void wsRequestFromBadHostAndValidJWTIsDenied(final TestContext context) { connected.cause().printStackTrace(); } assertThat(connected.succeeded()).isFalse(); - async.complete(); + testContext.completeNow(); }); - async.awaitSuccess(10000); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); engineJsonRpcService.stop(); httpClient.close(); } @Test - public void httpRequestFromBadHostAndValidJWTIsDenied(final TestContext context) { + public void httpRequestFromBadHostAndValidJWTIsDenied() throws InterruptedException { JsonRpcConfiguration strictHost = JsonRpcConfiguration.createEngineDefault(); strictHost.setHostsAllowlist(List.of("localhost")); @@ -358,7 +353,6 @@ public void httpRequestFromBadHostAndValidJWTIsDenied(final TestContext context) "Authorization", "Bearer " + ((EngineAuthService) jwtAuth.get()).createToken()) .set(HttpHeaders.HOST, "bogushost"); - final Async async = context.async(); httpClient.request( HttpMethod.GET, "/", @@ -372,18 +366,18 @@ public void httpRequestFromBadHostAndValidJWTIsDenied(final TestContext context) response -> { assertThat(response.result().statusCode()).isNotEqualTo(500); assertThat(response.result().statusCode()).isEqualTo(403); - async.complete(); + testContext.completeNow(); }); }); - async.awaitSuccess(10000); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); engineJsonRpcService.stop(); httpClient.close(); } @Test - public void httpRequestWithDefaultHeaderAndInvalidJWTIsDenied(final TestContext context) { + public void httpRequestWithDefaultHeaderAndInvalidJWTIsDenied() throws InterruptedException { EngineJsonRpcService engineJsonRpcService = new EngineJsonRpcService( @@ -415,7 +409,6 @@ public void httpRequestWithDefaultHeaderAndInvalidJWTIsDenied(final TestContext wsOpts.setURI("/"); wsOpts.addHeader("Authorization", "Bearer totallyunparseablenonsense"); - final Async async = context.async(); httpClient.webSocket( wsOpts, connected -> { @@ -423,10 +416,10 @@ public void httpRequestWithDefaultHeaderAndInvalidJWTIsDenied(final TestContext connected.cause().printStackTrace(); } assertThat(connected.succeeded()).isFalse(); - async.complete(); + testContext.completeNow(); }); - async.awaitSuccess(10000); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); engineJsonRpcService.stop(); httpClient.close(); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketConfigurationTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketConfigurationTest.java index 7bfbcd844c2..0eacc6c3242 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketConfigurationTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketConfigurationTest.java @@ -21,7 +21,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import com.google.common.collect.Lists; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class WebSocketConfigurationTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketHostAllowlistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketHostAllowlistTest.java index afdc42fd057..879788b26a1 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketHostAllowlistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketHostAllowlistTest.java @@ -35,28 +35,24 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.concurrent.TimeUnit; import io.vertx.core.Vertx; import io.vertx.core.http.HttpClient; import io.vertx.core.http.HttpClientOptions; import io.vertx.core.http.HttpMethod; -import io.vertx.ext.unit.Async; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import org.junit.After; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; - -@RunWith(VertxUnitRunner.class) +import io.vertx.junit5.VertxExtension; +import io.vertx.junit5.VertxTestContext; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +@ExtendWith(VertxExtension.class) public class WebSocketHostAllowlistTest { - @ClassRule public static final TemporaryFolder folder = new TemporaryFolder(); - protected static Vertx vertx; - + private VertxTestContext testContext; private final List hostsAllowlist = Arrays.asList("ally", "friend"); private final WebSocketConfiguration webSocketConfiguration = @@ -67,10 +63,11 @@ public class WebSocketHostAllowlistTest { private static final int VERTX_AWAIT_TIMEOUT_MILLIS = 10000; private int websocketPort; - @Before + @BeforeEach public void initServerAndClient() { webSocketConfiguration.setPort(0); vertx = Vertx.vertx(); + testContext = new VertxTestContext(); final Map websocketMethods = new WebSocketMethodsFactory( @@ -99,7 +96,7 @@ public void initServerAndClient() { httpClient = vertx.createHttpClient(httpClientOptions); } - @After + @AfterEach public void after() { reset(webSocketMessageHandlerSpy); websocketService.stop(); @@ -112,8 +109,8 @@ public void websocketRequestWithDefaultHeaderAndDefaultConfigIsAccepted() { } @Test - public void httpRequestWithDefaultHeaderAndDefaultConfigIsAccepted(final TestContext context) { - doHttpRequestAndVerify(context, "localhost:50012", 400); + public void httpRequestWithDefaultHeaderAndDefaultConfigIsAccepted() throws InterruptedException { + doHttpRequestAndVerify(testContext, "localhost:50012", 400); } @Test @@ -122,8 +119,8 @@ public void websocketRequestWithEmptyHeaderAndDefaultConfigIsRejected() { } @Test - public void httpRequestWithEmptyHeaderAndDefaultConfigIsRejected(final TestContext context) { - doHttpRequestAndVerify(context, "", 403); + public void httpRequestWithEmptyHeaderAndDefaultConfigIsRejected() throws InterruptedException { + doHttpRequestAndVerify(testContext, "", 403); } @Test @@ -134,10 +131,10 @@ public void websocketRequestWithAnyHostnameAndWildcardConfigIsAccepted() { } @Test - public void httpRequestWithAnyHostnameAndWildcardConfigIsAccepted(final TestContext context) { + public void httpRequestWithAnyHostnameAndWildcardConfigIsAccepted() throws InterruptedException { webSocketConfiguration.setHostsAllowlist(Collections.singletonList("*")); - doHttpRequestAndVerify(context, "ally", 400); - doHttpRequestAndVerify(context, "foe", 400); + doHttpRequestAndVerify(testContext, "ally", 400); + doHttpRequestAndVerify(testContext, "foe", 400); } @Test @@ -149,11 +146,11 @@ public void websocketRequestWithAllowedHostIsAccepted() { } @Test - public void httpRequestWithAllowedHostIsAccepted(final TestContext context) { + public void httpRequestWithAllowedHostIsAccepted() throws InterruptedException { webSocketConfiguration.setHostsAllowlist(hostsAllowlist); - doHttpRequestAndVerify(context, "ally", 400); - doHttpRequestAndVerify(context, "ally:12345", 400); - doHttpRequestAndVerify(context, "friend", 400); + doHttpRequestAndVerify(testContext, "ally", 400); + doHttpRequestAndVerify(testContext, "ally:12345", 400); + doHttpRequestAndVerify(testContext, "friend", 400); } @Test @@ -163,9 +160,9 @@ public void websocketRequestWithUnknownHostIsRejected() { } @Test - public void httpRequestWithUnknownHostIsRejected(final TestContext context) { + public void httpRequestWithUnknownHostIsRejected() throws InterruptedException { webSocketConfiguration.setHostsAllowlist(hostsAllowlist); - doHttpRequestAndVerify(context, "foe", 403); + doHttpRequestAndVerify(testContext, "foe", 403); } @Test @@ -179,17 +176,17 @@ public void websocketRequestWithMalformedHostIsRejected() { } @Test - public void httpRequestWithMalformedHostIsRejected(final TestContext context) { + public void httpRequestWithMalformedHostIsRejected() throws InterruptedException { webSocketConfiguration.setAuthenticationEnabled(false); webSocketConfiguration.setHostsAllowlist(hostsAllowlist); - doHttpRequestAndVerify(context, "ally:friend", 400); - doHttpRequestAndVerify(context, "ally:123456", 403); - doHttpRequestAndVerify(context, "ally:friend:1234", 403); + doHttpRequestAndVerify(testContext, "ally:friend", 400); + doHttpRequestAndVerify(testContext, "ally:123456", 403); + doHttpRequestAndVerify(testContext, "ally:friend:1234", 403); } private void doHttpRequestAndVerify( - final TestContext context, final String hostname, final int expectedResponse) { - final Async async = context.async(); + final VertxTestContext testContext, final String hostname, final int expectedResponse) + throws InterruptedException { httpClient.request( HttpMethod.POST, @@ -204,9 +201,9 @@ private void doHttpRequestAndVerify( .send( response -> { assertThat(response.result().statusCode()).isEqualTo(expectedResponse); - async.complete(); + testContext.completeNow(); }); }); - async.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketMessageHandlerTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketMessageHandlerTest.java index 5cfa997e465..3fcd20324ee 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketMessageHandlerTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketMessageHandlerTest.java @@ -28,9 +28,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.methods.WebSocketRpcRequest; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; @@ -39,40 +39,42 @@ import java.util.Map; import java.util.Optional; import java.util.UUID; +import java.util.concurrent.TimeUnit; import io.vertx.core.Future; import io.vertx.core.Vertx; +import io.vertx.core.VertxOptions; import io.vertx.core.buffer.Buffer; import io.vertx.core.http.ServerWebSocket; import io.vertx.core.http.WebSocketFrame; import io.vertx.core.json.Json; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; -import io.vertx.ext.unit.Async; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import io.vertx.junit5.VertxExtension; +import io.vertx.junit5.VertxTestContext; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentMatcher; import org.mockito.Mockito; import org.mockito.stubbing.Answer; -@RunWith(VertxUnitRunner.class) +@ExtendWith(VertxExtension.class) public class WebSocketMessageHandlerTest { private static final int VERTX_AWAIT_TIMEOUT_MILLIS = 10000; - private Vertx vertx; + private VertxTestContext testContext; private WebSocketMessageHandler handler; private JsonRpcMethod jsonRpcMethodMock; private ServerWebSocket websocketMock; private final Map methods = new HashMap<>(); - @Before - public void before(final TestContext context) { - vertx = Vertx.vertx(); + @BeforeEach + public void before() { + vertx = Vertx.vertx(new VertxOptions().setPreferNativeTransport(true)); + testContext = new VertxTestContext(); jsonRpcMethodMock = mock(JsonRpcMethod.class); websocketMock = mock(ServerWebSocket.class); @@ -88,16 +90,14 @@ public void before(final TestContext context) { TimeoutOptions.defaultOptions().getTimeoutSeconds()); } - @After - public void after(final TestContext context) { + @AfterEach + public void after() throws Throwable { Mockito.reset(jsonRpcMethodMock); Mockito.reset(websocketMock); - vertx.close(context.asyncAssertSuccess()); } @Test - public void handlerDeliversResponseSuccessfully(final TestContext context) { - final Async async = context.async(); + public void handlerDeliversResponseSuccessfully() throws InterruptedException { final JsonObject requestJson = new JsonObject().put("id", 1).put("method", "eth_x"); final JsonRpcRequest requestBody = requestJson.mapTo(WebSocketRpcRequest.class); @@ -108,11 +108,13 @@ public void handlerDeliversResponseSuccessfully(final TestContext context) { when(jsonRpcMethodMock.response(eq(expectedRequest))).thenReturn(expectedResponse); - when(websocketMock.writeFrame(argThat(this::isFinalFrame))).then(completeOnLastFrame(async)); + when(websocketMock.writeFrame(argThat(this::isFinalFrame))) + .then(completeOnLastFrame(testContext)); handler.handle(websocketMock, requestJson.toBuffer(), Optional.empty()); - async.awaitSuccess(WebSocketMessageHandlerTest.VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion( + WebSocketMessageHandlerTest.VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); // can verify only after async not before verify(websocketMock).writeFrame(argThat(isFrameWithText(Json.encode(expectedResponse)))); @@ -121,8 +123,7 @@ public void handlerDeliversResponseSuccessfully(final TestContext context) { } @Test - public void handlerBatchRequestDeliversResponseSuccessfully(final TestContext context) { - final Async async = context.async(); + public void handlerBatchRequestDeliversResponseSuccessfully() throws InterruptedException { final JsonObject requestJson = new JsonObject().put("id", 1).put("method", "eth_x"); final JsonArray arrayJson = new JsonArray(List.of(requestJson, requestJson)); @@ -136,11 +137,13 @@ public void handlerBatchRequestDeliversResponseSuccessfully(final TestContext co when(jsonRpcMethodMock.response(eq(expectedRequest))).thenReturn(expectedSingleResponse); - when(websocketMock.writeFrame(argThat(this::isFinalFrame))).then(completeOnLastFrame(async)); + when(websocketMock.writeFrame(argThat(this::isFinalFrame))) + .then(completeOnLastFrame(testContext)); handler.handle(websocketMock, arrayJson.toBuffer(), Optional.empty()); - async.awaitSuccess(WebSocketMessageHandlerTest.VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion( + WebSocketMessageHandlerTest.VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); // can verify only after async not before verify(websocketMock).writeFrame(argThat(isFrameWithText(Json.encode(expectedBatchResponse)))); verify(websocketMock).writeFrame(argThat(this::isFinalFrame)); @@ -148,8 +151,8 @@ public void handlerBatchRequestDeliversResponseSuccessfully(final TestContext co } @Test - public void handlerBatchRequestContainingErrorsShouldRespondWithBatchErrors( - final TestContext context) { + public void handlerBatchRequestContainingErrorsShouldRespondWithBatchErrors() + throws InterruptedException { ServerWebSocket websocketMock = mock(ServerWebSocket.class); when(websocketMock.textHandlerID()).thenReturn(UUID.randomUUID().toString()); @@ -161,23 +164,23 @@ public void handlerBatchRequestContainingErrorsShouldRespondWithBatchErrors( mock(EthScheduler.class), TimeoutOptions.defaultOptions().getTimeoutSeconds()); - final Async async = context.async(); - final JsonObject requestJson = new JsonObject().put("id", 1).put("method", "eth_nonexistentMethod"); final JsonRpcErrorResponse expectedErrorResponse1 = - new JsonRpcErrorResponse(1, JsonRpcError.METHOD_NOT_FOUND); + new JsonRpcErrorResponse(1, RpcErrorType.METHOD_NOT_FOUND); final JsonArray arrayJson = new JsonArray(List.of(requestJson, requestJson)); final JsonArray expectedBatchResponse = new JsonArray(List.of(expectedErrorResponse1, expectedErrorResponse1)); - when(websocketMock.writeFrame(argThat(this::isFinalFrame))).then(completeOnLastFrame(async)); + when(websocketMock.writeFrame(argThat(this::isFinalFrame))) + .then(completeOnLastFrame(testContext)); handleBadCalls.handle(websocketMock, arrayJson.toBuffer(), Optional.empty()); - async.awaitSuccess(WebSocketMessageHandlerTest.VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion( + WebSocketMessageHandlerTest.VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); // can verify only after async not before verify(websocketMock).writeFrame(argThat(isFrameWithText(Json.encode(expectedBatchResponse)))); @@ -186,17 +189,18 @@ public void handlerBatchRequestContainingErrorsShouldRespondWithBatchErrors( } @Test - public void jsonDecodeFailureShouldRespondInvalidRequest(final TestContext context) { - final Async async = context.async(); + public void jsonDecodeFailureShouldRespondInvalidRequest() throws InterruptedException { final JsonRpcErrorResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.INVALID_REQUEST); + new JsonRpcErrorResponse(null, RpcErrorType.INVALID_REQUEST); - when(websocketMock.writeFrame(argThat(this::isFinalFrame))).then(completeOnLastFrame(async)); + when(websocketMock.writeFrame(argThat(this::isFinalFrame))) + .then(completeOnLastFrame(testContext)); handler.handle(websocketMock, Buffer.buffer(), Optional.empty()); - async.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion( + WebSocketMessageHandlerTest.VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); // can verify only after async not before verify(websocketMock).writeFrame(argThat(isFrameWithText(Json.encode(expectedResponse)))); @@ -205,17 +209,18 @@ public void jsonDecodeFailureShouldRespondInvalidRequest(final TestContext conte } @Test - public void objectMapperFailureShouldRespondInvalidRequest(final TestContext context) { - final Async async = context.async(); + public void objectMapperFailureShouldRespondInvalidRequest() throws InterruptedException { final JsonRpcErrorResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.INVALID_REQUEST); + new JsonRpcErrorResponse(null, RpcErrorType.INVALID_REQUEST); - when(websocketMock.writeFrame(argThat(this::isFinalFrame))).then(completeOnLastFrame(async)); + when(websocketMock.writeFrame(argThat(this::isFinalFrame))) + .then(completeOnLastFrame(testContext)); handler.handle(websocketMock, new JsonObject().toBuffer(), Optional.empty()); - async.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion( + WebSocketMessageHandlerTest.VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); // can verify only after async not before verify(websocketMock).writeFrame(argThat(isFrameWithText(Json.encode(expectedResponse)))); @@ -224,19 +229,20 @@ public void objectMapperFailureShouldRespondInvalidRequest(final TestContext con } @Test - public void absentMethodShouldRespondMethodNotFound(final TestContext context) { - final Async async = context.async(); + public void absentMethodShouldRespondMethodNotFound() throws InterruptedException { final JsonObject requestJson = new JsonObject().put("id", 1).put("method", "eth_nonexistentMethod"); final JsonRpcErrorResponse expectedResponse = - new JsonRpcErrorResponse(1, JsonRpcError.METHOD_NOT_FOUND); + new JsonRpcErrorResponse(1, RpcErrorType.METHOD_NOT_FOUND); - when(websocketMock.writeFrame(argThat(this::isFinalFrame))).then(completeOnLastFrame(async)); + when(websocketMock.writeFrame(argThat(this::isFinalFrame))) + .then(completeOnLastFrame(testContext)); handler.handle(websocketMock, requestJson.toBuffer(), Optional.empty()); - async.awaitSuccess(WebSocketMessageHandlerTest.VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion( + WebSocketMessageHandlerTest.VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); verify(websocketMock).writeFrame(argThat(isFrameWithText(Json.encode(expectedResponse)))); verify(websocketMock).writeFrame(argThat(this::isFinalFrame)); @@ -244,9 +250,8 @@ public void absentMethodShouldRespondMethodNotFound(final TestContext context) { } @Test - public void onInvalidJsonRpcParametersExceptionProcessingRequestShouldRespondInvalidParams( - final TestContext context) { - final Async async = context.async(); + public void onInvalidJsonRpcParametersExceptionProcessingRequestShouldRespondInvalidParams() + throws InterruptedException { final JsonObject requestJson = new JsonObject().put("id", 1).put("method", "eth_x"); final JsonRpcRequestContext expectedRequest = @@ -254,13 +259,15 @@ public void onInvalidJsonRpcParametersExceptionProcessingRequestShouldRespondInv when(jsonRpcMethodMock.response(eq(expectedRequest))) .thenThrow(new InvalidJsonRpcParameters("")); final JsonRpcErrorResponse expectedResponse = - new JsonRpcErrorResponse(1, JsonRpcError.INVALID_PARAMS); + new JsonRpcErrorResponse(1, RpcErrorType.INVALID_PARAMS); - when(websocketMock.writeFrame(argThat(this::isFinalFrame))).then(completeOnLastFrame(async)); + when(websocketMock.writeFrame(argThat(this::isFinalFrame))) + .then(completeOnLastFrame(testContext)); handler.handle(websocketMock, requestJson.toBuffer(), Optional.empty()); - async.awaitSuccess(WebSocketMessageHandlerTest.VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion( + WebSocketMessageHandlerTest.VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); // can verify only after async not before verify(websocketMock).writeFrame(argThat(isFrameWithText(Json.encode(expectedResponse)))); @@ -268,21 +275,22 @@ public void onInvalidJsonRpcParametersExceptionProcessingRequestShouldRespondInv } @Test - public void onExceptionProcessingRequestShouldRespondInternalError(final TestContext context) { - final Async async = context.async(); + public void onExceptionProcessingRequestShouldRespondInternalError() throws InterruptedException { final JsonObject requestJson = new JsonObject().put("id", 1).put("method", "eth_x"); final JsonRpcRequestContext expectedRequest = new JsonRpcRequestContext(requestJson.mapTo(WebSocketRpcRequest.class)); when(jsonRpcMethodMock.response(eq(expectedRequest))).thenThrow(new RuntimeException()); final JsonRpcErrorResponse expectedResponse = - new JsonRpcErrorResponse(1, JsonRpcError.INTERNAL_ERROR); + new JsonRpcErrorResponse(1, RpcErrorType.INTERNAL_ERROR); - when(websocketMock.writeFrame(argThat(this::isFinalFrame))).then(completeOnLastFrame(async)); + when(websocketMock.writeFrame(argThat(this::isFinalFrame))) + .then(completeOnLastFrame(testContext)); handler.handle(websocketMock, requestJson.toBuffer(), Optional.empty()); - async.awaitSuccess(WebSocketMessageHandlerTest.VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion( + WebSocketMessageHandlerTest.VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); // can verify only after async not before verify(websocketMock).writeFrame(argThat(isFrameWithText(Json.encode(expectedResponse)))); @@ -297,9 +305,9 @@ private boolean isFinalFrame(final WebSocketFrame frame) { return frame.isFinal(); } - private Answer> completeOnLastFrame(final Async async) { + private Answer> completeOnLastFrame(final VertxTestContext testContext) { return invocation -> { - async.complete(); + testContext.completeNow(); return Future.succeededFuture(); }; } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java index 4b9dc5e384a..622dd3c1197 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java @@ -18,6 +18,7 @@ import static java.util.concurrent.TimeUnit.MINUTES; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.util.Lists.list; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; @@ -55,6 +56,7 @@ import java.math.BigInteger; import java.net.URISyntaxException; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; @@ -67,6 +69,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.TimeUnit; import com.google.common.base.Splitter; import com.google.common.collect.Lists; @@ -85,26 +88,25 @@ import io.vertx.ext.auth.JWTOptions; import io.vertx.ext.auth.User; import io.vertx.ext.auth.jwt.JWTAuth; -import io.vertx.ext.unit.Async; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.junit5.VertxExtension; +import io.vertx.junit5.VertxTestContext; import okhttp3.MediaType; import okhttp3.OkHttpClient; import org.assertj.core.api.Assertions; -import org.junit.After; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; - -@RunWith(VertxUnitRunner.class) +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; + +@ExtendWith(VertxExtension.class) public class WebSocketServiceLoginTest { private static final int VERTX_AWAIT_TIMEOUT_MILLIS = 10000; - @ClassRule public static final TemporaryFolder folder = new TemporaryFolder(); + @TempDir private Path folder; private Vertx vertx; + private VertxTestContext testContext; protected static Map rpcMethods; protected static JsonRpcHttpService service; protected static OkHttpClient client; @@ -127,9 +129,10 @@ public class WebSocketServiceLoginTest { private WebSocketService websocketService; private HttpClient httpClient; - @Before + @BeforeEach public void before() throws URISyntaxException { vertx = Vertx.vertx(); + testContext = new VertxTestContext(); final String authTomlPath = Paths.get(ClassLoader.getSystemResource("JsonRpcHttpService/auth.toml").toURI()) @@ -183,7 +186,7 @@ public void before() throws URISyntaxException { mock(MetricsConfiguration.class), natService, new HashMap<>(), - folder.getRoot().toPath(), + folder, mock(EthPeers.class), vertx, Optional.empty(), @@ -219,15 +222,14 @@ public void before() throws URISyntaxException { httpClient = vertx.createHttpClient(httpClientOptions); } - @After + @AfterEach public void after() { reset(webSocketMessageHandlerSpy); websocketService.stop(); } @Test - public void loginWithBadCredentials(final TestContext context) { - final Async async = context.async(); + public void loginWithBadCredentials() throws InterruptedException { httpClient.request( HttpMethod.POST, websocketConfiguration.getPort(), @@ -242,16 +244,15 @@ public void loginWithBadCredentials(final TestContext context) { response -> { assertThat(response.result().statusCode()).isEqualTo(401); assertThat(response.result().statusMessage()).isEqualTo("Unauthorized"); - async.complete(); + testContext.completeNow(); }); }); - async.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } @Test - public void loginWithGoodCredentials(final TestContext context) { - final Async async = context.async(); + public void loginWithGoodCredentials() throws InterruptedException { Handler> responseHandler = response -> { assertThat(response.result().statusCode()).isEqualTo(200); @@ -296,7 +297,7 @@ public void loginWithGoodCredentials(final TestContext context) { (authed) -> { assertThat(authed.succeeded()).isTrue(); assertThat(authed.result()).isTrue(); - async.complete(); + testContext.completeNow(); }); }); }); @@ -314,12 +315,11 @@ public void loginWithGoodCredentials(final TestContext context) { "/login", requestHandler); - async.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } @Test - public void websocketServiceWithBadHeaderAuthenticationToken(final TestContext context) { - final Async async = context.async(); + public void websocketServiceWithBadHeaderAuthenticationToken() throws InterruptedException { final String request = "{\"id\": 1, \"method\": \"eth_subscribe\", \"params\": [\"syncing\"]}"; final String expectedResponse = @@ -339,18 +339,19 @@ public void websocketServiceWithBadHeaderAuthenticationToken(final TestContext c webSocket .result() .handler( - buffer -> { - context.assertEquals(expectedResponse, buffer.toString()); - async.complete(); - }); + buffer -> + testContext.verify( + () -> { + assertEquals(expectedResponse, buffer.toString()); + testContext.completeNow(); + })); }); - async.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } @Test - public void netServicesSucceedWithNoAuth(final TestContext context) { - final Async async = context.async(); + public void netServicesSucceedWithNoAuth() throws InterruptedException { final String id = "123"; final String request = @@ -370,18 +371,19 @@ public void netServicesSucceedWithNoAuth(final TestContext context) { webSocket .result() .handler( - buffer -> { - context.assertEquals(expectedResponse, buffer.toString()); - async.complete(); - }); + buffer -> + testContext.verify( + () -> { + assertEquals(expectedResponse, buffer.toString()); + testContext.completeNow(); + })); }); - async.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } @Test - public void websocketServiceWithGoodHeaderAuthenticationToken(final TestContext context) { - final Async async = context.async(); + public void websocketServiceWithGoodHeaderAuthenticationToken() throws InterruptedException { final JWTOptions jwtOptions = new JWTOptions().setExpiresInMinutes(5).setAlgorithm("RS256"); @@ -408,18 +410,19 @@ public void websocketServiceWithGoodHeaderAuthenticationToken(final TestContext webSocket .result() .handler( - buffer -> { - context.assertEquals(expectedResponse, buffer.toString()); - async.complete(); - }); + buffer -> + testContext.verify( + () -> { + assertEquals(expectedResponse, buffer.toString()); + testContext.completeNow(); + })); }); - async.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } @Test - public void loginPopulatesJWTPayloadWithRequiredValues(final TestContext context) { - final Async async = context.async(); + public void loginPopulatesJWTPayloadWithRequiredValues() throws InterruptedException { httpClient.request( HttpMethod.POST, websocketConfiguration.getPort(), @@ -462,12 +465,12 @@ public void loginPopulatesJWTPayloadWithRequiredValues(final TestContext context jwtPayload.getLong("exp") - jwtPayload.getLong("iat"); assertThat(tokenExpiry).isEqualTo(MINUTES.toSeconds(5)); - async.complete(); + testContext.completeNow(); }); }); }); - async.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } private JsonObject decodeJwtPayload(final String token) { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceTest.java index 6f26c513266..94c543332bb 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceTest.java @@ -15,6 +15,9 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.websocket; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; @@ -34,6 +37,8 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; @@ -43,20 +48,20 @@ import io.vertx.core.http.WebSocket; import io.vertx.core.http.WebSocketFrame; import io.vertx.core.json.JsonObject; -import io.vertx.ext.unit.Async; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(VertxUnitRunner.class) +import io.vertx.junit5.VertxExtension; +import io.vertx.junit5.VertxTestContext; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +@ExtendWith(VertxExtension.class) public class WebSocketServiceTest { private static final int VERTX_AWAIT_TIMEOUT_MILLIS = 10000; private Vertx vertx; + private VertxTestContext testContext; private WebSocketConfiguration websocketConfiguration; private WebSocketMessageHandler webSocketMessageHandlerSpy; private Map websocketMethods; @@ -65,9 +70,10 @@ public class WebSocketServiceTest { private final int maxConnections = 3; private final int maxFrameSize = 1024 * 1024; - @Before + @BeforeEach public void before() { vertx = Vertx.vertx(); + testContext = new VertxTestContext(); websocketConfiguration = WebSocketConfiguration.createDefault(); websocketConfiguration.setPort(0); @@ -102,19 +108,19 @@ public void before() { httpClient = vertx.createHttpClient(httpClientOptions); } - @After + @AfterEach public void after() { reset(webSocketMessageHandlerSpy); websocketService.stop(); } @Test - public void limitActiveConnections(final TestContext context) { + public void limitActiveConnections() throws InterruptedException { // expecting maxConnections successful responses - final Async asyncResponse = context.async(maxConnections); + final CountDownLatch successLatch = new CountDownLatch(maxConnections); // and a number of rejections final int countRejections = 2; - final Async asyncRejected = context.async(countRejections); + final CountDownLatch rejectionLatch = new CountDownLatch(countRejections); final String request = "{\"id\": 1, \"method\": \"eth_subscribe\", \"params\": [\"syncing\"]}"; // the number in the response is the subscription ID, so in successive responses this increments @@ -129,27 +135,25 @@ public void limitActiveConnections(final TestContext context) { WebSocket ws = future.result(); ws.handler( buffer -> { - context.assertNotNull(buffer.toString()); + assertNotNull(buffer.toString()); // assert a successful response - context.assertTrue( - buffer.toString().startsWith(expectedResponse1.substring(0, 36))); - asyncResponse.countDown(); + assertTrue(buffer.toString().startsWith(expectedResponse1.substring(0, 36))); + successLatch.countDown(); }); ws.writeTextMessage(request); } else { // count down the rejected WS connections - asyncRejected.countDown(); + rejectionLatch.countDown(); } }); } // wait for successful responses AND rejected connections - asyncResponse.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); - asyncRejected.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); + successLatch.await(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); + rejectionLatch.await(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } @Test - public void websocketServiceExecutesHandlerOnMessage(final TestContext context) { - final Async async = context.async(); + public void websocketServiceExecutesHandlerOnMessage() throws InterruptedException { final String request = "{\"id\": 1, \"method\": \"eth_subscribe\", \"params\": [\"syncing\"]}"; final String expectedResponse = "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":\"0x1\"}"; @@ -160,23 +164,24 @@ public void websocketServiceExecutesHandlerOnMessage(final TestContext context) if (future.succeeded()) { WebSocket ws = future.result(); ws.handler( - buffer -> { - context.assertEquals(expectedResponse, buffer.toString()); - async.complete(); - }); + buffer -> + testContext.verify( + () -> { + assertEquals(expectedResponse, buffer.toString()); + testContext.completeNow(); + })); ws.writeTextMessage(request); } else { - context.fail("websocket connection failed"); + testContext.failNow("websocket connection failed"); } }); - async.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } @Test - public void websocketServiceHandlesBinaryFrames(final TestContext context) { - final Async async = context.async(); + public void websocketServiceHandlesBinaryFrames() throws InterruptedException { httpClient.webSocket( "/", @@ -187,28 +192,27 @@ public void websocketServiceHandlesBinaryFrames(final TestContext context) { ws.handler( // we don't really care what the response is buffer -> { - async.complete(); + testContext.completeNow(); }); ws.writeFinalBinaryFrame(Buffer.buffer(requestJson.toString())); } else { - context.fail("websocket connection failed"); + testContext.failNow("websocket connection failed"); } }); - async.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } @Test - public void websocketServiceRemoveSubscriptionOnConnectionClose(final TestContext context) { - final Async async = context.async(); + public void websocketServiceRemoveSubscriptionOnConnectionClose() throws InterruptedException { vertx .eventBus() .consumer(SubscriptionManager.EVENTBUS_REMOVE_SUBSCRIPTIONS_ADDRESS) .handler( m -> { - context.assertNotNull(m.body()); - async.complete(); + assertNotNull(m.body()); + testContext.completeNow(); }) .completionHandler( v -> @@ -218,12 +222,11 @@ public void websocketServiceRemoveSubscriptionOnConnectionClose(final TestContex websocket.result().close(); })); - async.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } @Test - public void websocketServiceCloseConnectionOnUnrecoverableError(final TestContext context) { - final Async async = context.async(); + public void websocketServiceCloseConnectionOnUnrecoverableError() throws InterruptedException { final byte[] bigMessage = new byte[maxFrameSize + 1]; Arrays.fill(bigMessage, (byte) 1); @@ -234,19 +237,18 @@ public void websocketServiceCloseConnectionOnUnrecoverableError(final TestContex if (future.succeeded()) { WebSocket ws = future.result(); ws.write(Buffer.buffer(bigMessage)); - ws.closeHandler(v -> async.complete()); + ws.closeHandler(v -> testContext.completeNow()); } else { - context.fail("websocket connection failed"); + testContext.failNow("websocket connection failed"); } }); - async.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } @SuppressWarnings("deprecation") // No alternative available in vertx 3. @Test - public void websocketServiceMustReturnErrorOnHttpRequest(final TestContext context) { - final Async async = context.async(); + public void websocketServiceMustReturnErrorOnHttpRequest() throws InterruptedException { httpClient.request( HttpMethod.POST, @@ -262,15 +264,13 @@ public void websocketServiceMustReturnErrorOnHttpRequest(final TestContext conte .result() .bodyHandler( b -> { - context - .assertEquals(400, response.result().statusCode()) - .assertEquals( - "Websocket endpoint can't handle HTTP requests", - b.toString()); - async.complete(); + assertEquals(400, response.result().statusCode()); + assertEquals( + "Websocket endpoint can't handle HTTP requests", b.toString()); + testContext.completeNow(); })); }); - async.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } @Test @@ -295,8 +295,7 @@ public void handleLoginRequestWithAuthDisabled() { } @Test - public void webSocketDoesNotHandlePingPayloadAsJsonRpcRequest(final TestContext context) { - final Async async = context.async(); + public void webSocketDoesNotHandlePingPayloadAsJsonRpcRequest() throws InterruptedException { httpClient.webSocket( "/", @@ -307,26 +306,26 @@ public void webSocketDoesNotHandlePingPayloadAsJsonRpcRequest(final TestContext buffer -> { final String payload = buffer.toString(); if (!payload.equals("foo")) { - context.fail("Only expected PONG response with same payload as PING request"); + testContext.failNow( + "Only expected PONG response with same payload as PING request"); } }); websocket.closeHandler( h -> { verifyNoInteractions(webSocketMessageHandlerSpy); - async.complete(); + testContext.completeNow(); }); websocket.writeFrame(WebSocketFrame.pingFrame(Buffer.buffer("foo"))); websocket.close(); }); - async.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } @Test - public void handleResponseWithOptionalEmptyValue(final TestContext context) { - final Async async = context.async(); + public void handleResponseWithOptionalEmptyValue() throws InterruptedException { final JsonRpcMethod method = TestJsonRpcMethodsUtil.optionalEmptyResponse(); websocketMethods.put(method.getName(), method); @@ -341,23 +340,22 @@ public void handleResponseWithOptionalEmptyValue(final TestContext context) { WebSocket ws = future.result(); ws.handler( buffer -> { - context.assertEquals(expectedResponse, buffer.toString()); - async.complete(); + assertEquals(expectedResponse, buffer.toString()); + testContext.completeNow(); }); ws.writeTextMessage(request); } else { - context.fail("websocket connection failed"); + testContext.failNow("websocket connection failed"); } }); - async.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); - async.handler((result) -> websocketMethods.remove(method.getName())); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); + testContext.verify(() -> websocketMethods.remove(method.getName())); } @Test - public void handleResponseWithOptionalExistingValue(final TestContext context) { - final Async async = context.async(); + public void handleResponseWithOptionalExistingValue() throws InterruptedException { final JsonRpcMethod method = TestJsonRpcMethodsUtil.optionalResponseWithValue("foo"); websocketMethods.put(method.getName(), method); @@ -372,17 +370,17 @@ public void handleResponseWithOptionalExistingValue(final TestContext context) { WebSocket ws = future.result(); ws.handler( buffer -> { - context.assertEquals(expectedResponse, buffer.toString()); - async.complete(); + assertEquals(expectedResponse, buffer.toString()); + testContext.completeNow(); }); ws.writeTextMessage(request); } else { - context.fail("websocket connection failed"); + testContext.failNow("websocket connection failed"); } }); - async.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); - async.handler((result) -> websocketMethods.remove(method.getName())); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); + testContext.verify(() -> websocketMethods.remove(method.getName())); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthSubscribeIntegrationTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthSubscribeIntegrationTest.java index e4656c1d2e6..086ea8aea77 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthSubscribeIntegrationTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthSubscribeIntegrationTest.java @@ -36,6 +36,8 @@ import java.util.HashMap; import java.util.List; import java.util.Optional; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -44,20 +46,20 @@ import io.vertx.core.http.ServerWebSocket; import io.vertx.core.http.WebSocketFrame; import io.vertx.core.json.Json; -import io.vertx.ext.unit.Async; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import io.vertx.junit5.VertxExtension; +import io.vertx.junit5.VertxTestContext; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentMatcher; import org.mockito.Mockito; import org.mockito.stubbing.Answer; -@RunWith(VertxUnitRunner.class) +@ExtendWith(VertxExtension.class) public class EthSubscribeIntegrationTest { private Vertx vertx; + private VertxTestContext testContext; private WebSocketMessageHandler webSocketMessageHandler; private SubscriptionManager subscriptionManager; private WebSocketMethodsFactory webSocketMethodsFactory; @@ -65,9 +67,10 @@ public class EthSubscribeIntegrationTest { private final String CONNECTION_ID_1 = "test-connection-id-1"; private final String CONNECTION_ID_2 = "test-connection-id-2"; - @Before + @BeforeEach public void before() { vertx = Vertx.vertx(); + testContext = new VertxTestContext(); subscriptionManager = new SubscriptionManager(new NoOpMetricsSystem()); webSocketMethodsFactory = new WebSocketMethodsFactory(subscriptionManager, new HashMap<>()); webSocketMessageHandler = @@ -79,8 +82,7 @@ public void before() { } @Test - public void shouldAddConnectionToMap(final TestContext context) { - final Async async = context.async(); + public void shouldAddConnectionToMap() throws InterruptedException { final JsonRpcRequest subscribeRequestBody = createEthSubscribeRequestBody(CONNECTION_ID_1); @@ -90,12 +92,12 @@ public void shouldAddConnectionToMap(final TestContext context) { final ServerWebSocket websocketMock = mock(ServerWebSocket.class); when(websocketMock.textHandlerID()).thenReturn(CONNECTION_ID_1); when(websocketMock.writeFrame(argThat(this::isFinalFrame))) - .then(completeOnLastFrame(async, websocketMock)); + .then(completeOnLastFrame(testContext, websocketMock)); webSocketMessageHandler.handle( websocketMock, Json.encodeToBuffer(subscribeRequestBody), Optional.empty()); - async.awaitSuccess(ASYNC_TIMEOUT); + testContext.awaitCompletion(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS); final List syncingSubscriptions = getSubscriptions(); assertThat(syncingSubscriptions).hasSize(1); @@ -105,8 +107,8 @@ public void shouldAddConnectionToMap(final TestContext context) { } @Test - public void shouldAddMultipleConnectionsToMap(final TestContext context) { - final Async async = context.async(2); + public void shouldAddMultipleConnectionsToMap() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(2); final JsonRpcRequest subscribeRequestBody1 = createEthSubscribeRequestBody(CONNECTION_ID_1); final JsonRpcRequest subscribeRequestBody2 = createEthSubscribeRequestBody(CONNECTION_ID_2); @@ -118,18 +120,18 @@ public void shouldAddMultipleConnectionsToMap(final TestContext context) { final ServerWebSocket websocketMock1 = mock(ServerWebSocket.class); when(websocketMock1.textHandlerID()).thenReturn(CONNECTION_ID_1); - when(websocketMock1.writeFrame(argThat(this::isFinalFrame))).then(countDownOnLastFrame(async)); + when(websocketMock1.writeFrame(argThat(this::isFinalFrame))).then(countDownOnLastFrame(latch)); final ServerWebSocket websocketMock2 = mock(ServerWebSocket.class); when(websocketMock2.textHandlerID()).thenReturn(CONNECTION_ID_2); - when(websocketMock2.writeFrame(argThat(this::isFinalFrame))).then(countDownOnLastFrame(async)); + when(websocketMock2.writeFrame(argThat(this::isFinalFrame))).then(countDownOnLastFrame(latch)); webSocketMessageHandler.handle( websocketMock1, Json.encodeToBuffer(subscribeRequestBody1), Optional.empty()); webSocketMessageHandler.handle( websocketMock2, Json.encodeToBuffer(subscribeRequestBody2), Optional.empty()); - async.awaitSuccess(ASYNC_TIMEOUT); + latch.await(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS); final List updatedSubscriptions = getSubscriptions(); assertThat(updatedSubscriptions).hasSize(2); @@ -176,16 +178,16 @@ private boolean isFinalFrame(final WebSocketFrame frame) { } private Answer completeOnLastFrame( - final Async async, final ServerWebSocket websocket) { + final VertxTestContext testContext, final ServerWebSocket websocket) { return invocation -> { - async.complete(); + testContext.completeNow(); return websocket; }; } - private Answer> countDownOnLastFrame(final Async async) { + private Answer> countDownOnLastFrame(final CountDownLatch latch) { return invocation -> { - async.countDown(); + latch.countDown(); return Future.succeededFuture(); }; } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthSubscribeTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthSubscribeTest.java index 8975d4c1a26..7d1450dbc9a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthSubscribeTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthSubscribeTest.java @@ -21,9 +21,9 @@ import static org.mockito.Mockito.when; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionManager; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request.InvalidSubscriptionRequestException; @@ -32,8 +32,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request.SubscriptionType; import io.vertx.core.json.Json; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class EthSubscribeTest { @@ -41,7 +41,7 @@ public class EthSubscribeTest { private SubscriptionManager subscriptionManagerMock; private SubscriptionRequestMapper mapperMock; - @Before + @BeforeEach public void before() { subscriptionManagerMock = mock(SubscriptionManager.class); mapperMock = mock(SubscriptionRequestMapper.class); @@ -82,7 +82,7 @@ public void invalidSubscribeRequestRespondsInvalidRequestResponse() { final JsonRpcErrorResponse expectedResponse = new JsonRpcErrorResponse( - jsonRpcrequestContext.getRequest().getId(), JsonRpcError.INVALID_REQUEST); + jsonRpcrequestContext.getRequest().getId(), RpcErrorType.INVALID_REQUEST); assertThat(ethSubscribe.response(jsonRpcrequestContext)).isEqualTo(expectedResponse); } @@ -97,7 +97,7 @@ public void uncaughtErrorOnSubscriptionManagerShouldRespondInternalErrorResponse final JsonRpcErrorResponse expectedResponse = new JsonRpcErrorResponse( - jsonRpcrequestContext.getRequest().getId(), JsonRpcError.INTERNAL_ERROR); + jsonRpcrequestContext.getRequest().getId(), RpcErrorType.INTERNAL_ERROR); assertThat(ethSubscribe.response(jsonRpcrequestContext)).isEqualTo(expectedResponse); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthUnsubscribeIntegrationTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthUnsubscribeIntegrationTest.java index ff8212d7b34..6aa6d727914 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthUnsubscribeIntegrationTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthUnsubscribeIntegrationTest.java @@ -34,34 +34,37 @@ import java.util.HashMap; import java.util.Optional; +import java.util.concurrent.TimeUnit; import io.vertx.core.Future; import io.vertx.core.Vertx; +import io.vertx.core.VertxOptions; import io.vertx.core.http.ServerWebSocket; import io.vertx.core.http.WebSocketFrame; import io.vertx.core.json.Json; -import io.vertx.ext.unit.Async; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import io.vertx.junit5.VertxExtension; +import io.vertx.junit5.VertxTestContext; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentMatcher; import org.mockito.stubbing.Answer; -@RunWith(VertxUnitRunner.class) +@ExtendWith(VertxExtension.class) public class EthUnsubscribeIntegrationTest { private Vertx vertx; + private VertxTestContext testContext; private WebSocketMessageHandler webSocketMessageHandler; private SubscriptionManager subscriptionManager; private WebSocketMethodsFactory webSocketMethodsFactory; private final int ASYNC_TIMEOUT = 5000; private final String CONNECTION_ID = "test-connection-id-1"; - @Before + @BeforeEach public void before() { - vertx = Vertx.vertx(); + vertx = Vertx.vertx(new VertxOptions().setPreferNativeTransport(true)); + testContext = new VertxTestContext(); subscriptionManager = new SubscriptionManager(new NoOpMetricsSystem()); webSocketMethodsFactory = new WebSocketMethodsFactory(subscriptionManager, new HashMap<>()); webSocketMessageHandler = @@ -73,8 +76,7 @@ public void before() { } @Test - public void shouldRemoveConnectionWithSingleSubscriptionFromMap(final TestContext context) { - final Async async = context.async(); + public void shouldRemoveConnectionWithSingleSubscriptionFromMap() throws InterruptedException { // Add the subscription we'd like to remove final SubscribeRequest subscribeRequest = @@ -90,20 +92,20 @@ public void shouldRemoveConnectionWithSingleSubscriptionFromMap(final TestContex final ServerWebSocket websocketMock = mock(ServerWebSocket.class); when(websocketMock.textHandlerID()).thenReturn(CONNECTION_ID); - when(websocketMock.writeFrame(argThat(this::isFinalFrame))).then(completeOnLastFrame(async)); + when(websocketMock.writeFrame(argThat(this::isFinalFrame))) + .then(completeOnLastFrame(testContext)); webSocketMessageHandler.handle( websocketMock, Json.encodeToBuffer(unsubscribeRequestBody), Optional.empty()); - async.awaitSuccess(ASYNC_TIMEOUT); + testContext.awaitCompletion(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS); assertThat(subscriptionManager.getSubscriptionById(subscriptionId)).isNull(); verify(websocketMock).writeFrame(argThat(isFrameWithText(Json.encode(expectedResponse)))); verify(websocketMock).writeFrame(argThat(this::isFinalFrame)); } @Test - public void shouldRemoveSubscriptionAndKeepConnection(final TestContext context) { - final Async async = context.async(); + public void shouldRemoveSubscriptionAndKeepConnection() throws InterruptedException { // Add the subscriptions we'd like to remove final SubscribeRequest subscribeRequest = @@ -122,12 +124,13 @@ public void shouldRemoveSubscriptionAndKeepConnection(final TestContext context) final ServerWebSocket websocketMock = mock(ServerWebSocket.class); when(websocketMock.textHandlerID()).thenReturn(CONNECTION_ID); - when(websocketMock.writeFrame(argThat(this::isFinalFrame))).then(completeOnLastFrame(async)); + when(websocketMock.writeFrame(argThat(this::isFinalFrame))) + .then(completeOnLastFrame(testContext)); webSocketMessageHandler.handle( websocketMock, Json.encodeToBuffer(unsubscribeRequestBody), Optional.empty()); - async.awaitSuccess(ASYNC_TIMEOUT); + testContext.awaitCompletion(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS); assertThat(subscriptionManager.getSubscriptionById(subscriptionId1)).isNotNull(); assertThat(subscriptionManager.getSubscriptionById(subscriptionId2)).isNull(); verify(websocketMock).writeFrame(argThat(isFrameWithText(Json.encode(expectedResponse)))); @@ -153,9 +156,9 @@ private boolean isFinalFrame(final WebSocketFrame frame) { return frame.isFinal(); } - private Answer> completeOnLastFrame(final Async async) { + private Answer> completeOnLastFrame(final VertxTestContext testContext) { return invocation -> { - async.complete(); + testContext.completeNow(); return Future.succeededFuture(); }; } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthUnsubscribeTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthUnsubscribeTest.java index a32985ee472..3a32111f6b7 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthUnsubscribeTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthUnsubscribeTest.java @@ -22,9 +22,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionManager; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionNotFoundException; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request.InvalidSubscriptionRequestException; @@ -32,8 +32,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request.UnsubscribeRequest; import io.vertx.core.json.Json; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class EthUnsubscribeTest { @@ -42,7 +42,7 @@ public class EthUnsubscribeTest { private SubscriptionRequestMapper mapperMock; private final String CONNECTION_ID = "test-connection-id"; - @Before + @BeforeEach public void before() { subscriptionManagerMock = mock(SubscriptionManager.class); mapperMock = mock(SubscriptionRequestMapper.class); @@ -74,7 +74,7 @@ public void invalidUnsubscribeRequestReturnsInvalidRequestResponse() { .thenThrow(new InvalidSubscriptionRequestException()); final JsonRpcErrorResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_REQUEST); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_REQUEST); assertThat(ethUnsubscribe.response(request)).isEqualTo(expectedResponse); } @@ -87,7 +87,7 @@ public void whenSubscriptionNotFoundReturnError() { .thenThrow(new SubscriptionNotFoundException(1L)); final JsonRpcErrorResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.SUBSCRIPTION_NOT_FOUND); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.SUBSCRIPTION_NOT_FOUND); assertThat(ethUnsubscribe.response(request)).isEqualTo(expectedResponse); } @@ -99,7 +99,7 @@ public void uncaughtErrorOnSubscriptionManagerReturnsInternalErrorResponse() { when(subscriptionManagerMock.unsubscribe(any())).thenThrow(new RuntimeException()); final JsonRpcErrorResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INTERNAL_ERROR); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INTERNAL_ERROR); assertThat(ethUnsubscribe.response(request)).isEqualTo(expectedResponse); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/PrivSubscribeTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/PrivSubscribeTest.java index 522650edb83..ddd6481b0ce 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/PrivSubscribeTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/PrivSubscribeTest.java @@ -22,10 +22,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionManager; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request.InvalidSubscriptionRequestException; @@ -36,13 +36,13 @@ import io.vertx.core.json.Json; import io.vertx.ext.auth.User; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PrivSubscribeTest { private final String ENCLAVE_KEY = "enclave_key"; @@ -55,7 +55,7 @@ public class PrivSubscribeTest { private PrivSubscribe privSubscribe; - @Before + @BeforeEach public void before() { privSubscribe = new PrivSubscribe( @@ -102,7 +102,7 @@ public void invalidSubscribeRequestRespondsInvalidRequestResponse() { final JsonRpcErrorResponse expectedResponse = new JsonRpcErrorResponse( - jsonRpcrequestContext.getRequest().getId(), JsonRpcError.INVALID_REQUEST); + jsonRpcrequestContext.getRequest().getId(), RpcErrorType.INVALID_REQUEST); assertThat(privSubscribe.response(jsonRpcrequestContext)).isEqualTo(expectedResponse); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/PrivUnsubscribeTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/PrivUnsubscribeTest.java index 9131032d2b3..784f6fc9f94 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/PrivUnsubscribeTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/PrivUnsubscribeTest.java @@ -23,9 +23,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionManager; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionNotFoundException; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request.InvalidSubscriptionRequestException; @@ -34,13 +34,13 @@ import org.hyperledger.besu.ethereum.privacy.PrivacyController; import io.vertx.core.json.Json; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PrivUnsubscribeTest { private final String PRIVACY_GROUP_ID = "B1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; @@ -53,7 +53,7 @@ public class PrivUnsubscribeTest { private PrivUnsubscribe privUnsubscribe; - @Before + @BeforeEach public void before() { privUnsubscribe = new PrivUnsubscribe( @@ -86,7 +86,7 @@ public void invalidUnsubscribeRequestReturnsInvalidRequestResponse() { .thenThrow(new InvalidSubscriptionRequestException()); final JsonRpcErrorResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_REQUEST); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.INVALID_REQUEST); assertThat(privUnsubscribe.response(request)).isEqualTo(expectedResponse); } @@ -100,7 +100,7 @@ public void whenSubscriptionNotFoundReturnError() { .thenThrow(new SubscriptionNotFoundException(1L)); final JsonRpcErrorResponse expectedResponse = - new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.SUBSCRIPTION_NOT_FOUND); + new JsonRpcErrorResponse(request.getRequest().getId(), RpcErrorType.SUBSCRIPTION_NOT_FOUND); assertThat(privUnsubscribe.response(request)).isEqualTo(expectedResponse); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/WebSocketMethodsFactoryTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/WebSocketMethodsFactoryTest.java index 5318f9bd727..5cfc06eca3b 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/WebSocketMethodsFactoryTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/WebSocketMethodsFactoryTest.java @@ -23,13 +23,13 @@ import java.util.HashMap; import java.util.Map; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class WebSocketMethodsFactoryTest { private WebSocketMethodsFactory factory; @@ -37,7 +37,7 @@ public class WebSocketMethodsFactoryTest { @Mock private SubscriptionManager subscriptionManager; private final Map jsonRpcMethods = new HashMap<>(); - @Before + @BeforeEach public void before() { jsonRpcMethods.put("eth_unsubscribe", jsonRpcMethod()); factory = new WebSocketMethodsFactory(subscriptionManager, jsonRpcMethods); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/SubscriptionBuilderTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/SubscriptionBuilderTest.java index c3a6b2c4b11..dd2a7d48333 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/SubscriptionBuilderTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/SubscriptionBuilderTest.java @@ -29,15 +29,15 @@ import java.util.function.Function; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class SubscriptionBuilderTest { private static final String CONNECTION_ID = "connectionId"; private SubscriptionBuilder subscriptionBuilder; - @Before + @BeforeEach public void before() { subscriptionBuilder = new SubscriptionBuilder(); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/SubscriptionManagerSendMessageTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/SubscriptionManagerSendMessageTest.java index 7f88a0e2598..1aca4121129 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/SubscriptionManagerSendMessageTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/SubscriptionManagerSendMessageTest.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription; -import static junit.framework.TestCase.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.JsonRpcResult; @@ -24,36 +24,39 @@ import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.util.UUID; +import java.util.concurrent.TimeUnit; import io.vertx.core.Vertx; import io.vertx.core.json.Json; -import io.vertx.ext.unit.Async; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(VertxUnitRunner.class) +import io.vertx.junit5.VertxExtension; +import io.vertx.junit5.VertxTestContext; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +@ExtendWith(VertxExtension.class) public class SubscriptionManagerSendMessageTest { private static final int VERTX_AWAIT_TIMEOUT_MILLIS = 10000; private Vertx vertx; + private VertxTestContext testContext; private SubscriptionManager subscriptionManager; - @Before - public void before(final TestContext context) { + @BeforeEach + public void before() { vertx = Vertx.vertx(); + testContext = new VertxTestContext(); subscriptionManager = new SubscriptionManager(new NoOpMetricsSystem()); - vertx.deployVerticle(subscriptionManager, context.asyncAssertSuccess()); + vertx.deployVerticle(subscriptionManager, testContext.succeedingThenComplete()); } @Test - @Ignore - public void shouldSendMessageOnTheConnectionIdEventBusAddressForExistingSubscription( - final TestContext context) { + @Disabled + public void shouldSendMessageOnTheConnectionIdEventBusAddressForExistingSubscription() + throws InterruptedException { final String connectionId = UUID.randomUUID().toString(); final SubscribeRequest subscribeRequest = new SubscribeRequest(SubscriptionType.SYNCING, null, null, connectionId); @@ -66,41 +69,37 @@ public void shouldSendMessageOnTheConnectionIdEventBusAddressForExistingSubscrip final Long subscriptionId = subscriptionManager.subscribe(subscribeRequest); - final Async async = context.async(); - vertx .eventBus() .consumer(connectionId) .handler( msg -> { - context.assertEquals(Json.encode(expectedResponse), msg.body()); - async.complete(); + assertEquals(Json.encode(expectedResponse), msg.body()); + testContext.completeNow(); }) .completionHandler(v -> subscriptionManager.sendMessage(subscriptionId, expectedResult)); - async.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } @Test - public void shouldNotSendMessageOnTheConnectionIdEventBusAddressForAbsentSubscription( - final TestContext context) { + public void shouldNotSendMessageOnTheConnectionIdEventBusAddressForAbsentSubscription() + throws InterruptedException { final String connectionId = UUID.randomUUID().toString(); - final Async async = context.async(); - vertx .eventBus() .consumer(connectionId) .handler( msg -> { - fail("Shouldn't receive message"); - async.complete(); + Assertions.fail("Shouldn't receive message"); + testContext.completeNow(); }) .completionHandler(v -> subscriptionManager.sendMessage(1L, mock(JsonRpcResult.class))); // if it doesn't receive the message in 5 seconds we assume it won't receive anymore - vertx.setPeriodic(5000, v -> async.complete()); + vertx.setPeriodic(5000, v -> testContext.completeNow()); - async.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); + testContext.awaitCompletion(VERTX_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/SubscriptionManagerTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/SubscriptionManagerTest.java index e4213003294..12c95bbb493 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/SubscriptionManagerTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/SubscriptionManagerTest.java @@ -33,15 +33,15 @@ import java.util.List; import java.util.UUID; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class SubscriptionManagerTest { private SubscriptionManager subscriptionManager; private final String CONNECTION_ID = "test-connection-id"; - @Before + @BeforeEach public void before() { subscriptionManager = new SubscriptionManager(new NoOpMetricsSystem()); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/blockheaders/NewBlockHeadersSubscriptionServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/blockheaders/NewBlockHeadersSubscriptionServiceTest.java index 0628cefadbf..4902eb31464 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/blockheaders/NewBlockHeadersSubscriptionServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/blockheaders/NewBlockHeadersSubscriptionServiceTest.java @@ -42,16 +42,16 @@ import java.util.List; import java.util.function.Consumer; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mockito; import org.mockito.Spy; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class NewBlockHeadersSubscriptionServiceTest { @Captor ArgumentCaptor subscriptionIdCaptor; @@ -76,7 +76,7 @@ public class NewBlockHeadersSubscriptionServiceTest { private final BlockchainQueries blockchainQueriesSpy = Mockito.spy(new BlockchainQueries(blockchain, createInMemoryWorldStateArchive())); - @Before + @BeforeEach public void before() { final NewBlockHeadersSubscriptionService newBlockHeadersSubscriptionService = new NewBlockHeadersSubscriptionService(subscriptionManagerSpy, blockchainQueriesSpy); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java index d940a5f8ce5..5746ecc10ef 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java @@ -54,14 +54,14 @@ import com.google.common.collect.Lists; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class LogsSubscriptionServiceTest { private final BlockDataGenerator gen = new BlockDataGenerator(1); @@ -75,7 +75,7 @@ public class LogsSubscriptionServiceTest { @Mock private PrivacyQueries privacyQueries; - @Before + @BeforeEach public void before() { logsSubscriptionService = new LogsSubscriptionService(subscriptionManager, Optional.of(privacyQueries)); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDroppedSubscriptionServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDroppedSubscriptionServiceTest.java index 98967114267..3b3faf58907 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDroppedSubscriptionServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDroppedSubscriptionServiceTest.java @@ -36,13 +36,13 @@ import java.util.Map; import java.util.stream.Collectors; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PendingTransactionDroppedSubscriptionServiceTest { private static final Hash TX_ONE = @@ -54,7 +54,7 @@ public class PendingTransactionDroppedSubscriptionServiceTest { private PendingTransactionDroppedSubscriptionService service; - @Before + @BeforeEach public void setUp() { service = new PendingTransactionDroppedSubscriptionService(subscriptionManager); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionSubscriptionServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionSubscriptionServiceTest.java index 0a96b8f4fa0..dd78168a2e5 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionSubscriptionServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionSubscriptionServiceTest.java @@ -36,13 +36,13 @@ import java.util.Map; import java.util.stream.Collectors; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PendingTransactionSubscriptionServiceTest { private static final Hash TX_ONE = @@ -54,7 +54,7 @@ public class PendingTransactionSubscriptionServiceTest { private PendingTransactionSubscriptionService service; - @Before + @BeforeEach public void setUp() { service = new PendingTransactionSubscriptionService(subscriptionManager); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/request/SubscriptionRequestMapperTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/request/SubscriptionRequestMapperTest.java index 5f46fd2ad59..d71b47421eb 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/request/SubscriptionRequestMapperTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/request/SubscriptionRequestMapperTest.java @@ -33,8 +33,8 @@ import java.util.stream.Stream; import io.vertx.core.json.Json; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class SubscriptionRequestMapperTest { @@ -43,7 +43,7 @@ public class SubscriptionRequestMapperTest { private final String CONNECTION_ID = null; private static final String ENCLAVE_PUBLIC_KEY = "enclave_public_key"; - @Before + @BeforeEach public void before() { mapper = new SubscriptionRequestMapper(); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/syncing/SyncingSubscriptionServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/syncing/SyncingSubscriptionServiceTest.java index 66f9a226ad4..6a055b7dd08 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/syncing/SyncingSubscriptionServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/syncing/SyncingSubscriptionServiceTest.java @@ -34,22 +34,22 @@ import java.util.Optional; import java.util.function.Consumer; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatchers; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class SyncingSubscriptionServiceTest { @Mock private SubscriptionManager subscriptionManager; @Mock private Synchronizer synchronizer; private SyncStatusListener syncStatusListener; - @Before + @BeforeEach public void before() { final ArgumentCaptor captor = ArgumentCaptor.forClass(SyncStatusListener.class); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BackendQueryTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BackendQueryTest.java index 9660edb85ff..20eaf656ed7 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BackendQueryTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BackendQueryTest.java @@ -17,52 +17,33 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import java.util.Arrays; -import java.util.Collection; import java.util.function.Supplier; +import java.util.stream.Stream; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public class BackendQueryTest { - - private final Supplier alive; - private final Object wantReturn; - private final boolean wantException; - private final Class wantExceptionClass; - private final String wantExceptionMessage; - - public BackendQueryTest( - final Supplier alive, - final Object wantReturn, - final boolean wantException, - final Class wantExceptionClass, - final String wantExceptionMessage) { - this.alive = alive; - this.wantReturn = wantReturn; - this.wantException = wantException; - this.wantExceptionClass = wantExceptionClass; - this.wantExceptionMessage = wantExceptionMessage; - } - - @Parameters - public static Collection data() { - return Arrays.asList( - new Object[][] { - {supplierOf(false), null, true, RuntimeException.class, "Timeout expired"}, - {supplierOf(true), "expected return", false, null, null} - }); + public static Stream data() { + return Stream.of( + Arguments.of(supplierOf(false), null, true, RuntimeException.class, "Timeout expired"), + Arguments.of(supplierOf(true), "expected return", false, null, null)); } private static Supplier supplierOf(final boolean val) { return () -> val; } - @Test - public void test() throws Exception { + @ParameterizedTest + @MethodSource("data") + public void test( + final Supplier alive, + final Object wantReturn, + final boolean wantException, + final Class wantExceptionClass, + final String wantExceptionMessage) + throws Exception { if (wantException) { assertThatThrownBy(() -> BackendQuery.runIfAlive(() -> wantReturn, alive)) .isInstanceOf(wantExceptionClass) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesLogCacheTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesLogCacheTest.java index 801c1d7bd8a..b0e84b9e3ba 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesLogCacheTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesLogCacheTest.java @@ -38,24 +38,27 @@ import java.io.IOException; import java.io.RandomAccessFile; +import java.nio.file.Path; import java.util.Collections; import java.util.List; import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class BlockchainQueriesLogCacheTest { - @ClassRule public static TemporaryFolder cacheDir = new TemporaryFolder(); + @TempDir private static Path cacheDir; private static LogsQuery logsQuery; private Hash testHash; @@ -66,7 +69,7 @@ public class BlockchainQueriesLogCacheTest { @Mock EthScheduler scheduler; private BlockchainQueries blockchainQueries; - @BeforeClass + @BeforeAll public static void setupClass() throws IOException { final Address testAddress = Address.fromHexString("0x123456"); final Bytes testMessage = Bytes.fromHexString("0x9876"); @@ -76,7 +79,7 @@ public static void setupClass() throws IOException { for (int i = 0; i < 2; i++) { final RandomAccessFile file = - new RandomAccessFile(cacheDir.newFile("logBloom-" + i + ".cache"), "rws"); + new RandomAccessFile(cacheDir.resolve("logBloom-" + i + ".cache").toFile(), "rws"); writeThreeEntries(testLogsBloomFilter, file); file.seek((BLOCKS_PER_BLOOM_CACHE - 3) * LogsBloomFilter.BYTE_SIZE); writeThreeEntries(testLogsBloomFilter, file); @@ -90,7 +93,7 @@ private static void writeThreeEntries(final LogsBloomFilter filter, final Random file.write(filter.toArray()); } - @Before + @BeforeEach public void setup() { final BlockHeader fakeHeader = new BlockHeader( @@ -113,6 +116,7 @@ public void setup() { null, null, null, + null, new MainnetBlockHeaderFunctions()); testHash = fakeHeader.getHash(); final BlockBody fakeBody = new BlockBody(Collections.emptyList(), Collections.emptyList()); @@ -123,10 +127,7 @@ public void setup() { when(blockchain.getBlockBody(any())).thenReturn(Optional.of(fakeBody)); blockchainQueries = new BlockchainQueries( - blockchain, - worldStateArchive, - Optional.of(cacheDir.getRoot().toPath()), - Optional.of(scheduler)); + blockchain, worldStateArchive, Optional.of(cacheDir), Optional.of(scheduler)); } /** diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesTest.java index c4e64c7a432..e4539b19904 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesTest.java @@ -46,14 +46,14 @@ import java.util.stream.Collectors; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class BlockchainQueriesTest { private BlockDataGenerator gen; private EthScheduler scheduler; - @Before + @BeforeEach public void setup() { gen = new BlockDataGenerator(); scheduler = new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem()); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/LogsQueryTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/LogsQueryTest.java index 19932e3da2f..95a5103546e 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/LogsQueryTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/LogsQueryTest.java @@ -26,7 +26,7 @@ import java.util.List; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class LogsQueryTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/PrivacyQueriesTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/PrivacyQueriesTest.java index 1da57461ea3..23790371503 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/PrivacyQueriesTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/PrivacyQueriesTest.java @@ -42,13 +42,16 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class PrivacyQueriesTest { private final String PRIVACY_GROUP_ID = "B1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; @@ -63,7 +66,7 @@ public class PrivacyQueriesTest { private PrivacyQueries privacyQueries; - @Before + @BeforeEach public void before() { privacyQueries = new PrivacyQueries(blockchainQueries, privateWorldStateReader); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/StateBackupServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/StateBackupServiceTest.java index 1687db1c83c..d8103963fc3 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/StateBackupServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/StateBackupServiceTest.java @@ -20,7 +20,7 @@ import java.nio.file.Path; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class StateBackupServiceTest { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/cache/TransactionLogBloomCacherTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/cache/TransactionLogBloomCacherTest.java index d7664520291..b88e68a4f0d 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/cache/TransactionLogBloomCacherTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/cache/TransactionLogBloomCacherTest.java @@ -36,6 +36,8 @@ import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; +import java.nio.file.Files; +import java.nio.file.Path; import java.time.Duration; import java.util.ArrayList; import java.util.List; @@ -43,20 +45,22 @@ import java.util.function.Supplier; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; @SuppressWarnings("unused") -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class TransactionLogBloomCacherTest { - @Rule public TemporaryFolder cacheDir = new TemporaryFolder(); + @TempDir private Path cacheDir; private Hash testHash; private static LogsBloomFilter testLogsBloomFilter; @@ -65,7 +69,7 @@ public class TransactionLogBloomCacherTest { @Mock EthScheduler scheduler; private TransactionLogBloomCacher transactionLogBloomCacher; - @BeforeClass + @BeforeAll public static void setupClass() { final Address testAddress = Address.fromHexString("0x123456"); final Bytes testMessage = Bytes.fromHexString("0x9876"); @@ -81,7 +85,7 @@ private static void writeThreeEntries(final LogsBloomFilter filter, final Random } @SuppressWarnings({"unchecked", "ReturnValueIgnored"}) - @Before + @BeforeEach public void setup() throws IOException { final BlockHeader fakeHeader = new BlockHeader( @@ -104,6 +108,7 @@ public void setup() throws IOException { null, null, null, + null, new MainnetBlockHeaderFunctions()); testHash = fakeHeader.getHash(); when(blockchain.getBlockHeader(anyLong())).thenReturn(Optional.of(fakeHeader)); @@ -119,22 +124,21 @@ public void setup() throws IOException { invocation.getArgument(0, Supplier.class).get(); return null; }); - transactionLogBloomCacher = - new TransactionLogBloomCacher(blockchain, cacheDir.getRoot().toPath(), scheduler); + transactionLogBloomCacher = new TransactionLogBloomCacher(blockchain, cacheDir, scheduler); } @Test public void shouldSplitLogsIntoSeveralFiles() { when(blockchain.getChainHeadBlockNumber()).thenReturn(200003L); - assertThat(cacheDir.getRoot().list().length).isEqualTo(0); + assertThat(cacheDir.toFile().list().length).isEqualTo(0); transactionLogBloomCacher.cacheAll(); - assertThat(cacheDir.getRoot().list().length).isEqualTo(2); + assertThat(cacheDir.toFile().list().length).isEqualTo(2); } @Test public void shouldUpdateCacheWhenBlockAdded() throws IOException { - final File logBloom = cacheDir.newFile("logBloom-0.cache"); + final File logBloom = Files.createFile(cacheDir.resolve("logBloom-0.cache")).toFile(); createLogBloomCache(logBloom); @@ -146,12 +150,12 @@ public void shouldUpdateCacheWhenBlockAdded() throws IOException { header, Optional.empty(), Optional.of(logBloom)); assertThat(logBloom.length()).isEqualTo(BLOOM_BITS_LENGTH * 4); - assertThat(cacheDir.getRoot().list().length).isEqualTo(1); + assertThat(cacheDir.toFile().list().length).isEqualTo(1); } @Test public void shouldReloadCacheWhenBLockIsMissing() throws IOException { - final File logBloom = cacheDir.newFile("logBloom-0.cache"); + final File logBloom = Files.createFile(cacheDir.resolve("logBloom-0.cache")).toFile(); createLogBloomCache(logBloom); assertThat(logBloom.length()).isEqualTo(BLOOM_BITS_LENGTH * 3); @@ -170,31 +174,32 @@ public void shouldReloadCacheWhenBLockIsMissing() throws IOException { } assertThat(logBloom.length()).isEqualTo(BLOOM_BITS_LENGTH * 5); - assertThat(cacheDir.getRoot().list().length).isEqualTo(1); + assertThat(cacheDir.toFile().list().length).isEqualTo(1); } @Test public void shouldReloadCacheWhenFileIsInvalid() throws IOException { - final File logBloom = cacheDir.newFile("logBloom-0.cache"); - final File logBloom1 = cacheDir.newFile("logBloom-1.cache"); + final File logBloom = Files.createFile(cacheDir.resolve("logBloom-0.cache")).toFile(); + + final File logBloom1 = Files.createFile(cacheDir.resolve("logBloom-1.cache")).toFile(); when(blockchain.getChainHeadBlockNumber()).thenReturn(100003L); assertThat(logBloom.length()).isEqualTo(0); assertThat(logBloom1.length()).isEqualTo(0); - assertThat(cacheDir.getRoot().list().length).isEqualTo(2); + assertThat(cacheDir.toFile().list().length).isEqualTo(2); transactionLogBloomCacher.cacheAll(); assertThat(logBloom.length()).isEqualTo(BLOOM_BITS_LENGTH * BLOCKS_PER_BLOOM_CACHE); assertThat(logBloom1.length()).isEqualTo(0); - assertThat(cacheDir.getRoot().list().length).isEqualTo(2); + assertThat(cacheDir.toFile().list().length).isEqualTo(2); } @Test public void shouldUpdateCacheWhenChainReorgFired() throws IOException { - final File logBloom = cacheDir.newFile("logBloom-0.cache"); + final File logBloom = Files.createFile(cacheDir.resolve("logBloom-0.cache")).toFile(); final List firstBranch = new ArrayList<>(); @@ -229,7 +234,7 @@ public void shouldUpdateCacheWhenChainReorgFired() throws IOException { forkBranch.get(1), Optional.empty(), Optional.of(logBloom)); assertThat(logBloom.length()).isEqualTo(BLOOM_BITS_LENGTH * 2); - assertThat(cacheDir.getRoot().list().length).isEqualTo(1); + assertThat(cacheDir.toFile().list().length).isEqualTo(1); } private void createLogBloomCache(final File logBloom) throws IOException { @@ -277,6 +282,7 @@ private BlockHeader createBlock(final long number, final Optional messag null, null, null, + null, new MainnetBlockHeaderFunctions()); testHash = fakeHeader.getHash(); when(blockchain.getBlockHeader(number)).thenReturn(Optional.of(fakeHeader)); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/tls/FileBasedPasswordProviderTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/tls/FileBasedPasswordProviderTest.java index 2034f63147b..dd9d75778e8 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/tls/FileBasedPasswordProviderTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/tls/FileBasedPasswordProviderTest.java @@ -22,17 +22,16 @@ import java.util.List; import org.assertj.core.api.Assertions; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; public class FileBasedPasswordProviderTest { - @Rule public final TemporaryFolder folder = new TemporaryFolder(); + @TempDir private Path folder; @Test public void passwordCanBeReadFromFile() throws IOException { - final Path passwordFile = folder.newFile().toPath(); + final Path passwordFile = folder.resolve("pass1"); Files.write(passwordFile, List.of("line1", "line2")); final String password = new FileBasedPasswordProvider(passwordFile).get(); @@ -41,7 +40,7 @@ public void passwordCanBeReadFromFile() throws IOException { @Test public void exceptionRaisedFromReadingEmptyFile() throws IOException { - final Path passwordFile = folder.newFile().toPath(); + final Path passwordFile = folder.resolve("pass2"); Files.write(passwordFile, new byte[0]); Assertions.assertThatExceptionOfType(TlsConfigurationException.class) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtilsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtilsTest.java index 942898b8128..91ac0404a75 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtilsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtilsTest.java @@ -31,7 +31,7 @@ import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class DomainObjectDecodeUtilsTest { diff --git a/ethereum/blockcreation/build.gradle b/ethereum/blockcreation/build.gradle index 6ab57e51315..7fc35a6ec10 100644 --- a/ethereum/blockcreation/build.gradle +++ b/ethereum/blockcreation/build.gradle @@ -24,8 +24,8 @@ dependencies { implementation 'com.google.guava:guava' implementation 'io.vertx:vertx-core' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-units' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-units' testImplementation project(path: ':config', configuration: 'testSupportArtifacts') testImplementation project(path: ':ethereum:core', configuration: 'testArtifacts') @@ -35,12 +35,9 @@ dependencies { testImplementation project(':testutil') testImplementation 'com.fasterxml.jackson.core:jackson-databind' - testImplementation 'junit:junit' testImplementation 'org.assertj:assertj-core' testImplementation 'org.awaitility:awaitility' testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.mockito:mockito-junit-jupiter' testImplementation 'org.mockito:mockito-core' - - testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' } diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java index 5f4af0bf49d..2d02a113dce 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java @@ -14,9 +14,12 @@ */ package org.hyperledger.besu.ethereum.blockcreation; +import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent; + import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.DataGas; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.blockcreation.BlockTransactionSelector.TransactionSelectionResults; @@ -33,7 +36,7 @@ import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Withdrawal; import org.hyperledger.besu.ethereum.core.encoding.DepositDecoder; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.AbstractBlockProcessor; import org.hyperledger.besu.ethereum.mainnet.BodyValidation; import org.hyperledger.besu.ethereum.mainnet.DepositsValidator; @@ -47,7 +50,6 @@ import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.evm.account.EvmAccount; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.securitymodule.SecurityModuleException; @@ -79,7 +81,7 @@ public interface ExtraDataCalculator { protected final Supplier> targetGasLimitSupplier; private final ExtraDataCalculator extraDataCalculator; - private final PendingTransactions pendingTransactions; + private final TransactionPool transactionPool; protected final ProtocolContext protocolContext; protected final ProtocolSchedule protocolSchedule; protected final BlockHeaderFunctions blockHeaderFunctions; @@ -95,7 +97,7 @@ protected AbstractBlockCreator( final MiningBeneficiaryCalculator miningBeneficiaryCalculator, final Supplier> targetGasLimitSupplier, final ExtraDataCalculator extraDataCalculator, - final PendingTransactions pendingTransactions, + final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, final Wei minTransactionGasPrice, @@ -106,7 +108,7 @@ protected AbstractBlockCreator( this.miningBeneficiaryCalculator = miningBeneficiaryCalculator; this.targetGasLimitSupplier = targetGasLimitSupplier; this.extraDataCalculator = extraDataCalculator; - this.pendingTransactions = pendingTransactions; + this.transactionPool = transactionPool; this.protocolContext = protocolContext; this.protocolSchedule = protocolSchedule; this.minTransactionGasPrice = minTransactionGasPrice; @@ -169,10 +171,10 @@ protected BlockCreationResult createBlock( createPendingBlockHeader(timestamp, maybePrevRandao, newProtocolSpec); final Address miningBeneficiary = miningBeneficiaryCalculator.getMiningBeneficiary(processableBlockHeader.getNumber()); - final Wei dataGasPrice = + Wei blobGasPrice = newProtocolSpec .getFeeMarket() - .dataPrice(parentHeader.getExcessDataGas().orElse(DataGas.ZERO)); + .blobGasPricePerGas(calculateExcessBlobGasForParent(newProtocolSpec, parentHeader)); throwIfStopped(); @@ -185,7 +187,7 @@ protected BlockCreationResult createBlock( disposableWorldState, maybeTransactions, miningBeneficiary, - dataGasPrice, + blobGasPrice, newProtocolSpec); transactionResults.logSelectionStats(); @@ -228,17 +230,17 @@ protected BlockCreationResult createBlock( throwIfStopped(); - final DataGas newExcessDataGas = computeExcessDataGas(transactionResults, newProtocolSpec); + final GasUsage usage = computeExcessBlobGas(transactionResults, newProtocolSpec); throwIfStopped(); - final SealableBlockHeader sealableBlockHeader = + BlockHeaderBuilder builder = BlockHeaderBuilder.create() .populateFrom(processableBlockHeader) .ommersHash(BodyValidation.ommersHash(ommers)) .stateRoot(disposableWorldState.rootHash()) .transactionsRoot( - BodyValidation.transactionsRoot(transactionResults.getTransactions())) + BodyValidation.transactionsRoot(transactionResults.getSelectedTransactions())) .receiptsRoot(BodyValidation.receiptsRoot(transactionResults.getReceipts())) .logsBloom(BodyValidation.logsBloom(transactionResults.getReceipts())) .gasUsed(transactionResults.getCumulativeGasUsed()) @@ -247,9 +249,12 @@ protected BlockCreationResult createBlock( withdrawalsCanBeProcessed ? BodyValidation.withdrawalsRoot(maybeWithdrawals.get()) : null) - .depositsRoot(maybeDeposits.map(BodyValidation::depositsRoot).orElse(null)) - .excessDataGas(newExcessDataGas) - .buildSealableBlockHeader(); + .depositsRoot(maybeDeposits.map(BodyValidation::depositsRoot).orElse(null)); + if (usage != null) { + builder.blobGasUsed(usage.used.toLong()).excessBlobGas(usage.excessBlobGas); + } + + final SealableBlockHeader sealableBlockHeader = builder.buildSealableBlockHeader(); final BlockHeader blockHeader = createFinalBlockHeader(sealableBlockHeader); @@ -259,7 +264,10 @@ protected BlockCreationResult createBlock( new Block( blockHeader, new BlockBody( - transactionResults.getTransactions(), ommers, withdrawals, maybeDeposits)); + transactionResults.getSelectedTransactions(), + ommers, + withdrawals, + maybeDeposits)); return new BlockCreationResult(block, transactionResults); } catch (final SecurityModuleException ex) { throw new IllegalStateException("Failed to create block signature", ex); @@ -280,8 +288,10 @@ List findDepositsFromReceipts(final TransactionSelectionResults transac .toList(); } - private DataGas computeExcessDataGas( - TransactionSelectionResults transactionResults, ProtocolSpec newProtocolSpec) { + record GasUsage(BlobGas excessBlobGas, BlobGas used) {} + + private GasUsage computeExcessBlobGas( + final TransactionSelectionResults transactionResults, final ProtocolSpec newProtocolSpec) { if (newProtocolSpec.getFeeMarket().implementsDataFee()) { final var gasCalculator = newProtocolSpec.getGasCalculator(); @@ -290,11 +300,14 @@ private DataGas computeExcessDataGas( .map(tx -> tx.getVersionedHashes().orElseThrow()) .mapToInt(List::size) .sum(); - // casting parent excess data gas to long since for the moment it should be well below that + // casting parent excess blob gas to long since for the moment it should be well below that // limit - return DataGas.of( - gasCalculator.computeExcessDataGas( - parentHeader.getExcessDataGas().map(DataGas::toLong).orElse(0L), newBlobsCount)); + BlobGas excessBlobGas = + BlobGas.of( + gasCalculator.computeExcessBlobGas( + parentHeader.getExcessBlobGas().map(BlobGas::toLong).orElse(0L), newBlobsCount)); + BlobGas used = BlobGas.of(gasCalculator.blobGasCost(newBlobsCount)); + return new GasUsage(excessBlobGas, used); } return null; } @@ -304,7 +317,7 @@ private TransactionSelectionResults selectTransactions( final MutableWorldState disposableWorldState, final Optional> transactions, final Address miningBeneficiary, - final Wei dataGasPrice, + final Wei blobGasPrice, final ProtocolSpec protocolSpec) throws RuntimeException { final MainnetTransactionProcessor transactionProcessor = protocolSpec.getTransactionProcessor(); @@ -317,14 +330,14 @@ private TransactionSelectionResults selectTransactions( transactionProcessor, protocolContext.getBlockchain(), disposableWorldState, - pendingTransactions, + transactionPool, processableBlockHeader, transactionReceiptFactory, minTransactionGasPrice, minBlockOccupancyRatio, isCancelled::get, miningBeneficiary, - dataGasPrice, + blobGasPrice, protocolSpec.getFeeMarket(), protocolSpec.getGasCalculator(), protocolSpec.getGasLimitCalculator(), diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java index 83b9860d15a..3434c6f1b26 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java @@ -21,7 +21,7 @@ import org.hyperledger.besu.ethereum.chain.PoWObserver; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.MiningParameters; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.AbstractGasLimitSpecification; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.util.Subscribers; @@ -45,7 +45,7 @@ public abstract class AbstractMinerExecutorA list of receipts for inclusion in the block. *
  • The root hash of the world state at the completion of transaction execution. *
  • The amount of gas consumed when executing all transactions. + *
  • A list of transactions evaluated but not included in the block being constructed. * * * Once "used" this class must be discarded and another created. This class contains state which is @@ -78,49 +80,45 @@ */ public class BlockTransactionSelector { - public record TransactionValidationResult( - Transaction transaction, ValidationResult validationResult) {} - public static class TransactionSelectionResults { - private final List transactions = Lists.newArrayList(); + private final List selectedTransactions = Lists.newArrayList(); private final Map> transactionsByType = new EnumMap<>(TransactionType.class); private final List receipts = Lists.newArrayList(); - private final List invalidTransactions = Lists.newArrayList(); - private final List selectionResults = Lists.newArrayList(); + private final Map notSelectedTransactions = + new HashMap<>(); private long cumulativeGasUsed = 0; - private long cumulativeDataGasUsed = 0; + private long cumulativeBlobGasUsed = 0; - private void update( + private void updateSelected( final Transaction transaction, final TransactionReceipt receipt, final long gasUsed, - final long dataGasUsed) { - transactions.add(transaction); + final long blobGasUsed) { + selectedTransactions.add(transaction); transactionsByType .computeIfAbsent(transaction.getType(), type -> new ArrayList<>()) .add(transaction); receipts.add(receipt); cumulativeGasUsed += gasUsed; - cumulativeDataGasUsed += dataGasUsed; + cumulativeBlobGasUsed += blobGasUsed; LOG.atTrace() .setMessage( - "New selected transaction {}, total transactions {}, cumulative gas used {}, cumulative data gas used {}") + "New selected transaction {}, total transactions {}, cumulative gas used {}, cumulative blob gas used {}") .addArgument(transaction::toTraceLog) - .addArgument(transactions::size) + .addArgument(selectedTransactions::size) .addArgument(cumulativeGasUsed) - .addArgument(cumulativeDataGasUsed) + .addArgument(cumulativeBlobGasUsed) .log(); } - private void updateWithInvalidTransaction( - final Transaction transaction, - final ValidationResult validationResult) { - invalidTransactions.add(new TransactionValidationResult(transaction, validationResult)); + public void updateNotSelected( + final Transaction transaction, final TransactionSelectionResult res) { + notSelectedTransactions.put(transaction, res); } - public List getTransactions() { - return transactions; + public List getSelectedTransactions() { + return selectedTransactions; } public List getTransactionsByType(final TransactionType type) { @@ -135,43 +133,31 @@ public long getCumulativeGasUsed() { return cumulativeGasUsed; } - public long getCumulativeDataGasUsed() { - return cumulativeDataGasUsed; - } - - public List getInvalidTransactions() { - return invalidTransactions; + public long getCumulativeBlobGasUsed() { + return cumulativeBlobGasUsed; } - public void addSelectionResult(final TransactionSelectionResult res) { - selectionResults.add(res); + public Map getNotSelectedTransactions() { + return notSelectedTransactions; } public void logSelectionStats() { if (LOG.isDebugEnabled()) { - final Map selectionStats = - selectionResults.stream() + final Map notSelectedStats = + notSelectedTransactions.values().stream() .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); LOG.debug( - "Selection stats: Totals[Evaluated={}, Selected={}, Skipped={}, Dropped={}]; Detailed[{}]", - selectionResults.size(), - selectionStats.entrySet().stream() - .filter(e -> e.getKey().selected()) - .map(Map.Entry::getValue) - .mapToInt(Long::intValue) - .sum(), - selectionStats.entrySet().stream() - .filter(e -> !e.getKey().selected()) - .map(Map.Entry::getValue) - .mapToInt(Long::intValue) - .sum(), - selectionStats.entrySet().stream() + "Selection stats: Totals[Evaluated={}, Selected={}, NotSelected={}, Discarded={}]; Detailed[{}]", + selectedTransactions.size() + notSelectedTransactions.size(), + selectedTransactions.size(), + notSelectedStats.size(), + notSelectedStats.entrySet().stream() .filter(e -> e.getKey().discard()) .map(Map.Entry::getValue) .mapToInt(Long::intValue) .sum(), - selectionStats.entrySet().stream() + notSelectedStats.entrySet().stream() .map(e -> e.getKey().toString() + "=" + e.getValue()) .sorted() .collect(Collectors.joining(", "))); @@ -188,30 +174,41 @@ public boolean equals(final Object o) { } TransactionSelectionResults that = (TransactionSelectionResults) o; return cumulativeGasUsed == that.cumulativeGasUsed - && cumulativeDataGasUsed == that.cumulativeDataGasUsed - && transactions.equals(that.transactions) - && receipts.equals(that.receipts) - && invalidTransactions.equals(that.invalidTransactions); + && cumulativeBlobGasUsed == that.cumulativeBlobGasUsed + && selectedTransactions.equals(that.selectedTransactions) + && notSelectedTransactions.equals(that.notSelectedTransactions) + && receipts.equals(that.receipts); } @Override public int hashCode() { return Objects.hash( - transactions, receipts, invalidTransactions, cumulativeGasUsed, cumulativeDataGasUsed); + selectedTransactions, + notSelectedTransactions, + receipts, + cumulativeGasUsed, + cumulativeBlobGasUsed); } public String toTraceLog() { return "cumulativeGasUsed=" + cumulativeGasUsed - + ", cumulativeDataGasUsed=" - + cumulativeDataGasUsed - + ", transactions=" - + transactions.stream().map(Transaction::toTraceLog).collect(Collectors.joining("; ")); + + ", cumulativeBlobGasUsed=" + + cumulativeBlobGasUsed + + ", selectedTransactions=" + + selectedTransactions.stream() + .map(Transaction::toTraceLog) + .collect(Collectors.joining("; ")) + + ", notSelectedTransactions=" + + notSelectedTransactions.entrySet().stream() + .map(e -> e.getValue() + ":" + e.getKey().toTraceLog()) + .collect(Collectors.joining(";")); } } private static final Logger LOG = LoggerFactory.getLogger(BlockTransactionSelector.class); - + private static final TransactionSelector ALWAYS_SELECT = + (_1, _2, _3, _4) -> TransactionSelectionResult.SELECTED; private final Wei minTransactionGasPrice; private final Double minBlockOccupancyRatio; private final Supplier isCancelled; @@ -219,15 +216,14 @@ public String toTraceLog() { private final ProcessableBlockHeader processableBlockHeader; private final Blockchain blockchain; private final MutableWorldState worldState; - private final PendingTransactions pendingTransactions; + private final TransactionPool transactionPool; private final AbstractBlockProcessor.TransactionReceiptFactory transactionReceiptFactory; private final Address miningBeneficiary; - private final Wei dataGasPrice; + private final Wei blobGasPrice; private final FeeMarket feeMarket; private final GasCalculator gasCalculator; private final GasLimitCalculator gasLimitCalculator; private final TransactionSelector transactionSelector; - private final TransactionSelectionResults transactionSelectionResults = new TransactionSelectionResults(); @@ -235,14 +231,14 @@ public BlockTransactionSelector( final MainnetTransactionProcessor transactionProcessor, final Blockchain blockchain, final MutableWorldState worldState, - final PendingTransactions pendingTransactions, + final TransactionPool transactionPool, final ProcessableBlockHeader processableBlockHeader, final AbstractBlockProcessor.TransactionReceiptFactory transactionReceiptFactory, final Wei minTransactionGasPrice, final Double minBlockOccupancyRatio, final Supplier isCancelled, final Address miningBeneficiary, - final Wei dataGasPrice, + final Wei blobGasPrice, final FeeMarket feeMarket, final GasCalculator gasCalculator, final GasLimitCalculator gasLimitCalculator, @@ -250,36 +246,37 @@ public BlockTransactionSelector( this.transactionProcessor = transactionProcessor; this.blockchain = blockchain; this.worldState = worldState; - this.pendingTransactions = pendingTransactions; + this.transactionPool = transactionPool; this.processableBlockHeader = processableBlockHeader; this.transactionReceiptFactory = transactionReceiptFactory; this.isCancelled = isCancelled; this.minTransactionGasPrice = minTransactionGasPrice; this.minBlockOccupancyRatio = minBlockOccupancyRatio; this.miningBeneficiary = miningBeneficiary; - this.dataGasPrice = dataGasPrice; + this.blobGasPrice = blobGasPrice; this.feeMarket = feeMarket; this.gasCalculator = gasCalculator; this.gasLimitCalculator = gasLimitCalculator; this.transactionSelector = - transactionSelectorFactory.map(TransactionSelectorFactory::create).orElse(null); + transactionSelectorFactory.map(TransactionSelectorFactory::create).orElse(ALWAYS_SELECT); } /* This function iterates over (potentially) all transactions in the PendingTransactions, this is a - long running process. - If running in a thread, it can be cancelled via the isCancelled supplier (which will result + long-running process. If running in a thread, it can be cancelled via the isCancelled supplier (which will result in this throwing an CancellationException). */ public TransactionSelectionResults buildTransactionListForBlock() { LOG.atDebug() .setMessage("Transaction pool stats {}") - .addArgument(pendingTransactions.logStats()) + .addArgument(transactionPool::logStats) .log(); - pendingTransactions.selectTransactions( + transactionPool.selectTransactions( pendingTransaction -> { - final var res = evaluateTransaction(pendingTransaction, false); - transactionSelectionResults.addSelectionResult(res); + final var res = evaluateTransaction(pendingTransaction); + if (!res.selected()) { + transactionSelectionResults.updateNotSelected(pendingTransaction, res); + } return res; }); LOG.atTrace() @@ -297,8 +294,12 @@ public TransactionSelectionResults buildTransactionListForBlock() { */ public TransactionSelectionResults evaluateTransactions(final List transactions) { transactions.forEach( - transaction -> - transactionSelectionResults.addSelectionResult(evaluateTransaction(transaction, true))); + transaction -> { + final var res = evaluateTransaction(transaction); + if (!res.selected()) { + transactionSelectionResults.updateNotSelected(transaction, res); + } + }); return transactionSelectionResults; } @@ -311,8 +312,7 @@ public TransactionSelectionResults evaluateTransactions(final List * the space remaining in the block. * */ - private TransactionSelectionResult evaluateTransaction( - final Transaction transaction, final boolean reportFutureNonceTransactionsAsInvalid) { + private TransactionSelectionResult evaluateTransaction(final Transaction transaction) { if (isCancelled.get()) { throw new CancellationException("Cancelled during transaction selection."); } @@ -354,7 +354,7 @@ private TransactionSelectionResult evaluateTransaction( blockHashLookup, false, TransactionValidationParams.mining(), - dataGasPrice); + blobGasPrice); if (!effectiveResult.isInvalid()) { @@ -364,16 +364,13 @@ private TransactionSelectionResult evaluateTransaction( final long cumulativeGasUsed = transactionSelectionResults.getCumulativeGasUsed() + gasUsedByTransaction; - TransactionSelectionResult txSelectionResult = TransactionSelectionResult.SELECTED; - - if (transactionSelector != null) { - txSelectionResult = - transactionSelector.selectTransaction( - transaction, - effectiveResult.getStatus() == TransactionProcessingResult.Status.SUCCESSFUL, - getLogs(effectiveResult.getLogs()), - cumulativeGasUsed); - } + // check if the transaction is valid also for an optional configured plugin + final TransactionSelectionResult txSelectionResult = + transactionSelector.selectTransaction( + transaction, + effectiveResult.getStatus() == TransactionProcessingResult.Status.SUCCESSFUL, + getLogs(effectiveResult.getLogs()), + cumulativeGasUsed); if (txSelectionResult.equals(TransactionSelectionResult.SELECTED)) { @@ -382,26 +379,25 @@ private TransactionSelectionResult evaluateTransaction( transactionReceiptFactory.create( transaction.getType(), effectiveResult, worldState, cumulativeGasUsed); - final long dataGasUsed = gasCalculator.dataGasCost(transaction.getBlobCount()); + final long blobGasUsed = gasCalculator.blobGasCost(transaction.getBlobCount()); - transactionSelectionResults.update(transaction, receipt, gasUsedByTransaction, dataGasUsed); + transactionSelectionResults.updateSelected( + transaction, receipt, gasUsedByTransaction, blobGasUsed); LOG.atTrace() .setMessage("Selected {} for block creation") .addArgument(transaction::toTraceLog) .log(); - } - return txSelectionResult; - } else { - final boolean isIncorrectNonce = isIncorrectNonce(effectiveResult.getValidationResult()); - if (!isIncorrectNonce || reportFutureNonceTransactionsAsInvalid) { - transactionSelectionResults.updateWithInvalidTransaction( - transaction, effectiveResult.getValidationResult()); + return TransactionSelectionResult.SELECTED; } - return transactionSelectionResultForInvalidResult( - transaction, effectiveResult.getValidationResult()); + + // the transaction is not valid for the plugin + return txSelectionResult; } + + return transactionSelectionResultForInvalidResult( + transaction, effectiveResult.getValidationResult()); } private List getLogs(final List logs) { @@ -410,7 +406,7 @@ private List getLogs(final List logs) private boolean transactionDataPriceBelowMin(final Transaction transaction) { if (transaction.getType().supportsBlob()) { - if (transaction.getMaxFeePerDataGas().orElseThrow().lessThan(dataGasPrice)) { + if (transaction.getMaxFeePerBlobGas().orElseThrow().lessThan(blobGasPrice)) { return true; } } @@ -421,7 +417,7 @@ private boolean transactionCurrentPriceBelowMin(final Transaction transaction) { // Here we only care about EIP1159 since for Frontier and local transactions the checks // that we do when accepting them in the pool are enough if (transaction.getType().supports1559FeeMarket() - && !pendingTransactions.isLocalSender(transaction.getSender())) { + && !transactionPool.isLocalSender(transaction.getSender())) { // For EIP1559 transactions, the price is dynamic and depends on network conditions, so we can // only calculate at this time the current minimum price the transaction is willing to pay @@ -472,20 +468,16 @@ private boolean isTransientValidationError(final TransactionInvalidReason invali || invalidReason.equals(TransactionInvalidReason.NONCE_TOO_HIGH); } - private boolean isIncorrectNonce(final ValidationResult result) { - return result.getInvalidReason().equals(TransactionInvalidReason.NONCE_TOO_HIGH); - } - private boolean transactionTooLargeForBlock(final Transaction transaction) { - final long dataGasUsed = gasCalculator.dataGasCost(transaction.getBlobCount()); + final long blobGasUsed = gasCalculator.blobGasCost(transaction.getBlobCount()); - if (dataGasUsed - > gasLimitCalculator.currentDataGasLimit() - - transactionSelectionResults.getCumulativeDataGasUsed()) { + if (blobGasUsed + > gasLimitCalculator.currentBlobGasLimit() + - transactionSelectionResults.getCumulativeBlobGasUsed()) { return true; } - return transaction.getGasLimit() + dataGasUsed + return transaction.getGasLimit() + blobGasUsed > processableBlockHeader.getGasLimit() - transactionSelectionResults.getCumulativeGasUsed(); } diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreator.java index 90f529256ef..46eb9d5c5ff 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreator.java @@ -20,7 +20,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.core.SealableBlockHeader; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.EthHash; import org.hyperledger.besu.ethereum.mainnet.PoWSolution; import org.hyperledger.besu.ethereum.mainnet.PoWSolver; @@ -43,7 +43,7 @@ public PoWBlockCreator( final Address coinbase, final Supplier> targetGasLimitSupplier, final ExtraDataCalculator extraDataCalculator, - final PendingTransactions pendingTransactions, + final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, final PoWSolver nonceSolver, @@ -55,7 +55,7 @@ public PoWBlockCreator( __ -> coinbase, targetGasLimitSupplier, extraDataCalculator, - pendingTransactions, + transactionPool, protocolContext, protocolSchedule, minTransactionGasPrice, diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java index 0d98b723db5..49f7e702c23 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java @@ -20,7 +20,7 @@ import org.hyperledger.besu.ethereum.chain.PoWObserver; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.MiningParameters; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.EpochCalculator; import org.hyperledger.besu.ethereum.mainnet.PoWSolver; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; @@ -43,13 +43,13 @@ public class PoWMinerExecutor extends AbstractMinerExecutor { public PoWMinerExecutor( final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, - final PendingTransactions pendingTransactions, + final TransactionPool transactionPool, final MiningParameters miningParams, final AbstractBlockScheduler blockScheduler, final EpochCalculator epochCalculator, final long powJobTimeToLive, final int maxOmmerDepth) { - super(protocolContext, protocolSchedule, pendingTransactions, miningParams, blockScheduler); + super(protocolContext, protocolSchedule, transactionPool, miningParams, blockScheduler); this.coinbase = miningParams.getCoinbase(); this.nonceGenerator = miningParams.getNonceGenerator().orElse(new RandomNonceGenerator()); this.epochCalculator = epochCalculator; @@ -92,7 +92,7 @@ public PoWBlockMiner createMiner( coinbase.orElse(Address.ZERO), () -> targetGasLimit.map(AtomicLong::longValue), parent -> extraData, - pendingTransactions, + transactionPool, protocolContext, protocolSchedule, solver, diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java index 6a832cf011c..9addce37975 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java @@ -19,6 +19,7 @@ import static org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSpecs.DEFAULT_DEPOSIT_CONTRACT_ADDRESS; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -26,26 +27,40 @@ import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.config.GenesisConfigOptions; +import org.hyperledger.besu.crypto.KeyPair; +import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.BLSPublicKey; import org.hyperledger.besu.datatypes.BLSSignature; +import org.hyperledger.besu.datatypes.BlobGas; +import org.hyperledger.besu.datatypes.BlobsWithCommitments; import org.hyperledger.besu.datatypes.GWei; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.blockcreation.BlockCreator.BlockCreationResult; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; +import org.hyperledger.besu.ethereum.core.BlobTestFixture; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.core.Deposit; import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.SealableBlockHeader; +import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; +import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.core.Withdrawal; +import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics; import org.hyperledger.besu.ethereum.eth.transactions.sorter.AbstractPendingTransactionsSorter; import org.hyperledger.besu.ethereum.eth.transactions.sorter.GasPricePendingTransactionsSorter; import org.hyperledger.besu.ethereum.mainnet.BodyValidation; @@ -54,6 +69,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.ethereum.mainnet.WithdrawalsProcessor; +import org.hyperledger.besu.ethereum.mainnet.feemarket.CancunFeeMarket; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.log.Log; import org.hyperledger.besu.evm.log.LogTopic; @@ -69,6 +85,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt64; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -253,6 +270,52 @@ void withNoProcessorAndWithdrawals_WithdrawalsAreNotProcessed() { assertThat(blockCreationResult.getBlock().getBody().getWithdrawals()).isEmpty(); } + @Disabled + @Test + public void computesGasUsageFromIncludedTransactions() { + final KeyPair senderKeys = SignatureAlgorithmFactory.getInstance().generateKeyPair(); + final AbstractBlockCreator blockCreator = blockCreatorWithBlobGasSupport(); + BlobTestFixture blobTestFixture = new BlobTestFixture(); + BlobsWithCommitments bwc = blobTestFixture.createBlobsWithCommitments(6); + TransactionTestFixture ttf = new TransactionTestFixture(); + Transaction fullOfBlobs = + ttf.to(Optional.of(Address.ZERO)) + .type(TransactionType.BLOB) + .chainId(Optional.of(BigInteger.valueOf(42))) + .maxFeePerGas(Optional.of(Wei.of(15))) + .maxFeePerBlobGas(Optional.of(Wei.of(128))) + .maxPriorityFeePerGas(Optional.of(Wei.of(1))) + .versionedHashes(Optional.of(bwc.getVersionedHashes())) + .createTransaction(senderKeys); + + ttf.blobsWithCommitments(Optional.of(bwc)); + final BlockCreationResult blockCreationResult = + blockCreator.createBlock( + Optional.of(List.of(fullOfBlobs)), + Optional.empty(), + Optional.empty(), + Optional.empty(), + 1L, + false); + long blobGasUsage = blockCreationResult.getBlock().getHeader().getGasUsed(); + assertThat(blobGasUsage).isNotZero(); + BlobGas excessBlobGas = blockCreationResult.getBlock().getHeader().getExcessBlobGas().get(); + assertThat(excessBlobGas).isNotNull(); + } + + private AbstractBlockCreator blockCreatorWithBlobGasSupport() { + final ProtocolSpecAdapters protocolSpecAdapters = + ProtocolSpecAdapters.create( + 0, + specBuilder -> { + specBuilder.feeMarket(new CancunFeeMarket(0, Optional.empty())); + specBuilder.isReplayProtectionSupported(true); + specBuilder.withdrawalsProcessor(withdrawalsProcessor); + return specBuilder; + }); + return createBlockCreator(protocolSpecAdapters, EMPTY_DEPOSIT_CONTRACT_ADDRESS); + } + private AbstractBlockCreator blockCreatorWithWithdrawalsProcessor() { final ProtocolSpecAdapters protocolSpecAdapters = ProtocolSpecAdapters.create( @@ -282,19 +345,33 @@ private AbstractBlockCreator createBlockCreator( .build(); final MutableBlockchain blockchain = executionContextTestFixture.getBlockchain(); + final TransactionPoolConfiguration poolConf = + ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(100).build(); final AbstractPendingTransactionsSorter sorter = new GasPricePendingTransactionsSorter( - ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(100).build(), - Clock.systemUTC(), - new NoOpMetricsSystem(), - blockchain::getChainHeadHeader); + poolConf, Clock.systemUTC(), new NoOpMetricsSystem(), blockchain::getChainHeadHeader); + + final EthContext ethContext = mock(EthContext.class, RETURNS_DEEP_STUBS); + when(ethContext.getEthPeers().subscribeConnect(any())).thenReturn(1L); + + final TransactionPool transactionPool = + new TransactionPool( + () -> sorter, + executionContextTestFixture.getProtocolSchedule(), + executionContextTestFixture.getProtocolContext(), + mock(TransactionBroadcaster.class), + ethContext, + mock(MiningParameters.class), + new TransactionPoolMetrics(new NoOpMetricsSystem()), + poolConf); + transactionPool.setEnabled(); return new TestBlockCreator( Address.ZERO, __ -> Address.ZERO, () -> Optional.of(30_000_000L), __ -> Bytes.fromHexString("deadbeef"), - sorter, + transactionPool, executionContextTestFixture.getProtocolContext(), executionContextTestFixture.getProtocolSchedule(), Wei.of(1L), @@ -310,7 +387,7 @@ protected TestBlockCreator( final MiningBeneficiaryCalculator miningBeneficiaryCalculator, final Supplier> targetGasLimitSupplier, final ExtraDataCalculator extraDataCalculator, - final AbstractPendingTransactionsSorter pendingTransactions, + final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, final Wei minTransactionGasPrice, @@ -322,7 +399,7 @@ protected TestBlockCreator( miningBeneficiaryCalculator, targetGasLimitSupplier, extraDataCalculator, - pendingTransactions, + transactionPool, protocolContext, protocolSchedule, minTransactionGasPrice, diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java index cd7bdb87f6f..50e9cb48821 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java @@ -15,10 +15,10 @@ package org.hyperledger.besu.ethereum.blockcreation; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import org.hyperledger.besu.config.GenesisConfigFile; @@ -26,30 +26,36 @@ import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.GasLimitCalculator; -import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.ProtocolContext; +import org.hyperledger.besu.ethereum.chain.DefaultBlockchain; +import org.hyperledger.besu.ethereum.chain.GenesisState; +import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.AddressHelpers; +import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; -import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.difficulty.fixed.FixedDifficultyProtocolSchedule; -import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; -import org.hyperledger.besu.ethereum.eth.transactions.sorter.BaseFeePendingTransactionsSorter; +import org.hyperledger.besu.ethereum.eth.manager.EthContext; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; -import org.hyperledger.besu.ethereum.referencetests.ReferenceTestBlockchain; +import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; +import org.hyperledger.besu.ethereum.storage.keyvalue.VariablesKeyValueStorage; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; import org.hyperledger.besu.evm.gascalculator.GasCalculator; import org.hyperledger.besu.evm.gascalculator.LondonGasCalculator; @@ -57,48 +63,92 @@ import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.data.TransactionSelectionResult; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.txselection.TransactionSelectorFactory; -import org.hyperledger.besu.testutil.TestClock; +import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import java.math.BigInteger; import java.time.Instant; -import java.time.ZoneId; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Optional; import com.google.common.collect.Lists; import org.apache.tuweni.bytes.Bytes; -import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Answers; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public abstract class AbstractBlockTransactionSelectorTest { protected static final double MIN_OCCUPANCY_80_PERCENT = 0.8; protected static final double MIN_OCCUPANCY_100_PERCENT = 1; + protected static final BigInteger CHAIN_ID = BigInteger.valueOf(42L); protected static final KeyPair keyPair = SignatureAlgorithmFactory.getInstance().generateKeyPair(); + protected static final Address sender = + Address.extract(Hash.hash(keyPair.getPublicKey().getEncodedBytes())); protected final MetricsSystem metricsSystem = new NoOpMetricsSystem(); - - protected final Blockchain blockchain = new ReferenceTestBlockchain(); - protected PendingTransactions pendingTransactions; + protected GenesisConfigFile genesisConfigFile; + protected MutableBlockchain blockchain; + protected TransactionPool transactionPool; protected MutableWorldState worldState; + protected ProtocolSchedule protocolSchedule; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + protected ProtocolContext protocolContext; + @Mock protected MainnetTransactionProcessor transactionProcessor; + @Mock protected MiningParameters miningParameters; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + protected EthContext ethContext; - @Before + @BeforeEach public void setup() { + genesisConfigFile = getGenesisConfigFile(); + protocolSchedule = createProtocolSchedule(); + final Block genesisBlock = + GenesisState.fromConfig(genesisConfigFile, protocolSchedule).getBlock(); + + blockchain = + DefaultBlockchain.createMutable( + genesisBlock, + new KeyValueStoragePrefixedKeyBlockchainStorage( + new InMemoryKeyValueStorage(), + new VariablesKeyValueStorage(new InMemoryKeyValueStorage()), + new MainnetBlockHeaderFunctions()), + new NoOpMetricsSystem(), + 0); + + when(protocolContext.getBlockchain()).thenReturn(blockchain); + worldState = InMemoryKeyValueStorageProvider.createInMemoryWorldState(); - pendingTransactions = createPendingTransactions(); + final var worldStateUpdater = worldState.updater(); + worldStateUpdater.createAccount(sender, 0, Wei.of(1_000_000_000L)); + worldStateUpdater.commit(); + + when(protocolContext.getWorldStateArchive().getMutable(any(), anyBoolean())) + .thenReturn(Optional.of(worldState)); + when(ethContext.getEthPeers().subscribeConnect(any())).thenReturn(1L); + when(miningParameters.getMinTransactionGasPrice()).thenReturn(Wei.ONE); + + transactionPool = createTransactionPool(); } - protected abstract PendingTransactions createPendingTransactions(); + protected abstract GenesisConfigFile getGenesisConfigFile(); + + protected abstract ProtocolSchedule createProtocolSchedule(); + + protected abstract TransactionPool createTransactionPool(); private Boolean isCancelled() { return false; @@ -129,7 +179,7 @@ public void emptyPendingTransactionsResultsInEmptyVettingResult() { protocolSchedule.getByBlockHeader(blockHeader(0)).getTransactionProcessor(); // The block should fit 5 transactions only - final ProcessableBlockHeader blockHeader = createBlock(5000); + final ProcessableBlockHeader blockHeader = createBlock(500_000); final Address miningBeneficiary = AddressHelpers.ofValue(1); @@ -145,20 +195,20 @@ public void emptyPendingTransactionsResultsInEmptyVettingResult() { final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); - assertThat(results.getTransactions().size()).isEqualTo(0); - assertThat(results.getReceipts().size()).isEqualTo(0); + assertThat(results.getSelectedTransactions()).isEmpty(); + assertThat(results.getNotSelectedTransactions()).isEmpty(); + assertThat(results.getReceipts()).isEmpty(); assertThat(results.getCumulativeGasUsed()).isEqualTo(0); } @Test - public void failedTransactionsAreIncludedInTheBlock() { - final Transaction transaction = createTransaction(1); - pendingTransactions.addRemoteTransaction(transaction, Optional.empty()); + public void validPendingTransactionIsIncludedInTheBlock() { + final Transaction transaction = createTransaction(1, Wei.of(7L), 100_000); + transactionPool.addRemoteTransactions(List.of(transaction)); ensureTransactionIsValid(transaction, 0, 5); - // The block should fit 3 transactions only - final ProcessableBlockHeader blockHeader = createBlock(5000); + final ProcessableBlockHeader blockHeader = createBlock(500_000); final Address miningBeneficiary = AddressHelpers.ofValue(1); @@ -174,28 +224,28 @@ public void failedTransactionsAreIncludedInTheBlock() { final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); - assertThat(results.getTransactions().size()).isEqualTo(1); - Assertions.assertThat(results.getTransactions()).contains(transaction); + assertThat(results.getSelectedTransactions()).containsExactly(transaction); + assertThat(results.getNotSelectedTransactions()).isEmpty(); assertThat(results.getReceipts().size()).isEqualTo(1); - assertThat(results.getCumulativeGasUsed()).isEqualTo(95L); + assertThat(results.getCumulativeGasUsed()).isEqualTo(99995L); } @Test - public void invalidTransactionsTransactionProcessingAreSkippedButBlockStillFills() { + public void invalidTransactionsAreSkippedButBlockStillFills() { final List transactionsToInject = Lists.newArrayList(); for (int i = 0; i < 5; i++) { - final Transaction tx = createTransaction(i); + final Transaction tx = createTransaction(i, Wei.of(7), 100_000); transactionsToInject.add(tx); - pendingTransactions.addRemoteTransaction(tx, Optional.empty()); if (i == 1) { - ensureTransactionIsInvalid(tx, TransactionInvalidReason.NONCE_TOO_LOW); + ensureTransactionIsInvalid(tx, TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE); } else { ensureTransactionIsValid(tx); } } + transactionPool.addRemoteTransactions(transactionsToInject); - // The block should fit 3 transactions only - final ProcessableBlockHeader blockHeader = createBlock(5000); + // The block should fit 4 transactions only + final ProcessableBlockHeader blockHeader = createBlock(400_000); final Address miningBeneficiary = AddressHelpers.ofValue(1); @@ -211,24 +261,31 @@ public void invalidTransactionsTransactionProcessingAreSkippedButBlockStillFills final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); - assertThat(results.getTransactions().size()).isEqualTo(4); - assertThat(results.getTransactions().contains(transactionsToInject.get(1))).isFalse(); + final Transaction invalidTx = transactionsToInject.get(1); + + assertThat(results.getNotSelectedTransactions()) + .containsOnly( + entry( + invalidTx, + TransactionSelectionResult.invalid( + TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE.name()))); + assertThat(results.getSelectedTransactions().size()).isEqualTo(4); + assertThat(results.getSelectedTransactions().contains(invalidTx)).isFalse(); assertThat(results.getReceipts().size()).isEqualTo(4); - assertThat(results.getCumulativeGasUsed()).isEqualTo(400); + assertThat(results.getCumulativeGasUsed()).isEqualTo(400_000); } @Test public void subsetOfPendingTransactionsIncludedWhenBlockGasLimitHit() { final List transactionsToInject = Lists.newArrayList(); - // Transactions are reported in reverse order. for (int i = 0; i < 5; i++) { - final Transaction tx = createTransaction(i); + final Transaction tx = createTransaction(i, Wei.of(7), 100_000); transactionsToInject.add(tx); - pendingTransactions.addRemoteTransaction(tx, Optional.empty()); ensureTransactionIsValid(tx); } + transactionPool.addRemoteTransactions(transactionsToInject); - final ProcessableBlockHeader blockHeader = createBlock(301); + final ProcessableBlockHeader blockHeader = createBlock(301_000); final Address miningBeneficiary = AddressHelpers.ofValue(1); @@ -244,89 +301,22 @@ public void subsetOfPendingTransactionsIncludedWhenBlockGasLimitHit() { final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); - assertThat(results.getTransactions().size()).isEqualTo(3); + assertThat(results.getSelectedTransactions().size()).isEqualTo(3); - assertThat(results.getTransactions().containsAll(transactionsToInject.subList(0, 3))).isTrue(); + assertThat(results.getSelectedTransactions().containsAll(transactionsToInject.subList(0, 3))) + .isTrue(); + assertThat(results.getNotSelectedTransactions()) + .containsOnly( + entry( + transactionsToInject.get(3), + TransactionSelectionResult.BLOCK_OCCUPANCY_ABOVE_THRESHOLD)); assertThat(results.getReceipts().size()).isEqualTo(3); - assertThat(results.getCumulativeGasUsed()).isEqualTo(300); + assertThat(results.getCumulativeGasUsed()).isEqualTo(300_000); // Ensure receipts have the correct cumulative gas - Assertions.assertThat(results.getReceipts().get(0).getCumulativeGasUsed()).isEqualTo(100); - Assertions.assertThat(results.getReceipts().get(1).getCumulativeGasUsed()).isEqualTo(200); - Assertions.assertThat(results.getReceipts().get(2).getCumulativeGasUsed()).isEqualTo(300); - } - - @Test - public void useSingleGasSpaceForAllTransactions() { - final ProcessableBlockHeader blockHeader = createBlock(300); - - final Address miningBeneficiary = AddressHelpers.ofValue(1); - final BaseFeePendingTransactionsSorter pendingTransactions1559 = - new BaseFeePendingTransactionsSorter( - ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(5).build(), - TestClock.system(ZoneId.systemDefault()), - metricsSystem, - () -> { - final BlockHeader mockBlockHeader = mock(BlockHeader.class); - when(mockBlockHeader.getBaseFee()).thenReturn(Optional.of(Wei.ONE)); - return mockBlockHeader; - }); - final BlockTransactionSelector selector = - new BlockTransactionSelector( - transactionProcessor, - blockchain, - worldState, - pendingTransactions1559, - blockHeader, - this::createReceipt, - Wei.of(6), - 0.8, - this::isCancelled, - miningBeneficiary, - Wei.ZERO, - FeeMarket.london(0L), - new LondonGasCalculator(), - GasLimitCalculator.constant(), - Optional.empty()); - - // this should fill up all the block space - final Transaction fillingLegacyTx = - Transaction.builder() - .type(TransactionType.FRONTIER) - .gasLimit(300) - .gasPrice(Wei.of(10)) - .nonce(1) - .payload(Bytes.EMPTY) - .to(Address.ID) - .value(Wei.ZERO) - .sender(Address.ID) - .chainId(BigInteger.ONE) - .signAndBuild(keyPair); - - ensureTransactionIsValid(fillingLegacyTx); - - // so we shouldn't include this - final Transaction extraEIP1559Tx = - Transaction.builder() - .type(TransactionType.EIP1559) - .nonce(0) - .maxPriorityFeePerGas(Wei.of(10)) - .maxFeePerGas(Wei.of(10)) - .gasLimit(50) - .to(Address.ID) - .value(Wei.of(0)) - .payload(Bytes.EMPTY) - .chainId(BigInteger.ONE) - .signAndBuild(keyPair); - - ensureTransactionIsValid(extraEIP1559Tx); - - pendingTransactions1559.addRemoteTransaction(fillingLegacyTx, Optional.empty()); - pendingTransactions1559.addRemoteTransaction(extraEIP1559Tx, Optional.empty()); - final BlockTransactionSelector.TransactionSelectionResults results = - selector.buildTransactionListForBlock(); - - assertThat(results.getTransactions().size()).isEqualTo(1); + assertThat(results.getReceipts().get(0).getCumulativeGasUsed()).isEqualTo(100_000); + assertThat(results.getReceipts().get(1).getCumulativeGasUsed()).isEqualTo(200_000); + assertThat(results.getReceipts().get(2).getCumulativeGasUsed()).isEqualTo(300_000); } @Test @@ -343,40 +333,32 @@ public void transactionTooLargeForBlockDoesNotPreventMoreBeingAddedIfBlockOccupa Wei.ZERO, MIN_OCCUPANCY_80_PERCENT); - final TransactionTestFixture txTestFixture = new TransactionTestFixture(); // Add 3 transactions to the Pending Transactions, 79% of block, 100% of block and 10% of block // should end up selecting the first and third only. // NOTE - PendingTransactions outputs these in nonce order - final List transactionsToInject = Lists.newArrayList(); - transactionsToInject.add( - txTestFixture - .gasLimit((long) (blockHeader.getGasLimit() * 0.79)) - .nonce(1) - .createTransaction(keyPair)); - transactionsToInject.add( - txTestFixture.gasLimit(blockHeader.getGasLimit()).nonce(2).createTransaction(keyPair)); - transactionsToInject.add( - txTestFixture - .gasLimit((long) (blockHeader.getGasLimit() * 0.1)) - .nonce(3) - .createTransaction(keyPair)); + final Transaction[] txs = + new Transaction[] { + createTransaction(1, Wei.of(10), (long) (blockHeader.getGasLimit() * 0.79)), + createTransaction(2, Wei.of(10), blockHeader.getGasLimit()), + createTransaction(3, Wei.of(10), (long) (blockHeader.getGasLimit() * 0.1)) + }; - for (final Transaction tx : transactionsToInject) { - pendingTransactions.addRemoteTransaction(tx, Optional.empty()); + for (final Transaction tx : txs) { ensureTransactionIsValid(tx); } + transactionPool.addRemoteTransactions(Arrays.stream(txs).toList()); final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); - assertThat(results.getTransactions().size()).isEqualTo(2); - Assertions.assertThat(results.getTransactions().get(0)).isEqualTo(transactionsToInject.get(0)); - Assertions.assertThat(results.getTransactions().get(1)).isEqualTo(transactionsToInject.get(2)); + assertThat(results.getSelectedTransactions()).containsExactly(txs[0], txs[2]); + assertThat(results.getNotSelectedTransactions()) + .containsOnly(entry(txs[1], TransactionSelectionResult.TX_TOO_LARGE_FOR_REMAINING_GAS)); } @Test public void transactionSelectionStopsWhenSufficientBlockOccupancyIsReached() { - final ProcessableBlockHeader blockHeader = createBlock(300); + final ProcessableBlockHeader blockHeader = createBlock(300_000); final Address miningBeneficiary = AddressHelpers.ofValue(1); final BlockTransactionSelector selector = @@ -388,44 +370,29 @@ public void transactionSelectionStopsWhenSufficientBlockOccupancyIsReached() { Wei.ZERO, MIN_OCCUPANCY_80_PERCENT); - final TransactionTestFixture txTestFixture = new TransactionTestFixture(); // Add 4 transactions to the Pending Transactions 15% (ok), 79% (ok), 25% (too large), 10% // (not included, it would fit, however previous transaction was too large and block was // suitably populated). // NOTE - PendingTransactions will output these in nonce order. final Transaction[] txs = new Transaction[] { - txTestFixture - .gasLimit((long) (blockHeader.getGasLimit() * 0.15)) - .nonce(1) - .createTransaction(keyPair), - txTestFixture - .gasLimit((long) (blockHeader.getGasLimit() * 0.79)) - .nonce(2) - .createTransaction(keyPair), - txTestFixture - .gasLimit((long) (blockHeader.getGasLimit() * 0.25)) - .nonce(3) - .createTransaction(keyPair), - txTestFixture - .gasLimit((long) (blockHeader.getGasLimit() * 0.1)) - .nonce(4) - .createTransaction(keyPair) + createTransaction(0, Wei.of(10), (long) (blockHeader.getGasLimit() * 0.15)), + createTransaction(1, Wei.of(10), (long) (blockHeader.getGasLimit() * 0.79)), + createTransaction(2, Wei.of(10), (long) (blockHeader.getGasLimit() * 0.25)), + createTransaction(3, Wei.of(10), (long) (blockHeader.getGasLimit() * 0.1)) }; for (Transaction tx : txs) { - pendingTransactions.addRemoteTransaction(tx, Optional.empty()); ensureTransactionIsValid(tx); } + transactionPool.addRemoteTransactions(Arrays.stream(txs).toList()); final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); - assertThat(results.getTransactions().size()).isEqualTo(2); - Assertions.assertThat(results.getTransactions().get(0)).isEqualTo(txs[0]); - Assertions.assertThat(results.getTransactions().get(1)).isEqualTo(txs[1]); - assertThat(results.getTransactions().contains(txs[3])).isFalse(); - assertThat(results.getTransactions().contains(txs[2])).isFalse(); + assertThat(results.getSelectedTransactions()).containsExactly(txs[0], txs[1]); + assertThat(results.getNotSelectedTransactions()) + .containsOnly(entry(txs[2], TransactionSelectionResult.BLOCK_OCCUPANCY_ABOVE_THRESHOLD)); } @Test @@ -458,25 +425,32 @@ public void transactionSelectionStopsWhenBlockIsFull() { final long gasLimit3 = minTxGasCost; final long gasLimit4 = minTxGasCost; - final TransactionTestFixture txTestFixture = new TransactionTestFixture(); final List transactionsToInject = Lists.newArrayList(); - transactionsToInject.add(txTestFixture.gasLimit(gasLimit0).nonce(0).createTransaction(keyPair)); - transactionsToInject.add(txTestFixture.gasLimit(gasLimit1).nonce(1).createTransaction(keyPair)); - transactionsToInject.add(txTestFixture.gasLimit(gasLimit2).nonce(2).createTransaction(keyPair)); - transactionsToInject.add(txTestFixture.gasLimit(gasLimit3).nonce(3).createTransaction(keyPair)); - transactionsToInject.add(txTestFixture.gasLimit(gasLimit4).nonce(4).createTransaction(keyPair)); + transactionsToInject.add(createTransaction(0, Wei.of(7), gasLimit0)); + transactionsToInject.add(createTransaction(1, Wei.of(7), gasLimit1)); + transactionsToInject.add(createTransaction(2, Wei.of(7), gasLimit2)); + transactionsToInject.add(createTransaction(3, Wei.of(7), gasLimit3)); + transactionsToInject.add(createTransaction(4, Wei.of(7), gasLimit4)); for (final Transaction tx : transactionsToInject) { - pendingTransactions.addRemoteTransaction(tx, Optional.empty()); ensureTransactionIsValid(tx); } + transactionPool.addRemoteTransactions(transactionsToInject); final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); - assertThat(results.getTransactions()) + assertThat(results.getSelectedTransactions()) .containsExactly( transactionsToInject.get(0), transactionsToInject.get(2), transactionsToInject.get(3)); + assertThat(results.getNotSelectedTransactions()) + .containsOnly( + entry( + transactionsToInject.get(1), + TransactionSelectionResult.TX_TOO_LARGE_FOR_REMAINING_GAS), + entry( + transactionsToInject.get(4), + TransactionSelectionResult.BLOCK_OCCUPANCY_ABOVE_THRESHOLD)); assertThat(results.getCumulativeGasUsed()).isEqualTo(blockHeader.getGasLimit()); } @@ -508,29 +482,34 @@ public void transactionSelectionStopsWhenRemainingGasIsNotEnoughForAnyMoreTransa final long gasLimit2 = blockHeader.getGasLimit() - gasLimit0 - (minTxGasCost - 1); final long gasLimit3 = minTxGasCost; - final TransactionTestFixture txTestFixture = new TransactionTestFixture(); final List transactionsToInject = Lists.newArrayList(); - transactionsToInject.add(txTestFixture.gasLimit(gasLimit0).nonce(0).createTransaction(keyPair)); - transactionsToInject.add(txTestFixture.gasLimit(gasLimit1).nonce(1).createTransaction(keyPair)); - transactionsToInject.add(txTestFixture.gasLimit(gasLimit2).nonce(2).createTransaction(keyPair)); - transactionsToInject.add(txTestFixture.gasLimit(gasLimit3).nonce(3).createTransaction(keyPair)); + transactionsToInject.add(createTransaction(0, Wei.of(10), gasLimit0)); + transactionsToInject.add(createTransaction(1, Wei.of(10), gasLimit1)); + transactionsToInject.add(createTransaction(2, Wei.of(10), gasLimit2)); + transactionsToInject.add(createTransaction(3, Wei.of(10), gasLimit3)); for (final Transaction tx : transactionsToInject) { - pendingTransactions.addRemoteTransaction(tx, Optional.empty()); ensureTransactionIsValid(tx); } + transactionPool.addRemoteTransactions(transactionsToInject); final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); - assertThat(results.getTransactions()) + assertThat(results.getSelectedTransactions()) .containsExactly(transactionsToInject.get(0), transactionsToInject.get(2)); + assertThat(results.getNotSelectedTransactions()) + .containsOnly( + entry( + transactionsToInject.get(1), + TransactionSelectionResult.TX_TOO_LARGE_FOR_REMAINING_GAS), + entry(transactionsToInject.get(3), TransactionSelectionResult.BLOCK_FULL)); assertThat(blockHeader.getGasLimit() - results.getCumulativeGasUsed()).isLessThan(minTxGasCost); } @Test public void shouldDiscardTransactionsThatFailValidation() { - final ProcessableBlockHeader blockHeader = createBlock(300); + final ProcessableBlockHeader blockHeader = createBlock(300_000); final Address miningBeneficiary = AddressHelpers.ofValue(1); final BlockTransactionSelector selector = @@ -542,62 +521,51 @@ public void shouldDiscardTransactionsThatFailValidation() { Wei.ZERO, MIN_OCCUPANCY_80_PERCENT); - final TransactionTestFixture txTestFixture = new TransactionTestFixture(); - final Transaction validTransaction = - txTestFixture.nonce(1).gasLimit(1).createTransaction(keyPair); - ensureTransactionIsValid(validTransaction, 2000, 10000); - final Transaction invalidTransaction = - txTestFixture.nonce(2).gasLimit(2).createTransaction(keyPair); + final Transaction validTransaction = createTransaction(0, Wei.of(10), 21_000); + + ensureTransactionIsValid(validTransaction, 21_000, 0); + final Transaction invalidTransaction = createTransaction(3, Wei.of(10), 21_000); ensureTransactionIsInvalid( - invalidTransaction, TransactionInvalidReason.EXCEEDS_BLOCK_GAS_LIMIT); + invalidTransaction, TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE); - pendingTransactions.addRemoteTransaction(validTransaction, Optional.empty()); - pendingTransactions.addRemoteTransaction(invalidTransaction, Optional.empty()); + transactionPool.addRemoteTransactions(List.of(validTransaction, invalidTransaction)); - selector.buildTransactionListForBlock(); + final BlockTransactionSelector.TransactionSelectionResults results = + selector.buildTransactionListForBlock(); - Assertions.assertThat(pendingTransactions.getTransactionByHash(validTransaction.getHash())) - .isPresent(); - Assertions.assertThat(pendingTransactions.getTransactionByHash(invalidTransaction.getHash())) - .isNotPresent(); + assertThat(transactionPool.getTransactionByHash(validTransaction.getHash())).isPresent(); + assertThat(transactionPool.getTransactionByHash(invalidTransaction.getHash())).isNotPresent(); + assertThat(results.getSelectedTransactions()).containsExactly(validTransaction); + assertThat(results.getNotSelectedTransactions()) + .containsOnly( + entry( + invalidTransaction, + TransactionSelectionResult.invalid( + TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE.name()))); } @Test public void transactionSelectionPluginShouldWork() { - final ProcessableBlockHeader blockHeader = createBlock(300); - - final TransactionTestFixture txTestFixture = new TransactionTestFixture(); - final Transaction selected = - txTestFixture - .nonce(1) - .gasLimit(1) - .createTransaction(SignatureAlgorithmFactory.getInstance().generateKeyPair()); - ensureTransactionIsValid(selected, 2000, 10000); - - final Transaction notSelectedTransient = - txTestFixture - .nonce(1) - .gasLimit(1) - .createTransaction(SignatureAlgorithmFactory.getInstance().generateKeyPair()); - ensureTransactionIsValid(notSelectedTransient, 2000, 10000); - - final Transaction notSelectedInvalid = - txTestFixture - .nonce(1) - .gasLimit(1) - .createTransaction(SignatureAlgorithmFactory.getInstance().generateKeyPair()); - ensureTransactionIsValid(notSelectedInvalid, 2000, 10000); + final ProcessableBlockHeader blockHeader = createBlock(300_000); + + final Transaction selected = createTransaction(0, Wei.of(10), 21_000); + ensureTransactionIsValid(selected, 21_000, 0); + + final Transaction notSelectedTransient = createTransaction(1, Wei.of(10), 21_000); + ensureTransactionIsValid(notSelectedTransient, 21_000, 0); + + final Transaction notSelectedInvalid = createTransaction(2, Wei.of(10), 21_000); + ensureTransactionIsValid(notSelectedInvalid, 21_000, 0); final TransactionSelectorFactory transactionSelectorFactory = - (TransactionSelectorFactory) - () -> - (tx, s, logs, cg) -> { - if (tx.equals(notSelectedTransient)) - return TransactionSelectionResult.invalidTransient("transient"); - if (tx.equals(notSelectedInvalid)) - return TransactionSelectionResult.invalid("invalid"); - return TransactionSelectionResult.SELECTED; - }; + () -> + (tx, s, logs, cg) -> { + if (tx.equals(notSelectedTransient)) + return TransactionSelectionResult.invalidTransient("transient"); + if (tx.equals(notSelectedInvalid)) + return TransactionSelectionResult.invalid("invalid"); + return TransactionSelectionResult.SELECTED; + }; final Address miningBeneficiary = AddressHelpers.ofValue(1); final BlockTransactionSelector selector = @@ -610,35 +578,28 @@ public void transactionSelectionPluginShouldWork() { MIN_OCCUPANCY_80_PERCENT, transactionSelectorFactory); - pendingTransactions.addRemoteTransaction(selected, Optional.empty()); - pendingTransactions.addRemoteTransaction(notSelectedTransient, Optional.empty()); - pendingTransactions.addRemoteTransaction(notSelectedInvalid, Optional.empty()); + transactionPool.addRemoteTransactions( + List.of(selected, notSelectedInvalid, notSelectedTransient)); final BlockTransactionSelector.TransactionSelectionResults transactionSelectionResults = selector.buildTransactionListForBlock(); - Assertions.assertThat(pendingTransactions.getTransactionByHash(notSelectedTransient.getHash())) - .isPresent(); - Assertions.assertThat(pendingTransactions.getTransactionByHash(notSelectedInvalid.getHash())) - .isNotPresent(); - // Assertions.assertThat(pendingTransactions.getTransactionByHash(selected.getHash())) - // .isNotPresent(); // TODO check with Fabio what should happen with selected txs - Assertions.assertThat(transactionSelectionResults.getTransactions()).contains(selected); - Assertions.assertThat(transactionSelectionResults.getTransactions()) - .doesNotContain(notSelectedTransient); - Assertions.assertThat(transactionSelectionResults.getTransactions()) - .doesNotContain(notSelectedInvalid); + assertThat(transactionPool.getTransactionByHash(notSelectedTransient.getHash())).isPresent(); + assertThat(transactionPool.getTransactionByHash(notSelectedInvalid.getHash())).isNotPresent(); + assertThat(transactionSelectionResults.getSelectedTransactions()).containsOnly(selected); + assertThat(transactionSelectionResults.getNotSelectedTransactions()) + .containsOnly( + entry(notSelectedTransient, TransactionSelectionResult.invalidTransient("transient")), + entry(notSelectedInvalid, TransactionSelectionResult.invalid("invalid"))); } @Test public void transactionWithIncorrectNonceRemainsInPoolAndNotSelected() { - final ProcessableBlockHeader blockHeader = createBlock(5000); + final ProcessableBlockHeader blockHeader = createBlock(5_000_000); - final TransactionTestFixture txTestFixture = new TransactionTestFixture(); - final Transaction futureTransaction = - txTestFixture.nonce(4).gasLimit(1).createTransaction(keyPair); + final Transaction futureTransaction = createTransaction(4, Wei.of(10), 100_000); - pendingTransactions.addRemoteTransaction(futureTransaction, Optional.empty()); + transactionPool.addRemoteTransactions(List.of(futureTransaction)); ensureTransactionIsInvalid(futureTransaction, TransactionInvalidReason.NONCE_TOO_HIGH); final Address miningBeneficiary = AddressHelpers.ofValue(1); @@ -654,9 +615,14 @@ public void transactionWithIncorrectNonceRemainsInPoolAndNotSelected() { final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); - Assertions.assertThat(pendingTransactions.getTransactionByHash(futureTransaction.getHash())) - .isPresent(); - assertThat(results.getTransactions().size()).isEqualTo(0); + assertThat(transactionPool.getTransactionByHash(futureTransaction.getHash())).isPresent(); + assertThat(results.getSelectedTransactions()).isEmpty(); + assertThat(results.getNotSelectedTransactions()) + .containsOnly( + entry( + futureTransaction, + TransactionSelectionResult.invalidTransient( + TransactionInvalidReason.NONCE_TOO_HIGH.name()))); } protected BlockTransactionSelector createBlockSelector( @@ -664,21 +630,21 @@ protected BlockTransactionSelector createBlockSelector( final ProcessableBlockHeader blockHeader, final Wei minGasPrice, final Address miningBeneficiary, - final Wei dataGasPrice, + final Wei blobGasPrice, final double minBlockOccupancyRatio) { final BlockTransactionSelector selector = new BlockTransactionSelector( transactionProcessor, blockchain, worldState, - pendingTransactions, + transactionPool, blockHeader, this::createReceipt, minGasPrice, minBlockOccupancyRatio, this::isCancelled, miningBeneficiary, - dataGasPrice, + blobGasPrice, getFeeMarket(), new LondonGasCalculator(), GasLimitCalculator.constant(), @@ -692,7 +658,7 @@ protected BlockTransactionSelector createBlockSelectorWithTxSelPlugin( final ProcessableBlockHeader blockHeader, final Wei minGasPrice, final Address miningBeneficiary, - final Wei dataGasPrice, + final Wei blobGasPrice, final double minBlockOccupancyRatio, final TransactionSelectorFactory transactionSelectorFactory) { final BlockTransactionSelector selector = @@ -700,14 +666,14 @@ protected BlockTransactionSelector createBlockSelectorWithTxSelPlugin( transactionProcessor, blockchain, worldState, - pendingTransactions, + transactionPool, blockHeader, this::createReceipt, minGasPrice, minBlockOccupancyRatio, this::isCancelled, miningBeneficiary, - dataGasPrice, + blobGasPrice, getFeeMarket(), new LondonGasCalculator(), GasLimitCalculator.constant(), @@ -716,24 +682,48 @@ protected BlockTransactionSelector createBlockSelectorWithTxSelPlugin( return selector; } - protected abstract GasCalculator getGasCalculator(); + protected GasCalculator getGasCalculator() { + return protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()).getGasCalculator(); + } - protected abstract FeeMarket getFeeMarket(); + protected FeeMarket getFeeMarket() { + return protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()).getFeeMarket(); + } - private Transaction createTransaction(final int transactionNumber) { + protected Transaction createTransaction( + final int nonce, final Wei gasPrice, final long gasLimit) { return Transaction.builder() - .gasLimit(100) - .gasPrice(Wei.of(5)) - .nonce(transactionNumber) + .gasLimit(gasLimit) + .gasPrice(gasPrice) + .nonce(nonce) .payload(Bytes.EMPTY) .to(Address.ID) - .value(Wei.of(transactionNumber)) - .sender(Address.ID) - .chainId(BigInteger.ONE) + .value(Wei.of(nonce)) + .sender(sender) + .chainId(CHAIN_ID) .guessType() .signAndBuild(keyPair); } + protected Transaction createEIP1559Transaction( + final int nonce, + final Wei maxFeePerGas, + final Wei maxPriorityFeePerGas, + final long gasLimit) { + return Transaction.builder() + .type(TransactionType.EIP1559) + .gasLimit(gasLimit) + .maxFeePerGas(maxFeePerGas) + .maxPriorityFeePerGas(maxPriorityFeePerGas) + .nonce(nonce) + .payload(Bytes.EMPTY) + .to(Address.ID) + .value(Wei.of(nonce)) + .sender(sender) + .chainId(CHAIN_ID) + .signAndBuild(keyPair); + } + // This is a duplicate of the MainnetProtocolSpec::frontierTransactionReceiptFactory private TransactionReceipt createReceipt( final TransactionType __, diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinatorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinatorTest.java index 623f612fcf4..6d502750d17 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinatorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinatorTest.java @@ -34,8 +34,8 @@ import java.util.Collections; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class AbstractMiningCoordinatorTest { @@ -50,7 +50,7 @@ public class AbstractMiningCoordinatorTest { private final TestMiningCoordinator miningCoordinator = new TestMiningCoordinator(blockchain, minerExecutor, syncState); - @Before + @BeforeEach public void setUp() { when(minerExecutor.startAsyncMining(any(), any(), any())).thenReturn(Optional.of(blockMiner)); } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/BlockMinerTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/BlockMinerTest.java index feb784f89e0..7bd64afe109 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/BlockMinerTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/BlockMinerTest.java @@ -42,7 +42,7 @@ import java.util.function.Function; import com.google.common.collect.Lists; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class BlockMinerTest { diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/DefaultBlockSchedulerTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/DefaultBlockSchedulerTest.java index 8c1d8f38412..0bb0ba1dd1a 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/DefaultBlockSchedulerTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/DefaultBlockSchedulerTest.java @@ -23,7 +23,7 @@ import java.time.Clock; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class DefaultBlockSchedulerTest { diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/HashRateMiningCoordinatorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/HashRateMiningCoordinatorTest.java index dffe653feec..985870c6fba 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/HashRateMiningCoordinatorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/HashRateMiningCoordinatorTest.java @@ -24,23 +24,14 @@ import java.util.Collection; import java.util.UUID; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public class HashRateMiningCoordinatorTest { private final Blockchain blockchain = mock(Blockchain.class); private final SyncState syncState = mock(SyncState.class); private final PoWMinerExecutor minerExecutor = mock(PoWMinerExecutor.class); - private final String id; - private final Long hashRate; - private final Long wantTotalHashrate; - private final int startSealersSize; - private final boolean wantAdded; - @Parameters public static Collection data() { return Arrays.asList( new Object[][] { @@ -51,21 +42,14 @@ public static Collection data() { }); } - public HashRateMiningCoordinatorTest( + @ParameterizedTest + @MethodSource("data") + public void test( final String id, final long hashRate, final long wantTotalHashrate, final int startSealersSize, final boolean wantAdded) { - this.id = id; - this.hashRate = hashRate; - this.startSealersSize = startSealersSize; - this.wantAdded = wantAdded; - this.wantTotalHashrate = wantTotalHashrate; - } - - @Test - public void test() { final PoWMiningCoordinator miningCoordinator = new PoWMiningCoordinator(blockchain, minerExecutor, syncState, 1000, 10); for (int i = 0; i < startSealersSize; i++) { diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/IncrementingNonceGeneratorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/IncrementingNonceGeneratorTest.java index 04b4ae02622..0f4d13bab45 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/IncrementingNonceGeneratorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/IncrementingNonceGeneratorTest.java @@ -16,7 +16,7 @@ import static org.assertj.core.api.Assertions.assertThat; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class IncrementingNonceGeneratorTest { diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java index 195c25b6634..c0e68efd706 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java @@ -14,50 +14,80 @@ */ package org.hyperledger.besu.ethereum.blockcreation; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.config.GenesisConfigFile; +import org.hyperledger.besu.ethereum.core.PrivacyParameters; +import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics; import org.hyperledger.besu.ethereum.eth.transactions.sorter.GasPricePendingTransactionsSorter; -import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; -import org.hyperledger.besu.evm.gascalculator.BerlinGasCalculator; -import org.hyperledger.besu.evm.gascalculator.GasCalculator; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; +import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.testutil.TestClock; import java.time.ZoneId; -import java.util.Optional; +import java.util.function.Function; public class LegacyFeeMarketBlockTransactionSelectorTest extends AbstractBlockTransactionSelectorTest { @Override - protected PendingTransactions createPendingTransactions() { + protected GenesisConfigFile getGenesisConfigFile() { + return GenesisConfigFile.genesisFileFromResources( + "/block-transaction-selector/gas-price-genesis.json"); + } - return new GasPricePendingTransactionsSorter( + @Override + protected ProtocolSchedule createProtocolSchedule() { + return new ProtocolScheduleBuilder( + genesisConfigFile.getConfigOptions(), + CHAIN_ID, + ProtocolSpecAdapters.create(0, Function.identity()), + new PrivacyParameters(), + false, + EvmConfiguration.DEFAULT) + .createProtocolSchedule(); + } + + @Override + protected TransactionPool createTransactionPool() { + final TransactionPoolConfiguration poolConf = ImmutableTransactionPoolConfiguration.builder() .txPoolMaxSize(5) .txPoolLimitByAccountPercentage(1) - .build(), - TestClock.system(ZoneId.systemDefault()), - metricsSystem, - LegacyFeeMarketBlockTransactionSelectorTest::mockBlockHeader); - } + .build(); - private static BlockHeader mockBlockHeader() { - final BlockHeader blockHeader = mock(BlockHeader.class); - when(blockHeader.getBaseFee()).thenReturn(Optional.empty()); - return blockHeader; - } + final PendingTransactions pendingTransactions = + new GasPricePendingTransactionsSorter( + poolConf, + TestClock.system(ZoneId.systemDefault()), + metricsSystem, + blockchain::getChainHeadHeader); - @Override - protected FeeMarket getFeeMarket() { - return FeeMarket.legacy(); - } + final EthContext ethContext = mock(EthContext.class, RETURNS_DEEP_STUBS); + when(ethContext.getEthPeers().subscribeConnect(any())).thenReturn(1L); - @Override - protected GasCalculator getGasCalculator() { - return new BerlinGasCalculator(); + final TransactionPool transactionPool = + new TransactionPool( + () -> pendingTransactions, + protocolSchedule, + protocolContext, + mock(TransactionBroadcaster.class), + ethContext, + miningParameters, + new TransactionPoolMetrics(metricsSystem), + poolConf); + transactionPool.setEnabled(); + return transactionPool; } } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java index 0b4308341ee..82cb1b0d89b 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java @@ -15,66 +15,89 @@ package org.hyperledger.besu.ethereum.blockcreation; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.AddressHelpers; -import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics; import org.hyperledger.besu.ethereum.eth.transactions.sorter.BaseFeePendingTransactionsSorter; -import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; -import org.hyperledger.besu.evm.gascalculator.GasCalculator; -import org.hyperledger.besu.evm.gascalculator.LondonGasCalculator; -import org.hyperledger.besu.plugin.data.TransactionType; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; +import org.hyperledger.besu.ethereum.mainnet.ValidationResult; +import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.plugin.data.TransactionSelectionResult; import org.hyperledger.besu.testutil.TestClock; -import java.math.BigInteger; import java.time.ZoneId; -import java.util.Optional; +import java.util.List; +import java.util.function.Function; -import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class LondonFeeMarketBlockTransactionSelectorTest extends AbstractBlockTransactionSelectorTest { @Override - protected PendingTransactions createPendingTransactions() { - return new BaseFeePendingTransactionsSorter( - ImmutableTransactionPoolConfiguration.builder() - .txPoolMaxSize(5) - .txPoolLimitByAccountPercentage(1) - .build(), - TestClock.system(ZoneId.systemDefault()), - metricsSystem, - LondonFeeMarketBlockTransactionSelectorTest::mockBlockHeader); + protected GenesisConfigFile getGenesisConfigFile() { + return GenesisConfigFile.genesisFileFromResources( + "/block-transaction-selector/london-genesis.json"); } @Override - protected GasCalculator getGasCalculator() { - return new LondonGasCalculator(); - } - - private static BlockHeader mockBlockHeader() { - final BlockHeader blockHeader = mock(BlockHeader.class); - when(blockHeader.getBaseFee()).thenReturn(Optional.of(Wei.ONE)); - return blockHeader; + protected ProtocolSchedule createProtocolSchedule() { + return new ProtocolScheduleBuilder( + genesisConfigFile.getConfigOptions(), + CHAIN_ID, + ProtocolSpecAdapters.create(0, Function.identity()), + new PrivacyParameters(), + false, + EvmConfiguration.DEFAULT) + .createProtocolSchedule(); } @Override - protected FeeMarket getFeeMarket() { - return FeeMarket.london(0L); + protected TransactionPool createTransactionPool() { + final TransactionPoolConfiguration poolConf = + ImmutableTransactionPoolConfiguration.builder() + .txPoolMaxSize(5) + .txPoolLimitByAccountPercentage(1) + .build(); + final PendingTransactions pendingTransactions = + new BaseFeePendingTransactionsSorter( + poolConf, + TestClock.system(ZoneId.systemDefault()), + metricsSystem, + blockchain::getChainHeadHeader); + + final TransactionPool transactionPool = + new TransactionPool( + () -> pendingTransactions, + protocolSchedule, + protocolContext, + mock(TransactionBroadcaster.class), + ethContext, + miningParameters, + new TransactionPoolMetrics(metricsSystem), + poolConf); + transactionPool.setEnabled(); + return transactionPool; } @Test public void eip1559TransactionCurrentGasPriceLessThanMinimumIsSkippedAndKeptInThePool() { - final ProcessableBlockHeader blockHeader = createBlock(301, Wei.ONE); + final ProcessableBlockHeader blockHeader = createBlock(301_000, Wei.ONE); final Address miningBeneficiary = AddressHelpers.ofValue(1); final BlockTransactionSelector selector = @@ -86,21 +109,24 @@ public void eip1559TransactionCurrentGasPriceLessThanMinimumIsSkippedAndKeptInTh Wei.ZERO, MIN_OCCUPANCY_80_PERCENT); - // tx is willing to pay max 6 wei for gas, but current network condition (baseFee == 1) + // tx is willing to pay max 7 wei for gas, but current network condition (baseFee == 1) // result in it paying 2 wei, that is below the minimum accepted by the node, so it is skipped - final Transaction tx = createEIP1559Transaction(1, Wei.of(6L), Wei.ONE); - pendingTransactions.addRemoteTransaction(tx, Optional.empty()); + final Transaction tx = createEIP1559Transaction(1, Wei.of(7L), Wei.ONE, 100_000); + final var addResults = transactionPool.addRemoteTransactions(List.of(tx)); + assertThat(addResults).extractingByKey(tx.getHash()).isEqualTo(ValidationResult.valid()); final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); - assertThat(results.getTransactions().size()).isEqualTo(0); - assertThat(pendingTransactions.size()).isEqualTo(1); + assertThat(results.getSelectedTransactions()).isEmpty(); + assertThat(results.getNotSelectedTransactions()) + .containsOnly(entry(tx, TransactionSelectionResult.CURRENT_TX_PRICE_BELOW_MIN)); + assertThat(transactionPool.count()).isEqualTo(1); } @Test public void eip1559TransactionCurrentGasPriceGreaterThanMinimumIsSelected() { - final ProcessableBlockHeader blockHeader = createBlock(301, Wei.of(5)); + final ProcessableBlockHeader blockHeader = createBlock(301_000, Wei.of(5)); final Address miningBeneficiary = AddressHelpers.ofValue(1); final BlockTransactionSelector selector = @@ -112,23 +138,23 @@ public void eip1559TransactionCurrentGasPriceGreaterThanMinimumIsSelected() { Wei.ZERO, MIN_OCCUPANCY_80_PERCENT); - // tx is willing to pay max 6 wei for gas, and current network condition (baseFee == 5) + // tx is willing to pay max 7 wei for gas, and current network condition (baseFee == 5) // result in it paying the max, that is >= the minimum accepted by the node, so it is selected - final Transaction tx = createEIP1559Transaction(1, Wei.of(6), Wei.ONE); - pendingTransactions.addRemoteTransaction(tx, Optional.empty()); + final Transaction tx = createEIP1559Transaction(1, Wei.of(7), Wei.ONE, 100_000); + transactionPool.addRemoteTransactions(List.of(tx)); ensureTransactionIsValid(tx); final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); - assertThat(results.getTransactions().size()).isEqualTo(1); - assertThat(pendingTransactions.size()).isEqualTo(1); + assertThat(results.getSelectedTransactions()).containsExactly(tx); + assertThat(results.getNotSelectedTransactions()).isEmpty(); } @Test public void eip1559LocalTransactionCurrentGasPriceLessThanMinimumIsSelected() { - final ProcessableBlockHeader blockHeader = createBlock(301, Wei.ONE); + final ProcessableBlockHeader blockHeader = createBlock(301_000, Wei.ONE); final Address miningBeneficiary = AddressHelpers.ofValue(1); final BlockTransactionSelector selector = @@ -140,47 +166,32 @@ public void eip1559LocalTransactionCurrentGasPriceLessThanMinimumIsSelected() { Wei.ZERO, MIN_OCCUPANCY_80_PERCENT); - // tx is willing to pay max 6 wei for gas, but current network condition (baseFee == 1) + // tx is willing to pay max 7 wei for gas, but current network condition (baseFee == 1) // result in it paying 2 wei, that is below the minimum accepted by the node, but since it is // a local sender it is accepted anyway - final Transaction tx = createEIP1559Transaction(1, Wei.of(6L), Wei.ONE); - pendingTransactions.addLocalTransaction(tx, Optional.empty()); + final Transaction tx = createEIP1559Transaction(1, Wei.of(7L), Wei.ONE, 100_000); + final var addResult = transactionPool.addTransactionViaApi(tx); + assertThat(addResult.isValid()).isTrue(); ensureTransactionIsValid(tx); final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); - assertThat(results.getTransactions().size()).isEqualTo(1); - assertThat(pendingTransactions.size()).isEqualTo(1); + assertThat(results.getSelectedTransactions()).containsExactly(tx); + assertThat(results.getNotSelectedTransactions()).isEmpty(); } @Test public void transactionFromSameSenderWithMixedTypes() { - final ProcessableBlockHeader blockHeader = createBlock(5000); - - final TransactionTestFixture txTestFixture = new TransactionTestFixture(); - final Transaction txFrontier1 = - txTestFixture - .type(TransactionType.FRONTIER) - .nonce(0) - .gasLimit(1) - .gasPrice(Wei.ONE) - .createTransaction(keyPair); - final Transaction txLondon1 = createEIP1559Transaction(1, Wei.ONE, Wei.ONE); - final Transaction txFrontier2 = - txTestFixture - .type(TransactionType.FRONTIER) - .nonce(2) - .gasLimit(1) - .gasPrice(Wei.ONE) - .createTransaction(keyPair); - final Transaction txLondon2 = createEIP1559Transaction(3, Wei.ONE, Wei.ONE); - - pendingTransactions.addRemoteTransaction(txFrontier1, Optional.empty()); - pendingTransactions.addRemoteTransaction(txLondon1, Optional.empty()); - pendingTransactions.addRemoteTransaction(txFrontier2, Optional.empty()); - pendingTransactions.addRemoteTransaction(txLondon2, Optional.empty()); + final ProcessableBlockHeader blockHeader = createBlock(5_000_000); + + final Transaction txFrontier1 = createTransaction(0, Wei.of(7L), 100_000); + final Transaction txLondon1 = createEIP1559Transaction(1, Wei.ONE, Wei.ONE, 100_000); + final Transaction txFrontier2 = createTransaction(2, Wei.of(7L), 100_000); + final Transaction txLondon2 = createEIP1559Transaction(3, Wei.ONE, Wei.ONE, 100_000); + + transactionPool.addRemoteTransactions(List.of(txFrontier1, txLondon1, txFrontier2, txLondon2)); ensureTransactionIsValid(txFrontier1); ensureTransactionIsValid(txLondon1); @@ -200,24 +211,8 @@ public void transactionFromSameSenderWithMixedTypes() { final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); - assertThat(results.getTransactions()) + assertThat(results.getSelectedTransactions()) .containsExactly(txFrontier1, txLondon1, txFrontier2, txLondon2); - } - - private Transaction createEIP1559Transaction( - final int transactionNumber, final Wei maxFeePerGas, final Wei maxPriorityFeePerGas) { - return Transaction.builder() - .type(TransactionType.EIP1559) - .gasLimit(100) - .maxFeePerGas(maxFeePerGas) - .maxPriorityFeePerGas(maxPriorityFeePerGas) - .nonce(transactionNumber) - .payload(Bytes.EMPTY) - .to(Address.ID) - .value(Wei.of(transactionNumber)) - .sender(Address.ID) - .chainId(BigInteger.ONE) - .guessType() - .signAndBuild(keyPair); + assertThat(results.getNotSelectedTransactions()).isEmpty(); } } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java index 4cc3d369ca8..af9f5b690a6 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java @@ -15,6 +15,10 @@ package org.hyperledger.besu.ethereum.blockcreation; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.config.GenesisConfigOptions; @@ -27,10 +31,16 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; +import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics; import org.hyperledger.besu.ethereum.eth.transactions.sorter.BaseFeePendingTransactionsSorter; import org.hyperledger.besu.ethereum.mainnet.EpochCalculator; import org.hyperledger.besu.ethereum.mainnet.PoWHasher; @@ -94,19 +104,14 @@ void createMainnetBlock1() throws IOException { 1000, 8); - final BaseFeePendingTransactionsSorter pendingTransactions = - new BaseFeePendingTransactionsSorter( - ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build(), - TestClock.fixed(), - metricsSystem, - executionContextTestFixture.getProtocolContext().getBlockchain()::getChainHeadHeader); + final TransactionPool transactionPool = createTransactionPool(executionContextTestFixture); final PoWBlockCreator blockCreator = new PoWBlockCreator( BLOCK_1_COINBASE, Optional::empty, parent -> BLOCK_1_EXTRA_DATA, - pendingTransactions, + transactionPool, executionContextTestFixture.getProtocolContext(), executionContextTestFixture.getProtocolSchedule(), solver, @@ -155,19 +160,14 @@ void createMainnetBlock1_fixedDifficulty1() { 1000, 8); - final BaseFeePendingTransactionsSorter pendingTransactions = - new BaseFeePendingTransactionsSorter( - ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build(), - TestClock.fixed(), - metricsSystem, - executionContextTestFixture.getProtocolContext().getBlockchain()::getChainHeadHeader); + final TransactionPool transactionPool = createTransactionPool(executionContextTestFixture); final PoWBlockCreator blockCreator = new PoWBlockCreator( BLOCK_1_COINBASE, Optional::empty, parent -> BLOCK_1_EXTRA_DATA, - pendingTransactions, + transactionPool, executionContextTestFixture.getProtocolContext(), executionContextTestFixture.getProtocolSchedule(), solver, @@ -207,19 +207,14 @@ void rewardBeneficiary_zeroReward_skipZeroRewardsFalse() { 1000, 8); - final BaseFeePendingTransactionsSorter pendingTransactions = - new BaseFeePendingTransactionsSorter( - ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build(), - TestClock.fixed(), - metricsSystem, - executionContextTestFixture.getProtocolContext().getBlockchain()::getChainHeadHeader); + final TransactionPool transactionPool = createTransactionPool(executionContextTestFixture); final PoWBlockCreator blockCreator = new PoWBlockCreator( BLOCK_1_COINBASE, () -> Optional.of(10_000_000L), parent -> BLOCK_1_EXTRA_DATA, - pendingTransactions, + transactionPool, executionContextTestFixture.getProtocolContext(), executionContextTestFixture.getProtocolSchedule(), solver, @@ -281,19 +276,14 @@ void rewardBeneficiary_zeroReward_skipZeroRewardsTrue() { 1000, 8); - final BaseFeePendingTransactionsSorter pendingTransactions = - new BaseFeePendingTransactionsSorter( - ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build(), - TestClock.fixed(), - metricsSystem, - executionContextTestFixture.getProtocolContext().getBlockchain()::getChainHeadHeader); + final TransactionPool transactionPool = createTransactionPool(executionContextTestFixture); final PoWBlockCreator blockCreator = new PoWBlockCreator( BLOCK_1_COINBASE, () -> Optional.of(10_000_000L), parent -> BLOCK_1_EXTRA_DATA, - pendingTransactions, + transactionPool, executionContextTestFixture.getProtocolContext(), executionContextTestFixture.getProtocolSchedule(), solver, @@ -326,4 +316,34 @@ void rewardBeneficiary_zeroReward_skipZeroRewardsTrue() { assertThat(mutableWorldState.get(BLOCK_1_COINBASE)).isNull(); } + + private TransactionPool createTransactionPool( + final ExecutionContextTestFixture executionContextTestFixture) { + final TransactionPoolConfiguration poolConf = + ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build(); + + final BaseFeePendingTransactionsSorter pendingTransactions = + new BaseFeePendingTransactionsSorter( + poolConf, + TestClock.fixed(), + metricsSystem, + executionContextTestFixture.getProtocolContext().getBlockchain()::getChainHeadHeader); + + final EthContext ethContext = mock(EthContext.class, RETURNS_DEEP_STUBS); + when(ethContext.getEthPeers().subscribeConnect(any())).thenReturn(1L); + + final TransactionPool transactionPool = + new TransactionPool( + () -> pendingTransactions, + executionContextTestFixture.getProtocolSchedule(), + executionContextTestFixture.getProtocolContext(), + mock(TransactionBroadcaster.class), + ethContext, + mock(MiningParameters.class), + new TransactionPoolMetrics(metricsSystem), + poolConf); + transactionPool.setEnabled(); + + return transactionPool; + } } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutorTest.java index 6c4a9f1b31d..6edc39f333e 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutorTest.java @@ -15,15 +15,24 @@ package org.hyperledger.besu.ethereum.blockcreation; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.MiningParameters; +import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics; import org.hyperledger.besu.ethereum.eth.transactions.sorter.GasPricePendingTransactionsSorter; import org.hyperledger.besu.ethereum.mainnet.EpochCalculator; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.testutil.TestClock; @@ -32,7 +41,7 @@ import java.time.ZoneId; import java.util.Optional; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PoWMinerExecutorTest { private final MetricsSystem metricsSystem = new NoOpMetricsSystem(); @@ -42,18 +51,13 @@ public void startingMiningWithoutCoinbaseThrowsException() { final MiningParameters miningParameters = new MiningParameters.Builder().coinbase(null).minTransactionGasPrice(Wei.of(1000)).build(); - final GasPricePendingTransactionsSorter pendingTransactions = - new GasPricePendingTransactionsSorter( - ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build(), - TestClock.system(ZoneId.systemDefault()), - metricsSystem, - PoWMinerExecutorTest::mockBlockHeader); + final TransactionPool transactionPool = createTransactionPool(miningParameters); final PoWMinerExecutor executor = new PoWMinerExecutor( null, null, - pendingTransactions, + transactionPool, miningParameters, new DefaultBlockScheduler(1, 10, TestClock.fixed()), new EpochCalculator.DefaultEpochCalculator(), @@ -69,18 +73,13 @@ public void startingMiningWithoutCoinbaseThrowsException() { public void settingCoinbaseToNullThrowsException() { final MiningParameters miningParameters = new MiningParameters.Builder().build(); - final GasPricePendingTransactionsSorter pendingTransactions = - new GasPricePendingTransactionsSorter( - ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build(), - TestClock.system(ZoneId.systemDefault()), - metricsSystem, - PoWMinerExecutorTest::mockBlockHeader); + final TransactionPool transactionPool = createTransactionPool(miningParameters); final PoWMinerExecutor executor = new PoWMinerExecutor( null, null, - pendingTransactions, + transactionPool, miningParameters, new DefaultBlockScheduler(1, 10, TestClock.fixed()), new EpochCalculator.DefaultEpochCalculator(), @@ -97,4 +96,32 @@ private static BlockHeader mockBlockHeader() { when(blockHeader.getBaseFee()).thenReturn(Optional.empty()); return blockHeader; } + + private TransactionPool createTransactionPool(final MiningParameters miningParameters) { + final TransactionPoolConfiguration poolConf = + ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build(); + final GasPricePendingTransactionsSorter pendingTransactions = + new GasPricePendingTransactionsSorter( + poolConf, + TestClock.system(ZoneId.systemDefault()), + metricsSystem, + PoWMinerExecutorTest::mockBlockHeader); + + final EthContext ethContext = mock(EthContext.class, RETURNS_DEEP_STUBS); + when(ethContext.getEthPeers().subscribeConnect(any())).thenReturn(1L); + + final TransactionPool transactionPool = + new TransactionPool( + () -> pendingTransactions, + mock(ProtocolSchedule.class), + mock(ProtocolContext.class), + mock(TransactionBroadcaster.class), + ethContext, + miningParameters, + new TransactionPoolMetrics(new NoOpMetricsSystem()), + poolConf); + transactionPool.setEnabled(); + + return transactionPool; + } } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMiningCoordinatorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMiningCoordinatorTest.java index 556c8f72b7e..b60b1f2cd43 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMiningCoordinatorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMiningCoordinatorTest.java @@ -29,8 +29,8 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class PoWMiningCoordinatorTest { @@ -39,7 +39,7 @@ public class PoWMiningCoordinatorTest { private final PoWMinerExecutor executor = mock(PoWMinerExecutor.class); private final PoWBlockMiner miner = mock(PoWBlockMiner.class); - @Before + @BeforeEach public void setUp() { when(syncState.isInSync()).thenReturn(true); } diff --git a/ethereum/blockcreation/src/test/resources/block-transaction-selector/gas-price-genesis.json b/ethereum/blockcreation/src/test/resources/block-transaction-selector/gas-price-genesis.json new file mode 100644 index 00000000000..689b54381cf --- /dev/null +++ b/ethereum/blockcreation/src/test/resources/block-transaction-selector/gas-price-genesis.json @@ -0,0 +1,21 @@ +{ + "config": { + "chainId": 42, + "homesteadBlock": 0, + "daoForkBlock": 0, + "eip150Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0 + }, + "nonce": "0x42", + "timestamp": "0x0", + "extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa", + "gasLimit": "0x989680", + "difficulty": "0x400000000", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000" +} diff --git a/ethereum/blockcreation/src/test/resources/block-transaction-selector/london-genesis.json b/ethereum/blockcreation/src/test/resources/block-transaction-selector/london-genesis.json new file mode 100644 index 00000000000..9d933db4b8e --- /dev/null +++ b/ethereum/blockcreation/src/test/resources/block-transaction-selector/london-genesis.json @@ -0,0 +1,23 @@ +{ + "config": { + "chainId": 42, + "homesteadBlock": 0, + "daoForkBlock": 0, + "eip150Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0 + }, + "nonce": "0x42", + "timestamp": "0x0", + "extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa", + "gasLimit": "0x989680", + "baseFeePerGas": "0x1", + "difficulty": "0x400000000", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000" +} diff --git a/ethereum/core/build.gradle b/ethereum/core/build.gradle index 2804b2648d0..b616413dd22 100644 --- a/ethereum/core/build.gradle +++ b/ethereum/core/build.gradle @@ -54,12 +54,13 @@ dependencies { implementation 'net.java.dev.jna:jna' implementation 'org.apache.commons:commons-lang3' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-concurrent' - implementation 'org.apache.tuweni:tuweni-units' - implementation 'org.apache.tuweni:tuweni-rlp' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-concurrent' + implementation 'io.tmio:tuweni-units' + implementation 'io.tmio:tuweni-rlp' implementation 'org.hyperledger.besu:bls12-381' implementation 'org.immutables:value-annotations' + implementation 'tech.pegasys:jc-kzg-4844' implementation 'io.prometheus:simpleclient_guava' @@ -75,12 +76,10 @@ dependencies { testImplementation project(':testutil') testImplementation project(path: ':plugins:rocksdb') - - testImplementation 'junit:junit' testImplementation 'org.apache.logging.log4j:log4j-core' - testImplementation 'org.apache.tuweni:tuweni-bytes' - testImplementation 'org.apache.tuweni:tuweni-io' - testImplementation 'org.apache.tuweni:tuweni-units' + testImplementation 'io.tmio:tuweni-bytes' + testImplementation 'io.tmio:tuweni-io' + testImplementation 'io.tmio:tuweni-units' testImplementation 'org.assertj:assertj-core' testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.junit.jupiter:junit-jupiter-params' @@ -88,8 +87,6 @@ dependencies { testImplementation 'org.mockito:mockito-junit-jupiter' testImplementation 'org.awaitility:awaitility' - testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' - integrationTestImplementation project(path: ':config', configuration: 'testSupportArtifacts') integrationTestImplementation project(':testutil') @@ -97,6 +94,7 @@ dependencies { integrationTestImplementation 'org.junit.jupiter:junit-jupiter-api' integrationTestImplementation 'org.mockito:mockito-core' integrationTestImplementation 'org.testcontainers:testcontainers' + integrationTestImplementation 'io.tmio:tuweni-bytes' integrationTestRuntimeOnly 'org.junit.jupiter:junit-jupiter' @@ -104,7 +102,7 @@ dependencies { testSupportImplementation project(':ethereum:eth') testSupportImplementation project(':testutil') - testSupportImplementation 'junit:junit' + testSupportImplementation 'org.junit.jupiter:junit-jupiter' testSupportImplementation 'org.assertj:assertj-core' testSupportImplementation 'org.mockito:mockito-core' diff --git a/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/vm/TraceTransactionIntegrationTest.java b/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/vm/TraceTransactionIntegrationTest.java index 53c69b0c1f6..37e6cdddced 100644 --- a/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/vm/TraceTransactionIntegrationTest.java +++ b/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/vm/TraceTransactionIntegrationTest.java @@ -19,6 +19,7 @@ import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Block; @@ -37,7 +38,6 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.List; import java.util.Map; diff --git a/ethereum/core/src/jmh/java/org/hyperledger/besu/ethereum/vm/operations/OperationBenchmarkHelper.java b/ethereum/core/src/jmh/java/org/hyperledger/besu/ethereum/vm/operations/OperationBenchmarkHelper.java index 81796f89f29..8307a8fef4a 100644 --- a/ethereum/core/src/jmh/java/org/hyperledger/besu/ethereum/vm/operations/OperationBenchmarkHelper.java +++ b/ethereum/core/src/jmh/java/org/hyperledger/besu/ethereum/vm/operations/OperationBenchmarkHelper.java @@ -24,16 +24,19 @@ import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture; import org.hyperledger.besu.ethereum.core.MessageFrameTestFixture; +import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier; import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfigurationBuilder; -import org.hyperledger.besu.plugin.services.storage.rocksdb.unsegmented.RocksDBKeyValueStorage; +import org.hyperledger.besu.plugin.services.storage.rocksdb.segmented.OptimisticRocksDBColumnarKeyValueStorage; +import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorageAdapter; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; import com.google.common.io.MoreFiles; import com.google.common.io.RecursiveDeleteOption; @@ -58,12 +61,18 @@ private OperationBenchmarkHelper( public static OperationBenchmarkHelper create() throws IOException { final Path storageDirectory = Files.createTempDirectory("benchmark"); - final KeyValueStorage keyValueStorage = - new RocksDBKeyValueStorage( + final OptimisticRocksDBColumnarKeyValueStorage optimisticRocksDBColumnarKeyValueStorage = + new OptimisticRocksDBColumnarKeyValueStorage( new RocksDBConfigurationBuilder().databaseDir(storageDirectory).build(), + List.of(KeyValueSegmentIdentifier.BLOCKCHAIN), + emptyList(), new NoOpMetricsSystem(), RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); + final KeyValueStorage keyValueStorage = + new SegmentedKeyValueStorageAdapter( + KeyValueSegmentIdentifier.BLOCKCHAIN, optimisticRocksDBColumnarKeyValueStorage); + final ExecutionContextTestFixture executionContext = ExecutionContextTestFixture.builder().blockchainKeyValueStorage(keyValueStorage).build(); final MutableBlockchain blockchain = executionContext.getBlockchain(); @@ -103,25 +112,19 @@ public MessageFrame createMessageFrame() { public MessageFrame.Builder createMessageFrameBuilder() { return MessageFrame.builder() + .parentMessageFrame(messageFrame) .type(MessageFrame.Type.MESSAGE_CALL) - .messageFrameStack(messageFrame.getMessageFrameStack()) .worldUpdater(messageFrame.getWorldUpdater()) .initialGas(messageFrame.getRemainingGas()) .address(messageFrame.getContractAddress()) - .originator(messageFrame.getOriginatorAddress()) .contract(messageFrame.getRecipientAddress()) - .gasPrice(messageFrame.getGasPrice()) .inputData(messageFrame.getInputData()) .sender(messageFrame.getSenderAddress()) .value(messageFrame.getValue()) .apparentValue(messageFrame.getApparentValue()) .code(messageFrame.getCode()) - .blockValues(messageFrame.getBlockValues()) - .depth(messageFrame.getMessageStackDepth()) .isStatic(messageFrame.isStatic()) - .completer(messageFrame -> {}) - .miningBeneficiary(messageFrame.getMiningBeneficiary()) - .maxStackSize(messageFrame.getMaxStackSize()); + .completer(frame -> {}); } public void cleanUp() throws IOException { diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/GasLimitCalculator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/GasLimitCalculator.java index 30a35389afb..3d5375c4012 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/GasLimitCalculator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/GasLimitCalculator.java @@ -16,13 +16,15 @@ public interface GasLimitCalculator { + static final long BLOB_GAS_LIMIT = 786432; + long nextGasLimit(long currentGasLimit, long targetGasLimit, long newBlockNumber); static GasLimitCalculator constant() { return (currentGasLimit, targetGasLimit, newBlockNumber) -> currentGasLimit; } - default long currentDataGasLimit() { - return 0L; + default long currentBlobGasLimit() { + return BLOB_GAS_LIMIT; } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiAccount.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiAccount.java index a7692b48d22..14be477a07d 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiAccount.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiAccount.java @@ -83,7 +83,7 @@ public BonsaiAccount( this( context, address, - Hash.hash(address), + address.addressHash(), stateTrieAccount.getNonce(), stateTrieAccount.getBalance(), stateTrieAccount.getStorageRoot(), @@ -142,7 +142,7 @@ public static BonsaiAccount fromRLP( in.leaveList(); return new BonsaiAccount( - context, address, Hash.hash(address), nonce, balance, storageRoot, codeHash, mutable); + context, address, address.addressHash(), nonce, balance, storageRoot, codeHash, mutable); } @Override diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateProvider.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateProvider.java index b3e7057f80e..986e736745a 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateProvider.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateProvider.java @@ -105,11 +105,11 @@ public BonsaiWorldStateProvider( this.persistedState = new BonsaiWorldState(this, worldStateStorage); this.cachedMerkleTrieLoader = cachedMerkleTrieLoader; blockchain - .getBlockHeader(persistedState.worldStateBlockHash) + .getBlockHeader(persistedState.getWorldStateBlockHash()) .ifPresent( blockHeader -> this.trieLogManager.addCachedLayer( - blockHeader, persistedState.worldStateRootHash, persistedState)); + blockHeader, persistedState.getWorldStateRootHash(), persistedState)); } @VisibleForTesting @@ -124,11 +124,11 @@ public BonsaiWorldStateProvider( this.persistedState = new BonsaiWorldState(this, worldStateStorage); this.cachedMerkleTrieLoader = cachedMerkleTrieLoader; blockchain - .getBlockHeader(persistedState.worldStateBlockHash) + .getBlockHeader(persistedState.getWorldStateBlockHash()) .ifPresent( blockHeader -> this.trieLogManager.addCachedLayer( - blockHeader, persistedState.worldStateRootHash, persistedState)); + blockHeader, persistedState.getWorldStateRootHash(), persistedState)); } @Override @@ -300,7 +300,7 @@ public MutableWorldState getMutable() { public void prepareStateHealing(final Address address, final Bytes location) { final Set keysToDelete = new HashSet<>(); final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updater = worldStateStorage.updater(); - final Hash accountHash = Hash.hash(address); + final Hash accountHash = address.addressHash(); final StoredMerklePatriciaTrie accountTrie = new StoredMerklePatriciaTrie<>( (l, h) -> { @@ -310,7 +310,7 @@ public void prepareStateHealing(final Address address, final Bytes location) { } return node; }, - persistedState.worldStateRootHash, + persistedState.getWorldStateRootHash(), Function.identity(), Function.identity()); try { @@ -359,7 +359,7 @@ public void resetArchiveStateTo(final BlockHeader blockHeader) { persistedState.resetWorldStateTo(blockHeader); this.trieLogManager.reset(); this.trieLogManager.addCachedLayer( - blockHeader, persistedState.worldStateRootHash, persistedState); + blockHeader, persistedState.getWorldStateRootHash(), persistedState); } @Override diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/cache/CachedMerkleTrieLoader.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/cache/CachedMerkleTrieLoader.java index 9dd4955989a..f53342d6317 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/cache/CachedMerkleTrieLoader.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/cache/CachedMerkleTrieLoader.java @@ -52,9 +52,8 @@ public CachedMerkleTrieLoader(final ObservableMetricsSystem metricsSystem) { CacheMetricsCollector cacheMetrics = new CacheMetricsCollector(); cacheMetrics.addCache("accountsNodes", accountNodes); cacheMetrics.addCache("storageNodes", storageNodes); - if (metricsSystem instanceof PrometheusMetricsSystem) - ((PrometheusMetricsSystem) metricsSystem) - .addCollector(BesuMetricCategory.BLOCKCHAIN, () -> cacheMetrics); + if (metricsSystem instanceof PrometheusMetricsSystem prometheusMetricsSystem) + prometheusMetricsSystem.addCollector(BesuMetricCategory.BLOCKCHAIN, () -> cacheMetrics); } public void preLoadAccount( @@ -82,7 +81,7 @@ public void cacheAccountNodes( worldStateRootHash, Function.identity(), Function.identity()); - accountTrie.get(Hash.hash(account)); + accountTrie.get(account.addressHash()); } catch (MerkleTrieException e) { // ignore exception for the cache } finally { @@ -102,7 +101,7 @@ public void cacheStorageNodes( final BonsaiWorldStateKeyValueStorage worldStateStorage, final Address account, final StorageSlotKey slotKey) { - final Hash accountHash = Hash.hash(account); + final Hash accountHash = account.addressHash(); final long storageSubscriberId = worldStateStorage.subscribe(this); try { worldStateStorage diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/cache/CachedWorldStorageManager.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/cache/CachedWorldStorageManager.java index 5ade72748d6..d0f1be97d89 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/cache/CachedWorldStorageManager.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/cache/CachedWorldStorageManager.java @@ -39,7 +39,6 @@ import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; -import java.util.stream.Collectors; import java.util.stream.LongStream; import java.util.stream.Stream; @@ -106,7 +105,7 @@ public synchronized void addCachedLayer( .get() .updateWorldStateStorage( new BonsaiSnapshotWorldStateKeyValueStorage( - forWorldState.worldStateStorage, metricsSystem)); + forWorldState.getWorldStateStorage(), metricsSystem)); } } else { LOG.atDebug() @@ -120,7 +119,7 @@ public synchronized void addCachedLayer( new CachedBonsaiWorldView( blockHeader, new BonsaiSnapshotWorldStateKeyValueStorage( - forWorldState.worldStateStorage, metricsSystem))); + forWorldState.getWorldStateStorage(), metricsSystem))); } else { // otherwise, add the layer to the cache cachedWorldStatesByHash.put( @@ -257,14 +256,12 @@ protected TrieLogFactory setupTrieLogFactory(final BesuContext pluginContext) { TrieLogProvider getTrieLogProvider() { return new TrieLogProvider() { @Override - public > Optional getTrieLogLayer( - final Hash blockHash) { + public Optional getTrieLogLayer(final Hash blockHash) { return CachedWorldStorageManager.this.getTrieLogLayer(blockHash); } @Override - public > Optional getTrieLogLayer( - final long blockNumber) { + public Optional getTrieLogLayer(final long blockNumber) { return CachedWorldStorageManager.this .blockchain .getBlockHeader(blockNumber) @@ -273,7 +270,7 @@ public > Optional getTrieLogLayer( } @Override - public > List getTrieLogsByRange( + public List getTrieLogsByRange( final long fromBlockNumber, final long toBlockNumber) { return rangeAsStream(fromBlockNumber, toBlockNumber) .map(blockchain::getBlockHeader) @@ -289,7 +286,7 @@ public > List getTrieLogsByRang header.getBlockHash(), header.getNumber(), layer)))) .filter(Optional::isPresent) .map(Optional::get) - .collect(Collectors.toList()); + .toList(); } Stream rangeAsStream(final long fromBlockNumber, final long toBlockNumber) { diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiSnapshotWorldStateKeyValueStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiSnapshotWorldStateKeyValueStorage.java index 82d68e0b766..44c79c46b8d 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiSnapshotWorldStateKeyValueStorage.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiSnapshotWorldStateKeyValueStorage.java @@ -42,19 +42,13 @@ public class BonsaiSnapshotWorldStateKeyValueStorage extends BonsaiWorldStateKey public BonsaiSnapshotWorldStateKeyValueStorage( final BonsaiWorldStateKeyValueStorage parentWorldStateStorage, - final SnappedKeyValueStorage accountStorage, - final SnappedKeyValueStorage codeStorage, - final SnappedKeyValueStorage storageStorage, - final SnappedKeyValueStorage trieBranchStorage, + final SnappedKeyValueStorage segmentedWorldStateStorage, final KeyValueStorage trieLogStorage, final ObservableMetricsSystem metricsSystem) { super( parentWorldStateStorage.flatDbMode, parentWorldStateStorage.flatDbReaderStrategy, - accountStorage, - codeStorage, - storageStorage, - trieBranchStorage, + segmentedWorldStateStorage, trieLogStorage, metricsSystem); this.parentWorldStateStorage = parentWorldStateStorage; @@ -66,10 +60,7 @@ public BonsaiSnapshotWorldStateKeyValueStorage( final ObservableMetricsSystem metricsSystem) { this( worldStateStorage, - ((SnappableKeyValueStorage) worldStateStorage.accountStorage).takeSnapshot(), - ((SnappableKeyValueStorage) worldStateStorage.codeStorage).takeSnapshot(), - ((SnappableKeyValueStorage) worldStateStorage.storageStorage).takeSnapshot(), - ((SnappableKeyValueStorage) worldStateStorage.trieBranchStorage).takeSnapshot(), + ((SnappableKeyValueStorage) worldStateStorage.composedWorldStateStorage).takeSnapshot(), worldStateStorage.trieLogStorage, metricsSystem); } @@ -85,10 +76,7 @@ private boolean isClosedGet() { @Override public BonsaiUpdater updater() { return new Updater( - ((SnappedKeyValueStorage) accountStorage).getSnapshotTransaction(), - ((SnappedKeyValueStorage) codeStorage).getSnapshotTransaction(), - ((SnappedKeyValueStorage) storageStorage).getSnapshotTransaction(), - ((SnappedKeyValueStorage) trieBranchStorage).getSnapshotTransaction(), + ((SnappedKeyValueStorage) composedWorldStateStorage).getSnapshotTransaction(), trieLogStorage.startTransaction()); } @@ -107,6 +95,11 @@ public Optional getAccountStateTrieNode(final Bytes location, final Bytes return isClosedGet() ? Optional.empty() : super.getAccountStateTrieNode(location, nodeHash); } + @Override + public Optional getTrieNodeUnsafe(final Bytes key) { + return isClosedGet() ? Optional.empty() : super.getTrieNodeUnsafe(key); + } + @Override public Optional getAccountStorageTrieNode( final Hash accountHash, final Bytes location, final Bytes32 nodeHash) { @@ -223,10 +216,7 @@ protected synchronized void doClose() throws Exception { subscribers.forEach(BonsaiStorageSubscriber::onCloseStorage); // close all of the SnappedKeyValueStorages: - accountStorage.close(); - codeStorage.close(); - storageStorage.close(); - trieBranchStorage.close(); + composedWorldStateStorage.close(); // unsubscribe the parent worldstate parentWorldStateStorage.unSubscribe(subscribeParentId); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiWorldStateKeyValueStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiWorldStateKeyValueStorage.java index 1b8def7fc3d..4ceb63ef219 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiWorldStateKeyValueStorage.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiWorldStateKeyValueStorage.java @@ -14,6 +14,11 @@ */ package org.hyperledger.besu.ethereum.bonsai.storage; +import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE; +import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_STORAGE_STORAGE; +import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.CODE_STORAGE; +import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE; + import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.StorageSlotKey; import org.hyperledger.besu.ethereum.bonsai.storage.flat.FlatDbReaderStrategy; @@ -29,9 +34,12 @@ import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction; import org.hyperledger.besu.util.Subscribers; import java.nio.charset.StandardCharsets; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; @@ -60,10 +68,7 @@ public class BonsaiWorldStateKeyValueStorage implements WorldStateStorage, AutoC protected FlatDbMode flatDbMode; protected FlatDbReaderStrategy flatDbReaderStrategy; - protected final KeyValueStorage accountStorage; - protected final KeyValueStorage codeStorage; - protected final KeyValueStorage storageStorage; - protected final KeyValueStorage trieBranchStorage; + protected final SegmentedKeyValueStorage composedWorldStateStorage; protected final KeyValueStorage trieLogStorage; protected final ObservableMetricsSystem metricsSystem; @@ -76,14 +81,10 @@ public class BonsaiWorldStateKeyValueStorage implements WorldStateStorage, AutoC public BonsaiWorldStateKeyValueStorage( final StorageProvider provider, final ObservableMetricsSystem metricsSystem) { - this.accountStorage = - provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE); - this.codeStorage = - provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.CODE_STORAGE); - this.storageStorage = - provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.ACCOUNT_STORAGE_STORAGE); - this.trieBranchStorage = - provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE); + this.composedWorldStateStorage = + provider.getStorageBySegmentIdentifiers( + List.of( + ACCOUNT_INFO_STATE, CODE_STORAGE, ACCOUNT_STORAGE_STORAGE, TRIE_BRANCH_STORAGE)); this.trieLogStorage = provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.TRIE_LOG_STORAGE); this.metricsSystem = metricsSystem; @@ -93,18 +94,12 @@ public BonsaiWorldStateKeyValueStorage( public BonsaiWorldStateKeyValueStorage( final FlatDbMode flatDbMode, final FlatDbReaderStrategy flatDbReaderStrategy, - final KeyValueStorage accountStorage, - final KeyValueStorage codeStorage, - final KeyValueStorage storageStorage, - final KeyValueStorage trieBranchStorage, + final SegmentedKeyValueStorage composedWorldStateStorage, final KeyValueStorage trieLogStorage, final ObservableMetricsSystem metricsSystem) { this.flatDbMode = flatDbMode; this.flatDbReaderStrategy = flatDbReaderStrategy; - this.accountStorage = accountStorage; - this.codeStorage = codeStorage; - this.storageStorage = storageStorage; - this.trieBranchStorage = trieBranchStorage; + this.composedWorldStateStorage = composedWorldStateStorage; this.trieLogStorage = trieLogStorage; this.metricsSystem = metricsSystem; } @@ -112,8 +107,8 @@ public BonsaiWorldStateKeyValueStorage( public void loadFlatDbStrategy() { this.flatDbMode = FlatDbMode.fromVersion( - trieBranchStorage - .get(FLAT_DB_MODE) + composedWorldStateStorage + .get(TRIE_BRANCH_STORAGE, FLAT_DB_MODE) .map(Bytes::wrap) .orElse( FlatDbMode.PARTIAL @@ -146,7 +141,7 @@ public Optional getCode(final Bytes32 codeHash, final Hash accountHash) { if (codeHash.equals(Hash.EMPTY)) { return Optional.of(Bytes.EMPTY); } else { - return getFlatDbReaderStrategy().getCode(codeHash, accountHash, codeStorage); + return getFlatDbReaderStrategy().getCode(codeHash, accountHash, composedWorldStateStorage); } } @@ -156,7 +151,7 @@ public Optional getAccount(final Hash accountHash) { this::getWorldStateRootHash, this::getAccountStateTrieNode, accountHash, - accountStorage); + composedWorldStateStorage); } @Override @@ -164,39 +159,31 @@ public Optional getAccountStateTrieNode(final Bytes location, final Bytes if (nodeHash.equals(MerkleTrie.EMPTY_TRIE_NODE_HASH)) { return Optional.of(MerkleTrie.EMPTY_TRIE_NODE); } else { - return trieBranchStorage - .get(location.toArrayUnsafe()) + return composedWorldStateStorage + .get(TRIE_BRANCH_STORAGE, location.toArrayUnsafe()) .map(Bytes::wrap) .filter(b -> Hash.hash(b).equals(nodeHash)); } } - /** - * Retrieves the storage trie node associated with the specified account and location, if - * available. - * - * @param accountHash The hash of the account. - * @param location The location within the storage trie. - * @param maybeNodeHash The optional hash of the storage trie node to validate the retrieved data - * against. - * @return The optional bytes of the storage trie node. - */ + @Override public Optional getAccountStorageTrieNode( - final Hash accountHash, final Bytes location, final Optional maybeNodeHash) { - if (maybeNodeHash.filter(hash -> hash.equals(MerkleTrie.EMPTY_TRIE_NODE_HASH)).isPresent()) { + final Hash accountHash, final Bytes location, final Bytes32 nodeHash) { + if (nodeHash.equals(MerkleTrie.EMPTY_TRIE_NODE_HASH)) { return Optional.of(MerkleTrie.EMPTY_TRIE_NODE); } else { - return trieBranchStorage - .get(Bytes.concatenate(accountHash, location).toArrayUnsafe()) + return composedWorldStateStorage + .get(TRIE_BRANCH_STORAGE, Bytes.concatenate(accountHash, location).toArrayUnsafe()) .map(Bytes::wrap) - .filter(data -> maybeNodeHash.map(hash -> Hash.hash(data).equals(hash)).orElse(true)); + .filter(b -> Hash.hash(b).equals(nodeHash)); } } @Override - public Optional getAccountStorageTrieNode( - final Hash accountHash, final Bytes location, final Bytes32 nodeHash) { - return getAccountStorageTrieNode(accountHash, location, Optional.ofNullable(nodeHash)); + public Optional getTrieNodeUnsafe(final Bytes key) { + return composedWorldStateStorage + .get(TRIE_BRANCH_STORAGE, Bytes.concatenate(key).toArrayUnsafe()) + .map(Bytes::wrap); } public Optional getTrieLog(final Hash blockHash) { @@ -204,15 +191,20 @@ public Optional getTrieLog(final Hash blockHash) { } public Optional getStateTrieNode(final Bytes location) { - return trieBranchStorage.get(location.toArrayUnsafe()).map(Bytes::wrap); + return composedWorldStateStorage + .get(TRIE_BRANCH_STORAGE, location.toArrayUnsafe()) + .map(Bytes::wrap); } public Optional getWorldStateRootHash() { - return trieBranchStorage.get(WORLD_ROOT_HASH_KEY).map(Bytes::wrap); + return composedWorldStateStorage.get(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY).map(Bytes::wrap); } public Optional getWorldStateBlockHash() { - return trieBranchStorage.get(WORLD_BLOCK_HASH_KEY).map(Bytes32::wrap).map(Hash::wrap); + return composedWorldStateStorage + .get(TRIE_BRANCH_STORAGE, WORLD_BLOCK_HASH_KEY) + .map(Bytes32::wrap) + .map(Hash::wrap); } public Optional getStorageValueByStorageSlotKey( @@ -240,21 +232,22 @@ public Optional getStorageValueByStorageSlotKey( (location, hash) -> getAccountStorageTrieNode(accountHash, location, hash), accountHash, storageSlotKey, - storageStorage); + composedWorldStateStorage); } @Override public Map streamFlatAccounts( final Bytes startKeyHash, final Bytes32 endKeyHash, final long max) { return getFlatDbReaderStrategy() - .streamAccountFlatDatabase(accountStorage, startKeyHash, endKeyHash, max); + .streamAccountFlatDatabase(composedWorldStateStorage, startKeyHash, endKeyHash, max); } @Override public Map streamFlatStorages( final Hash accountHash, final Bytes startKeyHash, final Bytes32 endKeyHash, final long max) { return getFlatDbReaderStrategy() - .streamStorageFlatDatabase(storageStorage, accountHash, startKeyHash, endKeyHash, max); + .streamStorageFlatDatabase( + composedWorldStateStorage, accountHash, startKeyHash, endKeyHash, max); } @Override @@ -264,23 +257,27 @@ public Optional getNodeData(final Bytes location, final Bytes32 hash) { @Override public boolean isWorldStateAvailable(final Bytes32 rootHash, final Hash blockHash) { - return trieBranchStorage - .get(WORLD_ROOT_HASH_KEY) + return composedWorldStateStorage + .get(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY) .map(Bytes32::wrap) .map(hash -> hash.equals(rootHash) || trieLogStorage.containsKey(blockHash.toArrayUnsafe())) .orElse(false); } public void upgradeToFullFlatDbMode() { - final KeyValueStorageTransaction transaction = trieBranchStorage.startTransaction(); - transaction.put(FLAT_DB_MODE, FlatDbMode.FULL.getVersion().toArrayUnsafe()); + final SegmentedKeyValueStorageTransaction transaction = + composedWorldStateStorage.startTransaction(); + transaction.put( + TRIE_BRANCH_STORAGE, FLAT_DB_MODE, FlatDbMode.FULL.getVersion().toArrayUnsafe()); transaction.commit(); loadFlatDbStrategy(); // force reload of flat db reader strategy } public void downgradeToPartialFlatDbMode() { - final KeyValueStorageTransaction transaction = trieBranchStorage.startTransaction(); - transaction.put(FLAT_DB_MODE, FlatDbMode.PARTIAL.getVersion().toArrayUnsafe()); + final SegmentedKeyValueStorageTransaction transaction = + composedWorldStateStorage.startTransaction(); + transaction.put( + TRIE_BRANCH_STORAGE, FLAT_DB_MODE, FlatDbMode.PARTIAL.getVersion().toArrayUnsafe()); transaction.commit(); loadFlatDbStrategy(); // force reload of flat db reader strategy } @@ -288,8 +285,8 @@ public void downgradeToPartialFlatDbMode() { @Override public void clear() { subscribers.forEach(BonsaiStorageSubscriber::onClearStorage); - getFlatDbReaderStrategy().clearAll(accountStorage, storageStorage, codeStorage); - trieBranchStorage.clear(); + getFlatDbReaderStrategy().clearAll(composedWorldStateStorage); + composedWorldStateStorage.clear(TRIE_BRANCH_STORAGE); trieLogStorage.clear(); loadFlatDbStrategy(); // force reload of flat db reader strategy } @@ -303,17 +300,13 @@ public void clearTrieLog() { @Override public void clearFlatDatabase() { subscribers.forEach(BonsaiStorageSubscriber::onClearFlatDatabaseStorage); - getFlatDbReaderStrategy().resetOnResync(accountStorage, storageStorage); + getFlatDbReaderStrategy().resetOnResync(composedWorldStateStorage); } @Override public BonsaiUpdater updater() { return new Updater( - accountStorage.startTransaction(), - codeStorage.startTransaction(), - storageStorage.startTransaction(), - trieBranchStorage.startTransaction(), - trieLogStorage.startTransaction()); + composedWorldStateStorage.startTransaction(), trieLogStorage.startTransaction()); } @Override @@ -343,36 +336,27 @@ BonsaiUpdater putStorageValueBySlotHash( void removeStorageValueBySlotHash(final Hash accountHash, final Hash slotHash); - KeyValueStorageTransaction getTrieBranchStorageTransaction(); + SegmentedKeyValueStorageTransaction getWorldStateTransaction(); KeyValueStorageTransaction getTrieLogStorageTransaction(); } public static class Updater implements BonsaiUpdater { - private final KeyValueStorageTransaction accountStorageTransaction; - private final KeyValueStorageTransaction codeStorageTransaction; - private final KeyValueStorageTransaction storageStorageTransaction; - private final KeyValueStorageTransaction trieBranchStorageTransaction; + private final SegmentedKeyValueStorageTransaction composedWorldStateTransaction; private final KeyValueStorageTransaction trieLogStorageTransaction; public Updater( - final KeyValueStorageTransaction accountStorageTransaction, - final KeyValueStorageTransaction codeStorageTransaction, - final KeyValueStorageTransaction storageStorageTransaction, - final KeyValueStorageTransaction trieBranchStorageTransaction, + final SegmentedKeyValueStorageTransaction composedWorldStateTransaction, final KeyValueStorageTransaction trieLogStorageTransaction) { - this.accountStorageTransaction = accountStorageTransaction; - this.codeStorageTransaction = codeStorageTransaction; - this.storageStorageTransaction = storageStorageTransaction; - this.trieBranchStorageTransaction = trieBranchStorageTransaction; + this.composedWorldStateTransaction = composedWorldStateTransaction; this.trieLogStorageTransaction = trieLogStorageTransaction; } @Override public BonsaiUpdater removeCode(final Hash accountHash) { - codeStorageTransaction.remove(accountHash.toArrayUnsafe()); + composedWorldStateTransaction.remove(CODE_STORAGE, accountHash.toArrayUnsafe()); return this; } @@ -382,13 +366,14 @@ public BonsaiUpdater putCode(final Hash accountHash, final Bytes32 codeHash, fin // Don't save empty values return this; } - codeStorageTransaction.put(accountHash.toArrayUnsafe(), code.toArrayUnsafe()); + composedWorldStateTransaction.put( + CODE_STORAGE, accountHash.toArrayUnsafe(), code.toArrayUnsafe()); return this; } @Override public BonsaiUpdater removeAccountInfoState(final Hash accountHash) { - accountStorageTransaction.remove(accountHash.toArrayUnsafe()); + composedWorldStateTransaction.remove(ACCOUNT_INFO_STATE, accountHash.toArrayUnsafe()); return this; } @@ -398,16 +383,20 @@ public BonsaiUpdater putAccountInfoState(final Hash accountHash, final Bytes acc // Don't save empty values return this; } - accountStorageTransaction.put(accountHash.toArrayUnsafe(), accountValue.toArrayUnsafe()); + composedWorldStateTransaction.put( + ACCOUNT_INFO_STATE, accountHash.toArrayUnsafe(), accountValue.toArrayUnsafe()); return this; } @Override public WorldStateStorage.Updater saveWorldState( final Bytes blockHash, final Bytes32 nodeHash, final Bytes node) { - trieBranchStorageTransaction.put(Bytes.EMPTY.toArrayUnsafe(), node.toArrayUnsafe()); - trieBranchStorageTransaction.put(WORLD_ROOT_HASH_KEY, nodeHash.toArrayUnsafe()); - trieBranchStorageTransaction.put(WORLD_BLOCK_HASH_KEY, blockHash.toArrayUnsafe()); + composedWorldStateTransaction.put( + TRIE_BRANCH_STORAGE, Bytes.EMPTY.toArrayUnsafe(), node.toArrayUnsafe()); + composedWorldStateTransaction.put( + TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY, nodeHash.toArrayUnsafe()); + composedWorldStateTransaction.put( + TRIE_BRANCH_STORAGE, WORLD_BLOCK_HASH_KEY, blockHash.toArrayUnsafe()); return this; } @@ -418,13 +407,14 @@ public BonsaiUpdater putAccountStateTrieNode( // Don't save empty nodes return this; } - trieBranchStorageTransaction.put(location.toArrayUnsafe(), node.toArrayUnsafe()); + composedWorldStateTransaction.put( + TRIE_BRANCH_STORAGE, location.toArrayUnsafe(), node.toArrayUnsafe()); return this; } @Override public BonsaiUpdater removeAccountStateTrieNode(final Bytes location, final Bytes32 nodeHash) { - trieBranchStorageTransaction.remove(location.toArrayUnsafe()); + composedWorldStateTransaction.remove(TRIE_BRANCH_STORAGE, location.toArrayUnsafe()); return this; } @@ -435,28 +425,33 @@ public synchronized BonsaiUpdater putAccountStorageTrieNode( // Don't save empty nodes return this; } - trieBranchStorageTransaction.put( - Bytes.concatenate(accountHash, location).toArrayUnsafe(), node.toArrayUnsafe()); + composedWorldStateTransaction.put( + TRIE_BRANCH_STORAGE, + Bytes.concatenate(accountHash, location).toArrayUnsafe(), + node.toArrayUnsafe()); return this; } @Override public synchronized BonsaiUpdater putStorageValueBySlotHash( final Hash accountHash, final Hash slotHash, final Bytes storage) { - storageStorageTransaction.put( - Bytes.concatenate(accountHash, slotHash).toArrayUnsafe(), storage.toArrayUnsafe()); + composedWorldStateTransaction.put( + ACCOUNT_STORAGE_STORAGE, + Bytes.concatenate(accountHash, slotHash).toArrayUnsafe(), + storage.toArrayUnsafe()); return this; } @Override public synchronized void removeStorageValueBySlotHash( final Hash accountHash, final Hash slotHash) { - storageStorageTransaction.remove(Bytes.concatenate(accountHash, slotHash).toArrayUnsafe()); + composedWorldStateTransaction.remove( + ACCOUNT_STORAGE_STORAGE, Bytes.concatenate(accountHash, slotHash).toArrayUnsafe()); } @Override - public KeyValueStorageTransaction getTrieBranchStorageTransaction() { - return trieBranchStorageTransaction; + public SegmentedKeyValueStorageTransaction getWorldStateTransaction() { + return composedWorldStateTransaction; } @Override @@ -466,19 +461,14 @@ public KeyValueStorageTransaction getTrieLogStorageTransaction() { @Override public void commit() { - accountStorageTransaction.commit(); - codeStorageTransaction.commit(); - storageStorageTransaction.commit(); - trieBranchStorageTransaction.commit(); + // write the log ahead, then the worldstate trieLogStorageTransaction.commit(); + composedWorldStateTransaction.commit(); } @Override public void rollback() { - accountStorageTransaction.rollback(); - codeStorageTransaction.rollback(); - storageStorageTransaction.rollback(); - trieBranchStorageTransaction.rollback(); + composedWorldStateTransaction.rollback(); trieLogStorageTransaction.rollback(); } } @@ -521,10 +511,7 @@ protected synchronized void doClose() throws Exception { subscribers.forEach(BonsaiStorageSubscriber::onCloseStorage); // close all of the KeyValueStorages: - accountStorage.close(); - codeStorage.close(); - storageStorage.close(); - trieBranchStorage.close(); + composedWorldStateStorage.close(); trieLogStorage.close(); // set storage closed diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiWorldStateLayerStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiWorldStateLayerStorage.java index 2d6a6c407e6..aa96354789a 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiWorldStateLayerStorage.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiWorldStateLayerStorage.java @@ -27,31 +27,18 @@ public class BonsaiWorldStateLayerStorage extends BonsaiSnapshotWorldStateKeyVal public BonsaiWorldStateLayerStorage(final BonsaiWorldStateKeyValueStorage parent) { this( - new LayeredKeyValueStorage(parent.accountStorage), - new LayeredKeyValueStorage(parent.codeStorage), - new LayeredKeyValueStorage(parent.storageStorage), - new LayeredKeyValueStorage(parent.trieBranchStorage), + new LayeredKeyValueStorage(parent.composedWorldStateStorage), parent.trieLogStorage, parent, parent.metricsSystem); } public BonsaiWorldStateLayerStorage( - final SnappedKeyValueStorage accountStorage, - final SnappedKeyValueStorage codeStorage, - final SnappedKeyValueStorage storageStorage, - final SnappedKeyValueStorage trieBranchStorage, + final SnappedKeyValueStorage composedWorldStateStorage, final KeyValueStorage trieLogStorage, final BonsaiWorldStateKeyValueStorage parent, final ObservableMetricsSystem metricsSystem) { - super( - parent, - accountStorage, - codeStorage, - storageStorage, - trieBranchStorage, - trieLogStorage, - metricsSystem); + super(parent, composedWorldStateStorage, trieLogStorage, metricsSystem); } @Override @@ -62,10 +49,7 @@ public FlatDbMode getFlatDbMode() { @Override public BonsaiWorldStateLayerStorage clone() { return new BonsaiWorldStateLayerStorage( - ((LayeredKeyValueStorage) accountStorage).clone(), - ((LayeredKeyValueStorage) codeStorage).clone(), - ((LayeredKeyValueStorage) storageStorage).clone(), - ((LayeredKeyValueStorage) trieBranchStorage).clone(), + ((LayeredKeyValueStorage) composedWorldStateStorage).clone(), trieLogStorage, parentWorldStateStorage, metricsSystem); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/flat/FlatDbReaderStrategy.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/flat/FlatDbReaderStrategy.java index 86e60ae4d6c..1a35dbb93fe 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/flat/FlatDbReaderStrategy.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/flat/FlatDbReaderStrategy.java @@ -15,13 +15,17 @@ */ package org.hyperledger.besu.ethereum.bonsai.storage.flat; +import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE; +import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_STORAGE_STORAGE; +import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.CODE_STORAGE; + import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.StorageSlotKey; import org.hyperledger.besu.ethereum.trie.NodeLoader; import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.metrics.Counter; -import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; import java.util.Map; import java.util.Optional; @@ -84,7 +88,7 @@ public abstract Optional getAccount( Supplier> worldStateRootHashSupplier, NodeLoader nodeLoader, Hash accountHash, - KeyValueStorage accountStorage); + SegmentedKeyValueStorage storage); /* * Retrieves the storage value for the given account hash and storage slot key, using the world state root hash supplier, storage root supplier, and node loader. @@ -96,46 +100,42 @@ public abstract Optional getStorageValueByStorageSlotKey( NodeLoader nodeLoader, Hash accountHash, StorageSlotKey storageSlotKey, - KeyValueStorage storageStorage); + SegmentedKeyValueStorage storageStorage); /* * Retrieves the code data for the given code hash and account hash. */ public Optional getCode( - final Bytes32 codeHash, final Hash accountHash, final KeyValueStorage codeStorage) { + final Bytes32 codeHash, final Hash accountHash, final SegmentedKeyValueStorage storage) { if (codeHash.equals(Hash.EMPTY)) { return Optional.of(Bytes.EMPTY); } else { - return codeStorage - .get(accountHash.toArrayUnsafe()) + return storage + .get(CODE_STORAGE, accountHash.toArrayUnsafe()) .map(Bytes::wrap) .filter(b -> Hash.hash(b).equals(codeHash)); } } - public void clearAll( - final KeyValueStorage accountStorage, - final KeyValueStorage storageStorage, - final KeyValueStorage codeStorage) { - accountStorage.clear(); - storageStorage.clear(); - codeStorage.clear(); + public void clearAll(final SegmentedKeyValueStorage storage) { + storage.clear(ACCOUNT_INFO_STATE); + storage.clear(ACCOUNT_STORAGE_STORAGE); + storage.clear(CODE_STORAGE); } - public void resetOnResync( - final KeyValueStorage accountStorage, final KeyValueStorage storageStorage) { - accountStorage.clear(); - storageStorage.clear(); + public void resetOnResync(final SegmentedKeyValueStorage storage) { + storage.clear(ACCOUNT_INFO_STATE); + storage.clear(ACCOUNT_STORAGE_STORAGE); } public Map streamAccountFlatDatabase( - final KeyValueStorage accountStorage, + final SegmentedKeyValueStorage storage, final Bytes startKeyHash, final Bytes32 endKeyHash, final long max) { final Stream> pairStream = - accountStorage - .streamFromKey(startKeyHash.toArrayUnsafe()) + storage + .streamFromKey(ACCOUNT_INFO_STATE, startKeyHash.toArrayUnsafe()) .limit(max) .map(pair -> new Pair<>(Bytes32.wrap(pair.getKey()), Bytes.wrap(pair.getValue()))) .takeWhile(pair -> pair.getFirst().compareTo(endKeyHash) <= 0); @@ -148,14 +148,16 @@ public Map streamAccountFlatDatabase( } public Map streamStorageFlatDatabase( - final KeyValueStorage storageStorage, + final SegmentedKeyValueStorage storage, final Hash accountHash, final Bytes startKeyHash, final Bytes32 endKeyHash, final long max) { final Stream> pairStream = - storageStorage - .streamFromKey(Bytes.concatenate(accountHash, startKeyHash).toArrayUnsafe()) + storage + .streamFromKey( + ACCOUNT_STORAGE_STORAGE, + Bytes.concatenate(accountHash, startKeyHash).toArrayUnsafe()) .takeWhile(pair -> Bytes.wrap(pair.getKey()).slice(0, Hash.SIZE).equals(accountHash)) .limit(max) .map( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/flat/FullFlatDbReaderStrategy.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/flat/FullFlatDbReaderStrategy.java index e28ead510f1..efce863a802 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/flat/FullFlatDbReaderStrategy.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/flat/FullFlatDbReaderStrategy.java @@ -15,13 +15,16 @@ */ package org.hyperledger.besu.ethereum.bonsai.storage.flat; +import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE; +import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_STORAGE_STORAGE; + import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.StorageSlotKey; import org.hyperledger.besu.ethereum.trie.NodeLoader; import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.metrics.Counter; -import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; import java.util.Optional; import java.util.function.Supplier; @@ -55,10 +58,10 @@ public Optional getAccount( final Supplier> worldStateRootHashSupplier, final NodeLoader nodeLoader, final Hash accountHash, - final KeyValueStorage accountStorage) { + final SegmentedKeyValueStorage storage) { getAccountCounter.inc(); final Optional accountFound = - accountStorage.get(accountHash.toArrayUnsafe()).map(Bytes::wrap); + storage.get(ACCOUNT_INFO_STATE, accountHash.toArrayUnsafe()).map(Bytes::wrap); if (accountFound.isPresent()) { getAccountFoundInFlatDatabaseCounter.inc(); } else { @@ -74,11 +77,13 @@ public Optional getStorageValueByStorageSlotKey( final NodeLoader nodeLoader, final Hash accountHash, final StorageSlotKey storageSlotKey, - final KeyValueStorage storageStorage) { + final SegmentedKeyValueStorage storage) { getStorageValueCounter.inc(); final Optional storageFound = - storageStorage - .get(Bytes.concatenate(accountHash, storageSlotKey.getSlotHash()).toArrayUnsafe()) + storage + .get( + ACCOUNT_STORAGE_STORAGE, + Bytes.concatenate(accountHash, storageSlotKey.getSlotHash()).toArrayUnsafe()) .map(Bytes::wrap); if (storageFound.isPresent()) { getStorageValueFlatDatabaseCounter.inc(); @@ -90,8 +95,7 @@ public Optional getStorageValueByStorageSlotKey( } @Override - public void resetOnResync( - final KeyValueStorage accountStorage, final KeyValueStorage storageStorage) { + public void resetOnResync(final SegmentedKeyValueStorage storage) { // NOOP // not need to reset anything in full mode } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/flat/PartialFlatDbReaderStrategy.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/flat/PartialFlatDbReaderStrategy.java index 8ea0fbcde38..288ff67b095 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/flat/PartialFlatDbReaderStrategy.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/flat/PartialFlatDbReaderStrategy.java @@ -15,6 +15,9 @@ */ package org.hyperledger.besu.ethereum.bonsai.storage.flat; +import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE; +import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_STORAGE_STORAGE; + import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.StorageSlotKey; import org.hyperledger.besu.ethereum.trie.NodeLoader; @@ -23,7 +26,7 @@ import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.metrics.Counter; -import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; import java.util.Optional; import java.util.function.Function; @@ -81,9 +84,10 @@ public Optional getAccount( final Supplier> worldStateRootHashSupplier, final NodeLoader nodeLoader, final Hash accountHash, - final KeyValueStorage accountStorage) { + final SegmentedKeyValueStorage storage) { getAccountCounter.inc(); - Optional response = accountStorage.get(accountHash.toArrayUnsafe()).map(Bytes::wrap); + Optional response = + storage.get(ACCOUNT_INFO_STATE, accountHash.toArrayUnsafe()).map(Bytes::wrap); if (response.isEmpty()) { // after a snapsync/fastsync we only have the trie branches. final Optional worldStateRootHash = worldStateRootHashSupplier.get(); @@ -113,11 +117,13 @@ public Optional getStorageValueByStorageSlotKey( final NodeLoader nodeLoader, final Hash accountHash, final StorageSlotKey storageSlotKey, - final KeyValueStorage storageStorage) { + final SegmentedKeyValueStorage storage) { getStorageValueCounter.inc(); Optional response = - storageStorage - .get(Bytes.concatenate(accountHash, storageSlotKey.getSlotHash()).toArrayUnsafe()) + storage + .get( + ACCOUNT_STORAGE_STORAGE, + Bytes.concatenate(accountHash, storageSlotKey.getSlotHash()).toArrayUnsafe()) .map(Bytes::wrap); if (response.isEmpty()) { final Optional storageRoot = storageRootSupplier.get(); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldState.java index d3f14e8e72e..865471eca99 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldState.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldState.java @@ -19,6 +19,7 @@ import static org.hyperledger.besu.ethereum.bonsai.BonsaiAccount.fromRLP; import static org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage.WORLD_BLOCK_HASH_KEY; import static org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage.WORLD_ROOT_HASH_KEY; +import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; @@ -43,6 +44,8 @@ import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction; +import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction; import java.util.Map; import java.util.Optional; @@ -62,13 +65,13 @@ public class BonsaiWorldState private static final Logger LOG = LoggerFactory.getLogger(BonsaiWorldState.class); - public BonsaiWorldStateKeyValueStorage worldStateStorage; + private BonsaiWorldStateKeyValueStorage worldStateStorage; private final BonsaiWorldStateProvider archive; private final BonsaiWorldStateUpdateAccumulator accumulator; - public Hash worldStateRootHash; - public Hash worldStateBlockHash; + private Hash worldStateRootHash; + Hash worldStateBlockHash; private boolean isFrozen; @@ -109,6 +112,24 @@ public BonsaiWorldState( this.accumulator = updater; } + /** + * Returns the world state block hash of this world state + * + * @return the world state block hash. + */ + public Hash getWorldStateBlockHash() { + return worldStateBlockHash; + } + + /** + * Returns the world state root hash of this world state + * + * @return the world state root hash. + */ + public Hash getWorldStateRootHash() { + return worldStateRootHash; + } + public BonsaiWorldStateProvider getArchive() { return archive; } @@ -124,7 +145,7 @@ private boolean isPersisted(final WorldStateStorage worldStateStorage) { @Override public Optional getCode(@Nonnull final Address address, final Hash codeHash) { - return worldStateStorage.getCode(codeHash, Hash.hash(address)); + return worldStateStorage.getCode(codeHash, address.addressHash()); } /** @@ -179,11 +200,14 @@ private Hash calculateRootHash( // TODO write to a cache and then generate a layer update from that and the // DB tx updates. Right now it is just DB updates. maybeStateUpdater.ifPresent( - bonsaiUpdater -> { - accountTrie.commit( - (location, hash, value) -> - writeTrieNode(bonsaiUpdater.getTrieBranchStorageTransaction(), location, value)); - }); + bonsaiUpdater -> + accountTrie.commit( + (location, hash, value) -> + writeTrieNode( + TRIE_BRANCH_STORAGE, + bonsaiUpdater.getWorldStateTransaction(), + location, + value))); final Bytes32 rootHash = accountTrie.getRootHash(); return Hash.wrap(rootHash); } @@ -227,8 +251,8 @@ private void updateCode( for (final Map.Entry> codeUpdate : worldStateUpdater.getCodeToUpdate().entrySet()) { final Bytes updatedCode = codeUpdate.getValue().getUpdated(); - final Hash accountHash = Hash.hash(codeUpdate.getKey()); - if (updatedCode == null || updatedCode.size() == 0) { + final Hash accountHash = codeUpdate.getKey().addressHash(); + if (updatedCode == null || updatedCode.isEmpty()) { bonsaiUpdater.removeCode(accountHash); } else { bonsaiUpdater.putCode(accountHash, null, updatedCode); @@ -243,7 +267,7 @@ private void updateAccountStorageState( final Map.Entry>> storageAccountUpdate) { final Address updatedAddress = storageAccountUpdate.getKey(); - final Hash updatedAddressHash = Hash.hash(updatedAddress); + final Hash updatedAddressHash = updatedAddress.addressHash(); if (worldStateUpdater.getAccountsToUpdate().containsKey(updatedAddress)) { final BonsaiValue accountValue = worldStateUpdater.getAccountsToUpdate().get(updatedAddress); @@ -290,12 +314,11 @@ private void updateAccountStorageState( final BonsaiAccount accountUpdated = accountValue.getUpdated(); if (accountUpdated != null) { maybeStateUpdater.ifPresent( - bonsaiUpdater -> { - storageTrie.commit( - (location, key, value) -> - writeStorageTrieNode( - bonsaiUpdater, updatedAddressHash, location, key, value)); - }); + bonsaiUpdater -> + storageTrie.commit( + (location, key, value) -> + writeStorageTrieNode( + bonsaiUpdater, updatedAddressHash, location, key, value))); final Hash newStorageRoot = Hash.wrap(storageTrie.getRootHash()); accountUpdated.setStorageRoot(newStorageRoot); } @@ -313,7 +336,7 @@ private void clearStorage( // because we are clearing persisted values we need the account root as persisted final BonsaiAccount oldAccount = worldStateStorage - .getAccount(Hash.hash(address)) + .getAccount(address.addressHash()) .map(bytes -> fromRLP(BonsaiWorldState.this, address, bytes, true)) .orElse(null); if (oldAccount == null) { @@ -321,7 +344,7 @@ private void clearStorage( // block. A not-uncommon DeFi bot pattern. continue; } - final Hash addressHash = Hash.hash(address); + final Hash addressHash = address.addressHash(); final MerkleTrie storageTrie = createTrie( (location, key) -> getStorageTrieNode(addressHash, location, key), @@ -334,7 +357,7 @@ private void clearStorage( .forEach( k -> bonsaiUpdater.removeStorageValueBySlotHash( - Hash.hash(address), Hash.wrap(k))); + address.addressHash(), Hash.wrap(k))); entriesToDelete.keySet().forEach(storageTrie::remove); if (entriesToDelete.size() == 256) { entriesToDelete = storageTrie.entriesFrom(Bytes32.ZERO, 256); @@ -391,17 +414,17 @@ public void persist(final BlockHeader blockHeader) { }; stateUpdater - .getTrieBranchStorageTransaction() - .put(WORLD_BLOCK_HASH_KEY, blockHeader.getHash().toArrayUnsafe()); + .getWorldStateTransaction() + .put(TRIE_BRANCH_STORAGE, WORLD_BLOCK_HASH_KEY, blockHeader.getHash().toArrayUnsafe()); worldStateBlockHash = blockHeader.getHash(); } else { - stateUpdater.getTrieBranchStorageTransaction().remove(WORLD_BLOCK_HASH_KEY); + stateUpdater.getWorldStateTransaction().remove(TRIE_BRANCH_STORAGE, WORLD_BLOCK_HASH_KEY); worldStateBlockHash = null; } stateUpdater - .getTrieBranchStorageTransaction() - .put(WORLD_ROOT_HASH_KEY, newWorldStateRootHash.toArrayUnsafe()); + .getWorldStateTransaction() + .put(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY, newWorldStateRootHash.toArrayUnsafe()); worldStateRootHash = newWorldStateRootHash; success = true; } finally { @@ -454,11 +477,35 @@ public void rollback() { } }; + static final SegmentedKeyValueStorageTransaction noOpSegmentedTx = + new SegmentedKeyValueStorageTransaction() { + + @Override + public void put( + final SegmentIdentifier segmentIdentifier, final byte[] key, final byte[] value) { + // no-op + } + + @Override + public void remove(final SegmentIdentifier segmentIdentifier, final byte[] key) { + // no-op + } + + @Override + public void commit() throws StorageException { + // no-op + } + + @Override + public void rollback() { + // no-op + } + }; + @Override public Hash frontierRootHash() { return calculateRootHash( - Optional.of( - new BonsaiWorldStateKeyValueStorage.Updater(noOpTx, noOpTx, noOpTx, noOpTx, noOpTx)), + Optional.of(new BonsaiWorldStateKeyValueStorage.Updater(noOpSegmentedTx, noOpTx)), accumulator.copy()); } @@ -474,7 +521,7 @@ public Stream streamAccounts(final Bytes32 startKeyHash, fina @Override public Account get(final Address address) { return worldStateStorage - .getAccount(Hash.hash(address)) + .getAccount(address.addressHash()) .map(bytes -> fromRLP(accumulator, address, bytes, true)) .orElse(null); } @@ -484,8 +531,11 @@ protected Optional getAccountStateTrieNode(final Bytes location, final By } private void writeTrieNode( - final KeyValueStorageTransaction tx, final Bytes location, final Bytes value) { - tx.put(location.toArrayUnsafe(), value.toArrayUnsafe()); + final SegmentIdentifier segmentId, + final SegmentedKeyValueStorageTransaction tx, + final Bytes location, + final Bytes value) { + tx.put(segmentId, location.toArrayUnsafe(), value.toArrayUnsafe()); } protected Optional getStorageTrieNode( @@ -512,7 +562,7 @@ public UInt256 getStorageValue(final Address address, final UInt256 storageKey) public Optional getStorageValueByStorageSlotKey( final Address address, final StorageSlotKey storageSlotKey) { return worldStateStorage - .getStorageValueByStorageSlotKey(Hash.hash(address), storageSlotKey) + .getStorageValueByStorageSlotKey(address.addressHash(), storageSlotKey) .map(UInt256::fromBytes); } @@ -521,7 +571,7 @@ public Optional getStorageValueByStorageSlotKey( final Address address, final StorageSlotKey storageSlotKey) { return worldStateStorage - .getStorageValueByStorageSlotKey(storageRootSupplier, Hash.hash(address), storageSlotKey) + .getStorageValueByStorageSlotKey(storageRootSupplier, address.addressHash(), storageSlotKey) .map(UInt256::fromBytes); } @@ -534,7 +584,7 @@ public UInt256 getPriorStorageValue(final Address address, final UInt256 storage public Map getAllAccountStorage(final Address address, final Hash rootHash) { final StoredMerklePatriciaTrie storageTrie = createTrie( - (location, key) -> getStorageTrieNode(Hash.hash(address), location, key), rootHash); + (location, key) -> getStorageTrieNode(address.addressHash(), location, key), rootHash); return storageTrie.entriesFrom(Bytes32.ZERO, Integer.MAX_VALUE); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java index 24ae04037bb..2a04f92fb19 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java @@ -134,7 +134,7 @@ public EvmAccount createAccount(final Address address, final long nonce, final W new BonsaiAccount( this, address, - Hash.hash(address), + address.addressHash(), nonce, balance, Hash.EMPTY_TRIE_HASH, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java index 691a8ab9ee9..9e596ed2db4 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java @@ -19,6 +19,7 @@ import org.hyperledger.besu.config.GenesisAllocation; import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Block; @@ -167,6 +168,8 @@ private static BlockHeader buildHeader( .blockHeaderFunctions(ScheduleBasedBlockHeaderFunctions.create(protocolSchedule)) .baseFee(genesis.getGenesisBaseFeePerGas().orElse(null)) .withdrawalsRoot(isShanghaiAtGenesis(genesis) ? Hash.EMPTY_TRIE_HASH : null) + .blobGasUsed(isCancunAtGenesis(genesis) ? parseBlobGasUsed(genesis) : null) + .excessBlobGas(isCancunAtGenesis(genesis) ? parseExcessBlobGas(genesis) : null) .depositsRoot(isExperimentalEipsTimeAtGenesis(genesis) ? Hash.EMPTY_TRIE_HASH : null) .buildBlockHeader(); } @@ -217,18 +220,38 @@ private static long parseNonce(final GenesisConfigFile genesis) { return withNiceErrorMessage("nonce", genesis.getNonce(), GenesisState::parseUnsignedLong); } + private static long parseBlobGasUsed(final GenesisConfigFile genesis) { + return withNiceErrorMessage( + "blobGasUsed", genesis.getBlobGasUsed(), GenesisState::parseUnsignedLong); + } + + private static BlobGas parseExcessBlobGas(final GenesisConfigFile genesis) { + long excessBlobGas = + withNiceErrorMessage( + "excessBlobGas", genesis.getExcessBlobGas(), GenesisState::parseUnsignedLong); + return BlobGas.of(excessBlobGas); + } + private static long parseUnsignedLong(final String value) { - String nonce = value.toLowerCase(Locale.US); - if (nonce.startsWith("0x")) { - nonce = nonce.substring(2); + String v = value.toLowerCase(Locale.US); + if (v.startsWith("0x")) { + v = v.substring(2); } - return Long.parseUnsignedLong(nonce, 16); + return Long.parseUnsignedLong(v, 16); } private static boolean isShanghaiAtGenesis(final GenesisConfigFile genesis) { final OptionalLong shanghaiTimestamp = genesis.getConfigOptions().getShanghaiTime(); if (shanghaiTimestamp.isPresent()) { - return shanghaiTimestamp.getAsLong() == genesis.getTimestamp(); + return genesis.getTimestamp() >= shanghaiTimestamp.getAsLong(); + } + return false; + } + + private static boolean isCancunAtGenesis(final GenesisConfigFile genesis) { + final OptionalLong cancunTimestamp = genesis.getConfigOptions().getCancunTime(); + if (cancunTimestamp.isPresent()) { + return genesis.getTimestamp() >= cancunTimestamp.getAsLong(); } return false; } @@ -236,7 +259,7 @@ private static boolean isShanghaiAtGenesis(final GenesisConfigFile genesis) { private static boolean isExperimentalEipsTimeAtGenesis(final GenesisConfigFile genesis) { final OptionalLong experimentalEipsTime = genesis.getConfigOptions().getExperimentalEipsTime(); if (experimentalEipsTime.isPresent()) { - return experimentalEipsTime.getAsLong() == genesis.getTimestamp(); + return genesis.getTimestamp() >= experimentalEipsTime.getAsLong(); } return false; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Block.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Block.java index 3abeaebd5cb..32313820cc8 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Block.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Block.java @@ -19,7 +19,9 @@ import org.hyperledger.besu.ethereum.rlp.RLPInput; import org.hyperledger.besu.ethereum.rlp.RLPOutput; +import java.util.List; import java.util.Objects; +import java.util.Optional; import org.apache.tuweni.bytes.Bytes; @@ -57,7 +59,10 @@ public void writeTo(final RLPOutput out) { out.startList(); header.writeTo(out); - body.writeTo(out); + out.writeList(body.getTransactions(), Transaction::writeTo); + out.writeList(body.getOmmers(), BlockHeader::writeTo); + body.getWithdrawals().ifPresent(withdrawals -> out.writeList(withdrawals, Withdrawal::writeTo)); + body.getDeposits().ifPresent(deposits -> out.writeList(deposits, Deposit::writeTo)); out.endList(); } @@ -65,10 +70,15 @@ public void writeTo(final RLPOutput out) { public static Block readFrom(final RLPInput in, final BlockHeaderFunctions hashFunction) { in.enterList(); final BlockHeader header = BlockHeader.readFrom(in, hashFunction); - final BlockBody body = BlockBody.readFrom(in, hashFunction); + final List transactions = in.readList(Transaction::readFrom); + final List ommers = in.readList(rlp -> BlockHeader.readFrom(rlp, hashFunction)); + final Optional> withdrawals = + in.isEndOfCurrentList() ? Optional.empty() : Optional.of(in.readList(Withdrawal::readFrom)); + final Optional> deposits = + in.isEndOfCurrentList() ? Optional.empty() : Optional.of(in.readList(Deposit::readFrom)); in.leaveList(); - return new Block(header, body); + return new Block(header, new BlockBody(transactions, ommers, withdrawals, deposits)); } @Override diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java index 4a20c2de520..94a719fbd0d 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java @@ -15,7 +15,7 @@ package org.hyperledger.besu.ethereum.core; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.DataGas; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.rlp.RLPInput; @@ -62,7 +62,8 @@ public BlockHeader( final Bytes32 mixHashOrPrevRandao, final long nonce, final Hash withdrawalsRoot, - final DataGas excessDataGas, + final long blobGasUsed, + final BlobGas excessBlobGas, final Hash depositsRoot, final BlockHeaderFunctions blockHeaderFunctions, final Optional privateLogsBloom) { @@ -83,7 +84,8 @@ public BlockHeader( baseFee, mixHashOrPrevRandao, withdrawalsRoot, - excessDataGas, + blobGasUsed, + excessBlobGas, depositsRoot); this.nonce = nonce; this.hash = Suppliers.memoize(() -> blockHeaderFunctions.hash(this)); @@ -108,7 +110,8 @@ public BlockHeader( final Bytes32 mixHashOrPrevRandao, final long nonce, final Hash withdrawalsRoot, - final DataGas excessDataGas, + final Long blobGasUsed, + final BlobGas excessBlobGas, final Hash depositsRoot, final BlockHeaderFunctions blockHeaderFunctions) { super( @@ -128,7 +131,8 @@ public BlockHeader( baseFee, mixHashOrPrevRandao, withdrawalsRoot, - excessDataGas, + blobGasUsed, + excessBlobGas, depositsRoot); this.nonce = nonce; this.hash = Suppliers.memoize(() -> blockHeaderFunctions.hash(this)); @@ -212,8 +216,9 @@ public void writeTo(final RLPOutput out) { if (withdrawalsRoot != null) { out.writeBytes(withdrawalsRoot); } - if (excessDataGas != null) { - out.writeUInt256Scalar(excessDataGas); + if (excessBlobGas.isPresent() && blobGasUsed.isPresent()) { + out.writeLongScalar(blobGasUsed.get()); + out.writeUInt64Scalar(excessBlobGas.get()); } if (depositsRoot != null) { out.writeBytes(depositsRoot); @@ -241,9 +246,12 @@ public static BlockHeader readFrom( final long nonce = input.readLong(); final Wei baseFee = !input.isEndOfCurrentList() ? Wei.of(input.readUInt256Scalar()) : null; final Hash withdrawalHashRoot = - !input.isEndOfCurrentList() ? Hash.wrap(input.readBytes32()) : null; - final DataGas excessDataGas = - !input.isEndOfCurrentList() ? DataGas.of(input.readUInt256Scalar()) : null; + !(input.isEndOfCurrentList() || input.isZeroLengthString()) + ? Hash.wrap(input.readBytes32()) + : null; + final Long blobGasUsed = !input.isEndOfCurrentList() ? input.readLongScalar() : null; + final BlobGas excessBlobGas = + !input.isEndOfCurrentList() ? BlobGas.of(input.readLongScalar()) : null; final Hash depositHashRoot = !input.isEndOfCurrentList() ? Hash.wrap(input.readBytes32()) : null; input.leaveList(); @@ -265,7 +273,8 @@ public static BlockHeader readFrom( mixHashOrPrevRandao, nonce, withdrawalHashRoot, - excessDataGas, + blobGasUsed, + excessBlobGas, depositHashRoot, blockHeaderFunctions); } @@ -311,9 +320,8 @@ public String toString() { if (withdrawalsRoot != null) { sb.append("withdrawalsRoot=").append(withdrawalsRoot).append(", "); } - if (excessDataGas != null) { - sb.append("excessDataGas=").append(excessDataGas).append(", "); - } + blobGasUsed.ifPresent(aLong -> sb.append("blobGasUsed=").append(aLong).append(", ")); + excessBlobGas.ifPresent(blobGas -> sb.append("excessBlobGas=").append(blobGas).append(", ")); if (depositsRoot != null) { sb.append("depositsRoot=").append(depositsRoot); } @@ -344,7 +352,8 @@ public static org.hyperledger.besu.ethereum.core.BlockHeader convertPluginBlockH .getWithdrawalsRoot() .map(h -> Hash.fromHexString(h.toHexString())) .orElse(null), - pluginBlockHeader.getExcessDataGas().map(DataGas::fromQuantity).orElse(null), + pluginBlockHeader.getBlobGasUsed().map(Long::longValue).orElse(null), + pluginBlockHeader.getExcessBlobGas().map(BlobGas::fromQuantity).orElse(null), pluginBlockHeader .getDepositsRoot() .map(h -> Hash.fromHexString(h.toHexString())) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java index e670c37221d..04b88464042 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java @@ -19,7 +19,7 @@ import static com.google.common.base.Preconditions.checkState; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.DataGas; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; @@ -73,7 +73,8 @@ public class BlockHeaderBuilder { // instead of an invalid identifier such as -1. private OptionalLong nonce = OptionalLong.empty(); - private DataGas excessDataGas = null; + private Long blobGasUsed = null; + private BlobGas excessBlobGas = null; public static BlockHeaderBuilder create() { return new BlockHeaderBuilder(); @@ -119,7 +120,8 @@ public static BlockHeaderBuilder fromHeader(final BlockHeader header) { .nonce(header.getNonce()) .prevRandao(header.getPrevRandao().orElse(null)) .withdrawalsRoot(header.getWithdrawalsRoot().orElse(null)) - .excessDataGas(header.getExcessDataGas().orElse(null)) + .blobGasUsed(header.getBlobGasUsed().orElse(null)) + .excessBlobGas(header.getExcessBlobGas().orElse(null)) .depositsRoot(header.getDepositsRoot().orElse(null)); } @@ -142,7 +144,7 @@ public static BlockHeaderBuilder fromBuilder(final BlockHeaderBuilder fromBuilde .baseFee(fromBuilder.baseFee) .prevRandao(fromBuilder.mixHashOrPrevRandao) .withdrawalsRoot(fromBuilder.withdrawalsRoot) - .excessDataGas(fromBuilder.excessDataGas) + .excessBlobGas(fromBuilder.excessBlobGas) .depositsRoot(fromBuilder.depositsRoot) .blockHeaderFunctions(fromBuilder.blockHeaderFunctions); toBuilder.nonce = fromBuilder.nonce; @@ -170,7 +172,8 @@ public BlockHeader buildBlockHeader() { mixHashOrPrevRandao, nonce.getAsLong(), withdrawalsRoot, - excessDataGas, + blobGasUsed, + excessBlobGas, depositsRoot, blockHeaderFunctions); } @@ -187,7 +190,8 @@ public ProcessableBlockHeader buildProcessableBlockHeader() { timestamp, baseFee, mixHashOrPrevRandao, - excessDataGas); + blobGasUsed, + excessBlobGas); } public SealableBlockHeader buildSealableBlockHeader() { @@ -210,7 +214,8 @@ public SealableBlockHeader buildSealableBlockHeader() { baseFee, mixHashOrPrevRandao, withdrawalsRoot, - excessDataGas, + blobGasUsed, + excessBlobGas, depositsRoot); } @@ -251,7 +256,8 @@ public BlockHeaderBuilder populateFrom(final ProcessableBlockHeader processableB timestamp(processableBlockHeader.getTimestamp()); baseFee(processableBlockHeader.getBaseFee().orElse(null)); processableBlockHeader.getPrevRandao().ifPresent(this::prevRandao); - processableBlockHeader.getExcessDataGas().ifPresent(this::excessDataGas); + processableBlockHeader.getBlobGasUsed().ifPresent(this::blobGasUsed); + processableBlockHeader.getExcessBlobGas().ifPresent(this::excessBlobGas); return this; } @@ -273,7 +279,8 @@ public BlockHeaderBuilder populateFrom(final SealableBlockHeader sealableBlockHe baseFee(sealableBlockHeader.getBaseFee().orElse(null)); sealableBlockHeader.getPrevRandao().ifPresent(this::prevRandao); withdrawalsRoot(sealableBlockHeader.getWithdrawalsRoot().orElse(null)); - sealableBlockHeader.getExcessDataGas().ifPresent(this::excessDataGas); + sealableBlockHeader.getBlobGasUsed().ifPresent(this::blobGasUsed); + sealableBlockHeader.getExcessBlobGas().ifPresent(this::excessBlobGas); depositsRoot(sealableBlockHeader.getDepositsRoot().orElse(null)); return this; } @@ -395,8 +402,13 @@ public BlockHeaderBuilder depositsRoot(final Hash hash) { return this; } - public BlockHeaderBuilder excessDataGas(final DataGas excessDataGas) { - this.excessDataGas = excessDataGas; + public BlockHeaderBuilder excessBlobGas(final BlobGas excessBlobGas) { + this.excessBlobGas = excessBlobGas; + return this; + } + + public BlockHeaderBuilder blobGasUsed(final Long blobGasUsed) { + this.blobGasUsed = blobGasUsed; return this; } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionFilter.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/PermissionTransactionFilter.java similarity index 88% rename from ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionFilter.java rename to ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/PermissionTransactionFilter.java index ec51812db1a..bb2784e9805 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionFilter.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/PermissionTransactionFilter.java @@ -1,5 +1,6 @@ /* - * Copyright ConsenSys AG. + * + * Copyright Hyperledger Besu Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -11,11 +12,12 @@ * specific language governing permissions and limitations under the License. * * SPDX-License-Identifier: Apache-2.0 + * */ package org.hyperledger.besu.ethereum.core; @FunctionalInterface -public interface TransactionFilter { +public interface PermissionTransactionFilter { boolean permitted( Transaction transaction, boolean checkLocalPermissions, boolean checkOnchainPermissions); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ProcessableBlockHeader.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ProcessableBlockHeader.java index bded52c4c18..ecde436c93d 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ProcessableBlockHeader.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ProcessableBlockHeader.java @@ -15,7 +15,7 @@ package org.hyperledger.besu.ethereum.core; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.DataGas; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.evm.frame.BlockValues; @@ -44,7 +44,10 @@ public class ProcessableBlockHeader implements BlockValues { protected final Wei baseFee; // prevRandao is included for post-merge blocks protected final Bytes32 mixHashOrPrevRandao; - protected final DataGas excessDataGas; + // blobGasUsed is included for Cancun + protected final Optional blobGasUsed; + // excessBlogGas is included for Cancun + protected final Optional excessBlobGas; protected ProcessableBlockHeader( final Hash parentHash, @@ -55,7 +58,8 @@ protected ProcessableBlockHeader( final long timestamp, final Wei baseFee, final Bytes32 mixHashOrPrevRandao, - final DataGas excessDataGas) { + final Long blobGasUsed, + final BlobGas excessBlobGas) { this.parentHash = parentHash; this.coinbase = coinbase; this.difficulty = difficulty; @@ -64,7 +68,8 @@ protected ProcessableBlockHeader( this.timestamp = timestamp; this.baseFee = baseFee; this.mixHashOrPrevRandao = mixHashOrPrevRandao; - this.excessDataGas = excessDataGas; + this.blobGasUsed = Optional.ofNullable(blobGasUsed); + this.excessBlobGas = Optional.ofNullable(excessBlobGas); } /** @@ -163,8 +168,12 @@ public Optional getPrevRandao() { return Optional.ofNullable(mixHashOrPrevRandao); } - public Optional getExcessDataGas() { - return Optional.ofNullable(excessDataGas); + public Optional getExcessBlobGas() { + return excessBlobGas; + } + + public Optional getBlobGasUsed() { + return blobGasUsed; } public String toLogString() { diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SealableBlockHeader.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SealableBlockHeader.java index c742b6ab746..240e8e10dd9 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SealableBlockHeader.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SealableBlockHeader.java @@ -15,7 +15,7 @@ package org.hyperledger.besu.ethereum.core; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.DataGas; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.evm.log.LogsBloomFilter; @@ -62,7 +62,8 @@ protected SealableBlockHeader( final Wei baseFee, final Bytes32 mixHashOrPrevRandao, final Hash withdrawalsRoot, - final DataGas excessDataGas, + final Long blobGasUsed, + final BlobGas excessBlobGas, final Hash depositsRoot) { super( parentHash, @@ -73,7 +74,8 @@ protected SealableBlockHeader( timestamp, baseFee, mixHashOrPrevRandao, - excessDataGas); + blobGasUsed, + excessBlobGas); this.ommersHash = ommersHash; this.stateRoot = stateRoot; this.transactionsRoot = transactionsRoot; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java index 3a444e5528f..c8f3f257dab 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java @@ -17,6 +17,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; import static org.hyperledger.besu.crypto.Hash.keccak256; +import static org.hyperledger.besu.datatypes.VersionedHash.SHA256_VERSION_ID; import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.crypto.SECPPublicKey; @@ -24,9 +25,17 @@ import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Blob; +import org.hyperledger.besu.datatypes.BlobsWithCommitments; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.KZGCommitment; +import org.hyperledger.besu.datatypes.KZGProof; import org.hyperledger.besu.datatypes.Quantity; +import org.hyperledger.besu.datatypes.Sha256Hash; +import org.hyperledger.besu.datatypes.TransactionType; +import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.encoding.BlobTransactionEncoder; import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; @@ -34,7 +43,6 @@ import org.hyperledger.besu.ethereum.rlp.RLPInput; import org.hyperledger.besu.ethereum.rlp.RLPOutput; import org.hyperledger.besu.evm.AccessListEntry; -import org.hyperledger.besu.plugin.data.TransactionType; import java.math.BigInteger; import java.util.Arrays; @@ -52,7 +60,7 @@ /** An operation submitted by an external actor to be applied to the system. */ public class Transaction - implements org.hyperledger.besu.plugin.data.Transaction, + implements org.hyperledger.besu.datatypes.Transaction, org.hyperledger.besu.plugin.data.UnsignedPrivateMarkerTransaction { // Used for transactions that are not tied to a specific chain @@ -75,7 +83,7 @@ public class Transaction private final Optional maxPriorityFeePerGas; private final Optional maxFeePerGas; - private final Optional maxFeePerDataGas; + private final Optional maxFeePerBlobGas; private final long gasLimit; @@ -107,7 +115,9 @@ public class Transaction private final TransactionType transactionType; private final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance(); - private final Optional> versionedHashes; + private final Optional> versionedHashes; + + private final Optional blobsWithCommitments; public static Builder builder() { return new Builder(); @@ -129,7 +139,7 @@ public static Transaction readFrom(final RLPInput rlpInput) { * @param gasPrice the gas price * @param maxPriorityFeePerGas the max priority fee per gas * @param maxFeePerGas the max fee per gas - * @param maxFeePerDataGas the max fee per data gas + * @param maxFeePerBlobGas the max fee per blob gas * @param gasLimit the gas limit * @param to the transaction recipient * @param value the value being transferred to the recipient @@ -150,7 +160,7 @@ public Transaction( final Optional gasPrice, final Optional maxPriorityFeePerGas, final Optional maxFeePerGas, - final Optional maxFeePerDataGas, + final Optional maxFeePerBlobGas, final long gasLimit, final Optional
    to, final Wei value, @@ -159,7 +169,8 @@ public Transaction( final Optional> maybeAccessList, final Address sender, final Optional chainId, - final Optional> versionedHashes) { + final Optional> versionedHashes, + final Optional blobsWithCommitments) { if (transactionType.requiresChainId()) { checkArgument( @@ -177,10 +188,10 @@ public Transaction( maybeAccessList.isPresent(), "Must specify access list for access list transaction"); } - if (versionedHashes.isPresent() || maxFeePerDataGas.isPresent()) { + if (versionedHashes.isPresent() || maxFeePerBlobGas.isPresent()) { checkArgument( transactionType.supportsBlob(), - "Must not specify blob versioned hashes of max fee per data gas for transaction not supporting it"); + "Must not specify blob versioned hashes of max fee per blob gas for transaction not supporting it"); } if (transactionType.supportsBlob()) { @@ -189,7 +200,7 @@ public Transaction( checkArgument( !versionedHashes.get().isEmpty(), "Blob transaction must have at least one blob"); checkArgument( - maxFeePerDataGas.isPresent(), "Must specify max fee per data gas for blob transaction"); + maxFeePerBlobGas.isPresent(), "Must specify max fee per blob gas for blob transaction"); } this.transactionType = transactionType; @@ -197,7 +208,7 @@ public Transaction( this.gasPrice = gasPrice; this.maxPriorityFeePerGas = maxPriorityFeePerGas; this.maxFeePerGas = maxFeePerGas; - this.maxFeePerDataGas = maxFeePerDataGas; + this.maxFeePerBlobGas = maxFeePerBlobGas; this.gasLimit = gasLimit; this.to = to; this.value = value; @@ -207,6 +218,7 @@ public Transaction( this.sender = sender; this.chainId = chainId; this.versionedHashes = versionedHashes; + this.blobsWithCommitments = blobsWithCommitments; if (isUpfrontGasCostTooHigh()) { throw new IllegalArgumentException("Upfront gas cost exceeds UInt256"); @@ -218,7 +230,7 @@ public Transaction( final Optional gasPrice, final Optional maxPriorityFeePerGas, final Optional maxFeePerGas, - final Optional maxFeePerDataGas, + final Optional maxFeePerBlobGas, final long gasLimit, final Optional
    to, final Wei value, @@ -226,14 +238,15 @@ public Transaction( final Bytes payload, final Address sender, final Optional chainId, - final Optional> versionedHashes) { + final Optional> versionedHashes, + final Optional blobsWithCommitments) { this( TransactionType.FRONTIER, nonce, gasPrice, maxPriorityFeePerGas, maxFeePerGas, - maxFeePerDataGas, + maxFeePerBlobGas, gasLimit, to, value, @@ -242,7 +255,8 @@ public Transaction( Optional.empty(), sender, chainId, - versionedHashes); + versionedHashes, + blobsWithCommitments); } public Transaction( @@ -254,7 +268,8 @@ public Transaction( final SECPSignature signature, final Bytes payload, final Optional chainId, - final Optional> versionedHashes) { + final Optional> versionedHashes, + final Optional blobsWithCommitments) { this( TransactionType.FRONTIER, nonce, @@ -270,7 +285,8 @@ public Transaction( Optional.empty(), null, chainId, - versionedHashes); + versionedHashes, + blobsWithCommitments); } /** @@ -300,7 +316,7 @@ public Transaction( final Bytes payload, final Address sender, final Optional chainId, - final Optional> versionedHashes) { + final Optional> versionedHashes) { this( nonce, Optional.of(gasPrice), @@ -314,7 +330,55 @@ public Transaction( payload, sender, chainId, - versionedHashes); + versionedHashes, + Optional.empty()); + } + + /** + * Instantiates a transaction instance. + * + * @param nonce the nonce + * @param gasPrice the gas price + * @param gasLimit the gas limit + * @param to the transaction recipient + * @param value the value being transferred to the recipient + * @param signature the signature + * @param payload the payload + * @param sender the transaction sender + * @param chainId the chain id to apply the transaction to + *

    The {@code to} will be an {@code Optional.empty()} for a contract creation transaction; + * otherwise it should contain an address. + *

    The {@code chainId} must be greater than 0 to be applied to a specific chain; otherwise + * it will default to any chain. + */ + public Transaction( + final long nonce, + final Wei gasPrice, + final long gasLimit, + final Optional

    to, + final Wei value, + final SECPSignature signature, + final Bytes payload, + final Address sender, + final Optional chainId, + final Optional maxFeePerBlobGas, + final Optional> versionedHashes, + final Optional blobsWithCommitments) { + this( + nonce, + Optional.of(gasPrice), + Optional.empty(), + Optional.empty(), + maxFeePerBlobGas, + gasLimit, + to, + value, + signature, + payload, + sender, + chainId, + versionedHashes, + blobsWithCommitments); } /** @@ -358,13 +422,13 @@ public Optional getMaxFeePerGas() { } /** - * Return the transaction max fee per data gas. + * Return the transaction max fee per blob gas. * - * @return the transaction max fee per data gas + * @return the transaction max fee per blob gas */ @Override - public Optional getMaxFeePerDataGas() { - return maxFeePerDataGas; + public Optional getMaxFeePerBlobGas() { + return maxFeePerBlobGas; } /** @@ -375,7 +439,7 @@ public Optional getMaxFeePerDataGas() { */ public boolean hasCostParams() { return Arrays.asList( - getGasPrice(), getMaxFeePerGas(), getMaxPriorityFeePerGas(), getMaxFeePerDataGas()) + getGasPrice(), getMaxFeePerGas(), getMaxPriorityFeePerGas(), getMaxFeePerBlobGas()) .stream() .flatMap(Optional::stream) .map(Quantity::getAsBigInteger) @@ -540,7 +604,7 @@ private Bytes32 getOrComputeSenderRecoveryHash() { gasPrice.orElse(null), maxPriorityFeePerGas.orElse(null), maxFeePerGas.orElse(null), - maxFeePerDataGas.orElse(null), + maxFeePerBlobGas.orElse(null), gasLimit, to, value, @@ -617,9 +681,15 @@ private void memoizeHashAndSize() { final Bytes bytes = TransactionEncoder.encodeOpaqueBytes(this); hash = Hash.hash(bytes); - final BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput(); - TransactionEncoder.encodeForWire(transactionType, bytes, rlpOutput); - size = rlpOutput.encodedSize(); + if (transactionType.supportsBlob()) { + if (getBlobsWithCommitments().isPresent()) { + size = TransactionEncoder.encodeOpaqueBytes(this).size(); + } + } else { + final BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput(); + TransactionEncoder.encodeForWire(transactionType, bytes, rlpOutput); + size = rlpOutput.encodedSize(); + } } /** @@ -636,9 +706,9 @@ public boolean isContractCreation() { * * @return the max up-front cost for the gas the transaction can use. */ - private Wei getMaxUpfrontGasCost(final long dataGasPerBlock) { + private Wei getMaxUpfrontGasCost(final long blobGasPerBlock) { return getUpfrontGasCost( - getMaxGasPrice(), getMaxFeePerDataGas().orElse(Wei.ZERO), dataGasPerBlock); + getMaxGasPrice(), getMaxFeePerBlobGas().orElse(Wei.ZERO), blobGasPerBlock); } /** @@ -651,19 +721,19 @@ private boolean isUpfrontGasCostTooHigh() { } /** - * Calculates the up-front cost for the gas and data gas the transaction can use. + * Calculates the up-front cost for the gas and blob gas the transaction can use. * * @param gasPrice the gas price to use - * @param dataGasPrice the data gas price to use + * @param blobGasPrice the blob gas price to use * @return the up-front cost for the gas the transaction can use. */ public Wei getUpfrontGasCost( - final Wei gasPrice, final Wei dataGasPrice, final long totalDataGas) { + final Wei gasPrice, final Wei blobGasPrice, final long totalBlobGas) { if (gasPrice == null || gasPrice.isZero()) { return Wei.ZERO; } - final var cost = calculateUpfrontGasCost(gasPrice, dataGasPrice, totalDataGas); + final var cost = calculateUpfrontGasCost(gasPrice, blobGasPrice, totalBlobGas); if (cost.bitLength() > 256) { return Wei.MAX_WEI; @@ -673,12 +743,12 @@ public Wei getUpfrontGasCost( } private BigInteger calculateUpfrontGasCost( - final Wei gasPrice, final Wei dataGasPrice, final long totalDataGas) { + final Wei gasPrice, final Wei blobGasPrice, final long totalBlobGas) { var cost = new BigInteger(1, Longs.toByteArray(getGasLimit())).multiply(gasPrice.getAsBigInteger()); if (transactionType.supportsBlob()) { - cost = cost.add(dataGasPrice.getAsBigInteger().multiply(BigInteger.valueOf(totalDataGas))); + cost = cost.add(blobGasPrice.getAsBigInteger().multiply(BigInteger.valueOf(totalBlobGas))); } return cost; @@ -693,8 +763,8 @@ private BigInteger calculateUpfrontGasCost( * * @return the up-front gas cost for the transaction */ - public Wei getUpfrontCost(final long totalDataGas) { - return getMaxUpfrontGasCost(totalDataGas).addExact(getValue()); + public Wei getUpfrontCost(final long totalBlobGas) { + return getMaxUpfrontGasCost(totalBlobGas).addExact(getValue()); } /** @@ -731,21 +801,12 @@ public TransactionType getType() { return this.transactionType; } - public Optional> getVersionedHashes() { - return this.versionedHashes; + public Optional> getVersionedHashes() { + return versionedHashes; } - /** - * Returns whether or not the transaction is a GoQuorum private transaction.
    - *
    - * A GoQuorum private transaction has its v value equal to 37 or 38, and does not contain a - * chainId. - * - * @param goQuorumCompatibilityMode true if GoQuorum compatbility mode is set - * @return true if GoQuorum private transaction, false otherwise - */ - public boolean isGoQuorumPrivateTransaction(final boolean goQuorumCompatibilityMode) { - return false; + public Optional getBlobsWithCommitments() { + return blobsWithCommitments; } /** @@ -765,13 +826,13 @@ private static Bytes32 computeSenderRecoveryHash( final Wei gasPrice, final Wei maxPriorityFeePerGas, final Wei maxFeePerGas, - final Wei maxFeePerDataGas, + final Wei maxFeePerBlobGas, final long gasLimit, final Optional
    to, final Wei value, final Bytes payload, final Optional> accessList, - final List versionedHashes, + final List versionedHashes, final Optional chainId) { if (transactionType.requiresChainId()) { checkArgument(chainId.isPresent(), "Transaction type %s requires chainId", transactionType); @@ -800,7 +861,7 @@ private static Bytes32 computeSenderRecoveryHash( nonce, maxPriorityFeePerGas, maxFeePerGas, - maxFeePerDataGas, + maxFeePerBlobGas, gasLimit, to, value, @@ -913,14 +974,15 @@ private static Bytes blobPreimage( final long nonce, final Wei maxPriorityFeePerGas, final Wei maxFeePerGas, - final Wei maxFeePerDataGas, + final Wei maxFeePerBlobGas, final long gasLimit, final Optional
    to, final Wei value, final Bytes payload, final Optional chainId, final Optional> accessList, - final List versionedHashes) { + final List versionedHashes) { + final Bytes encoded = RLP.encode( rlpOutput -> { @@ -936,8 +998,8 @@ private static Bytes blobPreimage( chainId, accessList, rlpOutput); - rlpOutput.writeUInt256Scalar(maxFeePerDataGas); - TransactionEncoder.writeBlobVersionedHashes(rlpOutput, versionedHashes); + rlpOutput.writeUInt256Scalar(maxFeePerBlobGas); + BlobTransactionEncoder.writeBlobVersionedHashes(rlpOutput, versionedHashes); rlpOutput.endList(); }); return Bytes.concatenate(Bytes.of(TransactionType.BLOB.getSerializedType()), encoded); @@ -974,7 +1036,7 @@ public boolean equals(final Object other) { && Objects.equals(this.gasPrice, that.gasPrice) && Objects.equals(this.maxPriorityFeePerGas, that.maxPriorityFeePerGas) && Objects.equals(this.maxFeePerGas, that.maxFeePerGas) - && Objects.equals(this.maxFeePerDataGas, that.maxFeePerDataGas) + && Objects.equals(this.maxFeePerBlobGas, that.maxFeePerBlobGas) && this.nonce == that.nonce && Objects.equals(this.payload, that.payload) && Objects.equals(this.signature, that.signature) @@ -990,7 +1052,7 @@ public int hashCode() { gasPrice, maxPriorityFeePerGas, maxFeePerGas, - maxFeePerDataGas, + maxFeePerBlobGas, gasLimit, to, value, @@ -1002,7 +1064,11 @@ public int hashCode() { @Override public String toString() { final StringBuilder sb = new StringBuilder(); - sb.append(isContractCreation() ? "ContractCreation" : "MessageCall").append("{"); + sb.append( + transactionType.supportsBlob() + ? "Blob" + : isContractCreation() ? "ContractCreation" : "MessageCall") + .append("{"); sb.append("type=").append(getType()).append(", "); sb.append("nonce=").append(getNonce()).append(", "); getGasPrice() @@ -1015,9 +1081,9 @@ public String toString() { sb.append("maxFeePerGas=") .append(getMaxFeePerGas().map(Wei::toShortHexString).get()) .append(", "); - getMaxFeePerDataGas() + getMaxFeePerBlobGas() .ifPresent( - wei -> sb.append("maxFeePerDataGas=").append(wei.toShortHexString()).append(", ")); + wei -> sb.append("maxFeePerBlobGas=").append(wei.toShortHexString()).append(", ")); } sb.append("gasLimit=").append(getGasLimit()).append(", "); if (getTo().isPresent()) sb.append("to=").append(getTo().get()).append(", "); @@ -1034,7 +1100,11 @@ public String toString() { public String toTraceLog() { final StringBuilder sb = new StringBuilder(); sb.append(getHash()).append("={"); - sb.append(isContractCreation() ? "ContractCreation" : "MessageCall").append(", "); + sb.append( + transactionType.supportsBlob() + ? "Blob" + : isContractCreation() ? "ContractCreation" : "MessageCall") + .append(", "); sb.append(getNonce()).append(", "); sb.append(getSender()).append(", "); sb.append(getType()).append(", "); @@ -1048,7 +1118,7 @@ public String toTraceLog() { sb.append("pf: ") .append(getMaxPriorityFeePerGas().map(Wei::toHumanReadableString).get()) .append(", "); - getMaxFeePerDataGas() + getMaxFeePerBlobGas() .ifPresent(wei -> sb.append("df: ").append(wei.toHumanReadableString()).append(", ")); } sb.append("gl: ").append(getGasLimit()).append(", "); @@ -1076,7 +1146,7 @@ public static class Builder { protected Wei maxPriorityFeePerGas; protected Wei maxFeePerGas; - protected Wei maxFeePerDataGas; + protected Wei maxFeePerBlobGas; protected long gasLimit = -1L; @@ -1093,9 +1163,9 @@ public static class Builder { protected Address sender; protected Optional chainId = Optional.empty(); - protected Optional v = Optional.empty(); - protected List versionedHashes = null; + protected List versionedHashes = null; + private BlobsWithCommitments blobsWithCommitments; public Builder type(final TransactionType transactionType) { this.transactionType = transactionType; @@ -1127,8 +1197,8 @@ public Builder maxFeePerGas(final Wei maxFeePerGas) { return this; } - public Builder maxFeePerDataGas(final Wei maxFeePerDataGas) { - this.maxFeePerDataGas = maxFeePerDataGas; + public Builder maxFeePerBlobGas(final Wei maxFeePerBlobGas) { + this.maxFeePerBlobGas = maxFeePerBlobGas; return this; } @@ -1175,7 +1245,7 @@ public Builder signature(final SECPSignature signature) { return this; } - public Builder versionedHashes(final List versionedHashes) { + public Builder versionedHashes(final List versionedHashes) { this.versionedHashes = versionedHashes; return this; } @@ -1205,7 +1275,7 @@ public Transaction build() { Optional.ofNullable(gasPrice), Optional.ofNullable(maxPriorityFeePerGas), Optional.ofNullable(maxFeePerGas), - Optional.ofNullable(maxFeePerDataGas), + Optional.ofNullable(maxFeePerBlobGas), gasLimit, to, value, @@ -1214,7 +1284,8 @@ public Transaction build() { accessList, sender, chainId, - Optional.ofNullable(versionedHashes)); + Optional.ofNullable(versionedHashes), + Optional.ofNullable(blobsWithCommitments)); } public Transaction signAndBuild(final KeyPair keys) { @@ -1234,7 +1305,7 @@ SECPSignature computeSignature(final KeyPair keys) { gasPrice, maxPriorityFeePerGas, maxFeePerGas, - maxFeePerDataGas, + maxFeePerBlobGas, gasLimit, to, value, @@ -1244,5 +1315,20 @@ SECPSignature computeSignature(final KeyPair keys) { chainId), keys); } + + public Builder kzgBlobs( + final List kzgCommitments, + final List blobs, + final List kzgProofs) { + if (this.versionedHashes == null || this.versionedHashes.isEmpty()) { + this.versionedHashes = + kzgCommitments.stream() + .map(c -> new VersionedHash(SHA256_VERSION_ID, Sha256Hash.sha256(c.getData()))) + .collect(Collectors.toList()); + } + this.blobsWithCommitments = + new BlobsWithCommitments(kzgCommitments, blobs, kzgProofs, versionedHashes); + return this; + } } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java index cdb7a8829d1..b7419b1572d 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.core; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.ethereum.mainnet.TransactionReceiptType; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; import org.hyperledger.besu.ethereum.rlp.RLP; @@ -23,7 +24,6 @@ import org.hyperledger.besu.ethereum.rlp.RLPOutput; import org.hyperledger.besu.evm.log.Log; import org.hyperledger.besu.evm.log.LogsBloomFilter; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.List; import java.util.Objects; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionDecoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionDecoder.java new file mode 100644 index 00000000000..b2f030f9d61 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionDecoder.java @@ -0,0 +1,108 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.core.encoding; + +import org.hyperledger.besu.crypto.SignatureAlgorithm; +import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Blob; +import org.hyperledger.besu.datatypes.KZGCommitment; +import org.hyperledger.besu.datatypes.KZGProof; +import org.hyperledger.besu.datatypes.TransactionType; +import org.hyperledger.besu.datatypes.VersionedHash; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.rlp.RLPInput; +import org.hyperledger.besu.evm.AccessListEntry; + +import java.util.List; +import java.util.function.Supplier; + +import com.google.common.base.Suppliers; + +public class BlobTransactionDecoder { + private static final Supplier SIGNATURE_ALGORITHM = + Suppliers.memoize(SignatureAlgorithmFactory::getInstance); + + static Transaction decode(final RLPInput input) { + Transaction transaction; + + input.enterList(); + // BlobTransactionNetworkWrapper + if (input.nextIsList()) { + transaction = readNetworkWrapperInner(input); + } else { + transaction = readTransactionPayload(input); + } + input.leaveList(); + return transaction; + } + + private static Transaction readTransactionPayload(final RLPInput input) { + final Transaction.Builder builder = Transaction.builder(); + readTransactionPayloadInner(builder, input); + return builder.build(); + } + + private static void readTransactionPayloadInner( + final Transaction.Builder builder, final RLPInput input) { + builder + .type(TransactionType.BLOB) + .chainId(input.readBigIntegerScalar()) + .nonce(input.readLongScalar()) + .maxPriorityFeePerGas(Wei.of(input.readUInt256Scalar())) + .maxFeePerGas(Wei.of(input.readUInt256Scalar())) + .gasLimit(input.readLongScalar()) + .to(input.readBytes(v -> v.size() == 0 ? null : Address.wrap(v))) + .value(Wei.of(input.readUInt256Scalar())) + .payload(input.readBytes()) + .accessList( + input.readList( + accessListEntryRLPInput -> { + accessListEntryRLPInput.enterList(); + final AccessListEntry accessListEntry = + new AccessListEntry( + Address.wrap(accessListEntryRLPInput.readBytes()), + accessListEntryRLPInput.readList(RLPInput::readBytes32)); + accessListEntryRLPInput.leaveList(); + return accessListEntry; + })) + .maxFeePerBlobGas(Wei.of(input.readUInt256Scalar())) + .versionedHashes( + input.readList(versionedHashes -> new VersionedHash(versionedHashes.readBytes32()))); + + final byte recId = (byte) input.readIntScalar(); + builder.signature( + SIGNATURE_ALGORITHM + .get() + .createSignature( + input.readUInt256Scalar().toUnsignedBigInteger(), + input.readUInt256Scalar().toUnsignedBigInteger(), + recId)); + } + + private static Transaction readNetworkWrapperInner(final RLPInput input) { + final Transaction.Builder builder = Transaction.builder(); + input.enterList(); + readTransactionPayloadInner(builder, input); + input.leaveList(); + + List blobs = input.readList(Blob::readFrom); + List commitments = input.readList(KZGCommitment::readFrom); + List proofs = input.readList(KZGProof::readFrom); + builder.kzgBlobs(commitments, blobs, proofs); + return builder.build(); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncoder.java new file mode 100644 index 00000000000..6df9baed920 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncoder.java @@ -0,0 +1,87 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.core.encoding; + +import static org.slf4j.LoggerFactory.getLogger; + +import org.hyperledger.besu.datatypes.Blob; +import org.hyperledger.besu.datatypes.KZGCommitment; +import org.hyperledger.besu.datatypes.KZGProof; +import org.hyperledger.besu.datatypes.VersionedHash; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.rlp.RLP; +import org.hyperledger.besu.ethereum.rlp.RLPOutput; + +import java.util.List; + +import org.apache.tuweni.bytes.Bytes; +import org.slf4j.Logger; + +public class BlobTransactionEncoder { + private static final Logger LOG = getLogger(BlobTransactionEncoder.class); + + public static void encodeEIP4844(final Transaction transaction, final RLPOutput out) { + out.startList(); + out.writeBigIntegerScalar(transaction.getChainId().orElseThrow()); + out.writeLongScalar(transaction.getNonce()); + out.writeUInt256Scalar(transaction.getMaxPriorityFeePerGas().orElseThrow()); + out.writeUInt256Scalar(transaction.getMaxFeePerGas().orElseThrow()); + out.writeLongScalar(transaction.getGasLimit()); + out.writeBytes(transaction.getTo().map(Bytes::copy).orElse(Bytes.EMPTY)); + out.writeUInt256Scalar(transaction.getValue()); + out.writeBytes(transaction.getPayload()); + TransactionEncoder.writeAccessList(out, transaction.getAccessList()); + out.writeUInt256Scalar(transaction.getMaxFeePerBlobGas().orElseThrow()); + out.startList(); + transaction + .getVersionedHashes() + .get() + .forEach( + vh -> { + out.writeBytes(vh.toBytes()); + }); + out.endList(); + TransactionEncoder.writeSignatureAndRecoveryId(transaction, out); + out.endList(); + } + + private static void encodeEIP4844Network(final Transaction transaction, final RLPOutput out) { + LOG.trace("Encoding transaction with blobs {}", transaction); + out.startList(); + var blobsWithCommitments = transaction.getBlobsWithCommitments().orElseThrow(); + encodeEIP4844(transaction, out); + + out.writeList(blobsWithCommitments.getBlobs(), Blob::writeTo); + out.writeList(blobsWithCommitments.getKzgCommitments(), KZGCommitment::writeTo); + out.writeList(blobsWithCommitments.getKzgProofs(), KZGProof::writeTo); + out.endList(); + } + + public static void encodeForWireNetwork( + final Transaction transaction, final RLPOutput rlpOutput) { + rlpOutput.writeBytes(encodeOpaqueBytesNetwork(transaction)); + } + + private static Bytes encodeOpaqueBytesNetwork(final Transaction transaction) { + return Bytes.concatenate( + Bytes.of(transaction.getType().getSerializedType()), + RLP.encode(rlpOutput -> encodeEIP4844Network(transaction, rlpOutput))); + } + + public static void writeBlobVersionedHashes( + final RLPOutput rlpOutput, final List versionedHashes) { + rlpOutput.writeList(versionedHashes, (h, out) -> out.writeBytes(h.toBytes())); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java index bd41e0276bf..11f9b008aea 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java @@ -25,12 +25,12 @@ import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLPInput; import org.hyperledger.besu.evm.AccessListEntry; -import org.hyperledger.besu.plugin.data.TransactionType; import java.math.BigInteger; import java.util.Optional; @@ -52,7 +52,9 @@ interface Decoder { TransactionType.ACCESS_LIST, TransactionDecoder::decodeAccessList, TransactionType.EIP1559, - TransactionDecoder::decodeEIP1559); + TransactionDecoder::decodeEIP1559, + TransactionType.BLOB, + BlobTransactionDecoder::decode); private static final Supplier SIGNATURE_ALGORITHM = Suppliers.memoize(SignatureAlgorithmFactory::getInstance); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java index 3af82a68301..22e88cae8bb 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java @@ -17,13 +17,13 @@ import static com.google.common.base.Preconditions.checkNotNull; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLPOutput; import org.hyperledger.besu.evm.AccessListEntry; -import org.hyperledger.besu.plugin.data.TransactionType; import java.math.BigInteger; import java.util.List; @@ -44,7 +44,9 @@ interface Encoder { TransactionType.ACCESS_LIST, TransactionEncoder::encodeAccessList, TransactionType.EIP1559, - TransactionEncoder::encodeEIP1559); + TransactionEncoder::encodeEIP1559, + TransactionType.BLOB, + BlobTransactionEncoder::encodeEIP4844); public static void encodeForWire(final Transaction transaction, final RLPOutput rlpOutput) { final TransactionType transactionType = @@ -75,9 +77,10 @@ public static Bytes encodeOpaqueBytes(final Transaction transaction) { TYPED_TRANSACTION_ENCODERS.get(transactionType), "Developer Error. A supported transaction type %s has no associated encoding logic", transactionType); - return Bytes.concatenate( - Bytes.of(transactionType.getSerializedType()), - RLP.encode(rlpOutput -> encoder.encode(transaction, rlpOutput))); + final BytesValueRLPOutput out = new BytesValueRLPOutput(); + out.writeByte(transactionType.getSerializedType()); + encoder.encode(transaction, out); + return out.encoded(); } } @@ -185,17 +188,12 @@ public static void writeAccessList( } } - public static void writeBlobVersionedHashes( - final RLPOutput rlpOutput, final List versionedHashes) { - // ToDo 4844: implement - } - private static void writeSignatureAndV(final Transaction transaction, final RLPOutput out) { out.writeBigIntegerScalar(transaction.getV()); writeSignature(transaction, out); } - private static void writeSignatureAndRecoveryId( + public static void writeSignatureAndRecoveryId( final Transaction transaction, final RLPOutput out) { out.writeIntScalar(transaction.getSignature().getRecId()); writeSignature(transaction, out); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java index b68da184006..f2b8637d591 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java @@ -1,5 +1,5 @@ /* - * Copyright ConsenSys AG. + * Copyright Hyperledger Besu contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -14,9 +14,11 @@ */ package org.hyperledger.besu.ethereum.core.feemarket; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; +import java.math.BigInteger; import java.util.Optional; @FunctionalInterface @@ -42,4 +44,36 @@ static TransactionPriceCalculator eip1559() { return price; }; } + + // curiously named as in the spec + // https://eips.ethereum.org/EIPS/eip-4844#cryptographic-helpers + private static BigInteger fakeExponential( + final BigInteger factor, final BigInteger numerator, final BigInteger denominator) { + int i = 1; + BigInteger output = BigInteger.ZERO; + BigInteger numeratorAccumulator = factor.multiply(denominator); + while (numeratorAccumulator.signum() > 0) { + output = output.add(numeratorAccumulator); + numeratorAccumulator = + (numeratorAccumulator.multiply(numerator)) + .divide(denominator.multiply(BigInteger.valueOf(i))); + ++i; + } + return output.divide(denominator); + } + + static TransactionPriceCalculator blobGas( + final int minBlobGasPrice, + final int blobGasPriceUpdateFraction, + final BlobGas excessBlobGas) { + return ((transaction, baseFee) -> { + final var blobGasPrice = + Wei.of( + fakeExponential( + BigInteger.valueOf(minBlobGasPrice), + excessBlobGas.toBigInteger(), + BigInteger.valueOf(blobGasPriceUpdateFraction))); + return blobGasPrice; + }); + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java index e61e3b1a90d..742493b0f23 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java @@ -14,8 +14,10 @@ */ package org.hyperledger.besu.ethereum.mainnet; +import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent; + import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.DataGas; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.BlockProcessingOutputs; import org.hyperledger.besu.ethereum.BlockProcessingResult; @@ -36,7 +38,6 @@ import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import org.hyperledger.besu.plugin.data.TransactionType; import java.text.MessageFormat; import java.util.ArrayList; @@ -112,14 +113,19 @@ public BlockProcessingResult processBlock( final BlockHashLookup blockHashLookup = new CachingBlockHashLookup(blockHeader, blockchain); final Address miningBeneficiary = miningBeneficiaryCalculator.calculateBeneficiary(blockHeader); - final Wei dataGasPrice = - protocolSpec - .getFeeMarket() - .dataPrice( - blockchain - .getBlockHeader(blockHeader.getParentHash()) - .flatMap(BlockHeader::getExcessDataGas) - .orElse(DataGas.ZERO)); + + Optional maybeParentHeader = + blockchain.getBlockHeader(blockHeader.getParentHash()); + + Wei blobGasPrice = + maybeParentHeader + .map( + (parentHeader) -> + protocolSpec + .getFeeMarket() + .blobGasPricePerGas( + calculateExcessBlobGasForParent(protocolSpec, parentHeader))) + .orElse(Wei.ZERO); final TransactionProcessingResult result = transactionProcessor.processTransaction( @@ -133,7 +139,7 @@ public BlockProcessingResult processBlock( true, TransactionValidationParams.processingBlock(), privateMetadataUpdater, - dataGasPrice); + blobGasPrice); if (result.isInvalid()) { String errorMessage = MessageFormat.format( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculator.java index c0c3366f4df..7dd1be481f6 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculator.java @@ -17,7 +17,7 @@ import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; public class CancunTargetingGasLimitCalculator extends LondonTargetingGasLimitCalculator { - private static final long MAX_DATA_GAS_PER_BLOCK = 1 << 19; + private static final long MAX_BLOB_GAS_PER_BLOCK = 786432L; public CancunTargetingGasLimitCalculator( final long londonForkBlock, final BaseFeeMarket feeMarket) { @@ -25,7 +25,7 @@ public CancunTargetingGasLimitCalculator( } @Override - public long currentDataGasLimit() { - return MAX_DATA_GAS_PER_BLOCK; + public long currentBlobGasLimit() { + return MAX_BLOB_GAS_PER_BLOCK; } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java index bb99bd72390..bc460811ae0 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java @@ -17,10 +17,10 @@ import static org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSpecs.powHasher; import org.hyperledger.besu.config.PowAlgorithm; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.feemarket.CoinbaseFeePriceCalculator; -import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; import org.hyperledger.besu.evm.MainnetEVMs; import org.hyperledger.besu.evm.contractvalidation.MaxCodeSizeRule; @@ -37,7 +37,6 @@ import org.hyperledger.besu.evm.processor.ContractCreationProcessor; import org.hyperledger.besu.evm.processor.MessageCallProcessor; import org.hyperledger.besu.evm.worldstate.WorldState; -import org.hyperledger.besu.plugin.data.TransactionType; import java.math.BigInteger; import java.util.Collections; @@ -72,10 +71,11 @@ public static ProtocolSpecBuilder tangerineWhistleDefinition( final EvmConfiguration evmConfiguration) { return MainnetProtocolSpecs.homesteadDefinition( contractSizeLimit, configStackSizeLimit, evmConfiguration) + .isReplayProtectionSupported(true) .gasCalculator(TangerineWhistleGasCalculator::new) - .transactionValidatorBuilder( - (gasCalculator, gasLimitCalculator) -> - new MainnetTransactionValidator(gasCalculator, gasLimitCalculator, true, chainId)) + .transactionValidatorFactoryBuilder( + (gasCalculator, gasLimitCalculator, feeMarket) -> + new TransactionValidatorFactory(gasCalculator, gasLimitCalculator, true, chainId)) .name("ClassicTangerineWhistle"); } @@ -127,9 +127,9 @@ public static ProtocolSpecBuilder defuseDifficultyBombDefinition( return gothamDefinition( chainId, contractSizeLimit, configStackSizeLimit, ecip1017EraRounds, evmConfiguration) .difficultyCalculator(ClassicDifficultyCalculators.DIFFICULTY_BOMB_REMOVED) - .transactionValidatorBuilder( - (gasCalculator, gasLimitCalculator) -> - new MainnetTransactionValidator(gasCalculator, gasLimitCalculator, true, chainId)) + .transactionValidatorFactoryBuilder( + (gasCalculator, gasLimitCalculator, feeMarket) -> + new TransactionValidatorFactory(gasCalculator, gasLimitCalculator, true, chainId)) .name("DefuseDifficultyBomb"); } @@ -170,18 +170,19 @@ public static ProtocolSpecBuilder atlantisDefinition( 1)) .transactionProcessorBuilder( (gasCalculator, - transactionValidator, + feeMarket, + transactionValidatorFactory, contractCreationProcessor, messageCallProcessor) -> new MainnetTransactionProcessor( gasCalculator, - transactionValidator, + transactionValidatorFactory, contractCreationProcessor, messageCallProcessor, true, false, stackSizeLimit, - FeeMarket.legacy(), + feeMarket, CoinbaseFeePriceCalculator.frontier())) .name("Atlantis"); } @@ -290,9 +291,9 @@ public static ProtocolSpecBuilder magnetoDefinition( ecip1017EraRounds, evmConfiguration) .gasCalculator(BerlinGasCalculator::new) - .transactionValidatorBuilder( - (gasCalculator, gasLimitCalculator) -> - new MainnetTransactionValidator( + .transactionValidatorFactoryBuilder( + (gasCalculator, gasLimitCalculator, feeMarket) -> + new TransactionValidatorFactory( gasCalculator, gasLimitCalculator, true, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolSchedule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolSchedule.java index a2de85905f3..9499a7a8064 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolSchedule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolSchedule.java @@ -20,8 +20,8 @@ import static com.google.common.base.Preconditions.checkArgument; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.PermissionTransactionFilter; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; -import org.hyperledger.besu.ethereum.core.TransactionFilter; import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec.BlockNumberProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec.TimestampProtocolSpec; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; @@ -40,7 +40,7 @@ public class DefaultProtocolSchedule implements ProtocolSchedule { @VisibleForTesting protected NavigableSet protocolSpecs = - new TreeSet<>(Comparator.comparing(ScheduledProtocolSpec::milestone).reversed()); + new TreeSet<>(Comparator.comparing(ScheduledProtocolSpec::fork).reversed()); private final Optional chainId; @@ -54,12 +54,23 @@ protected DefaultProtocolSchedule(final DefaultProtocolSchedule protocolSchedule this.protocolSpecs = protocolSchedule.protocolSpecs; } + public ScheduledProtocolSpec specScheduledForBlock(final ProcessableBlockHeader blockHeader) { + return protocolSpecs.stream() + .filter(s -> s.isOnOrAfterMilestoneBoundary(blockHeader)) + .findFirst() + .orElseThrow( + () -> + new IllegalStateException( + "No protocol spec found for block " + blockHeader.getNumber())); + } + @Override public ProtocolSpec getByBlockHeader(final ProcessableBlockHeader blockHeader) { checkArgument( !protocolSpecs.isEmpty(), "At least 1 milestone must be provided to the protocol schedule"); checkArgument( - protocolSpecs.last().milestone() == 0, "There must be a milestone starting from block 0"); + protocolSpecs.last().fork().milestone() == 0, + "There must be a milestone starting from block 0"); // protocolSpecs is sorted in descending block order, so the first one we find that's lower than // the requested level will be the most appropriate spec @@ -79,8 +90,8 @@ public Optional getChainId() { @Override public String listMilestones() { return protocolSpecs.stream() - .sorted(Comparator.comparing(ScheduledProtocolSpec::milestone)) - .map(scheduledSpec -> scheduledSpec.spec().getName() + ": " + scheduledSpec.milestone()) + .sorted(Comparator.comparing(ScheduledProtocolSpec::fork)) + .map(scheduledSpec -> scheduledSpec.fork().toString()) .collect(Collectors.joining(", ", "[", "]")); } @@ -111,9 +122,22 @@ public boolean anyMatch(final Predicate predicate) { } @Override - public void setTransactionFilter(final TransactionFilter transactionFilter) { + public Optional hardforkFor( + final Predicate predicate) { + return this.protocolSpecs.stream() + .filter(predicate) + .findFirst() + .map(ScheduledProtocolSpec::fork); + } + + @Override + public void setPermissionTransactionFilter( + final PermissionTransactionFilter permissionTransactionFilter) { protocolSpecs.forEach( - spec -> spec.spec().getTransactionValidator().setTransactionFilter(transactionFilter)); + spec -> + spec.spec() + .getTransactionValidatorFactory() + .setPermissionTransactionFilter(permissionTransactionFilter)); } @Override diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java index 0f0d53d565e..d361a6c0afc 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java @@ -20,6 +20,7 @@ import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.AncestryValidationRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.BaseFeeMarketBlockHeaderGasPriceValidationRule; +import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.BlobGasValidationRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.CalculatedDifficultyValidationRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.ConstantFieldValidationRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.ConstantOmmersHashRule; @@ -32,6 +33,7 @@ import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.ProofOfWorkValidationRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.TimestampBoundedByFutureParameter; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.TimestampMoreRecentThanParent; +import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; import java.util.Optional; @@ -195,4 +197,9 @@ public static BlockHeaderValidator.Builder mergeBlockHeaderValidator(final FeeMa .addRule(new NoDifficultyRule()) .addRule(new IncrementalTimestampRule()); } + + public static BlockHeaderValidator.Builder cancunBlockHeaderValidator(final FeeMarket feeMarket) { + return mergeBlockHeaderValidator(feeMarket) + .addRule(new BlobGasValidationRule(new CancunGasCalculator())); + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java index 18417763bd4..dd94e60b5bd 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java @@ -17,9 +17,9 @@ import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.config.PowAlgorithm; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.BlockProcessingResult; -import org.hyperledger.besu.ethereum.GasLimitCalculator; import org.hyperledger.besu.ethereum.MainnetBlockValidator; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -59,7 +59,6 @@ import org.hyperledger.besu.evm.processor.MessageCallProcessor; import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import org.hyperledger.besu.plugin.data.TransactionType; import java.io.IOException; import java.math.BigInteger; @@ -110,7 +109,7 @@ public static ProtocolSpecBuilder frontierDefinition( final int stackSizeLimit = configStackSizeLimit.orElse(MessageFrame.DEFAULT_MAX_STACK_SIZE); return new ProtocolSpecBuilder() .gasCalculator(FrontierGasCalculator::new) - .gasLimitCalculator(new FrontierTargetingGasLimitCalculator()) + .gasLimitCalculatorBuilder(feeMarket -> new FrontierTargetingGasLimitCalculator()) .evmBuilder(MainnetEVMs::frontier) .precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::frontier) .messageCallProcessorBuilder(MessageCallProcessor::new) @@ -122,18 +121,19 @@ public static ProtocolSpecBuilder frontierDefinition( false, Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)), 0)) - .transactionValidatorBuilder( - (gasCalculator, gasLimitCalculator) -> - new MainnetTransactionValidator( + .transactionValidatorFactoryBuilder( + (gasCalculator, gasLimitCalculator, feeMarket) -> + new TransactionValidatorFactory( gasCalculator, gasLimitCalculator, false, Optional.empty())) .transactionProcessorBuilder( (gasCalculator, - transactionValidator, + feeMarket, + transactionValidatorFactory, contractCreationProcessor, messageCallProcessor) -> new MainnetTransactionProcessor( gasCalculator, - transactionValidator, + transactionValidatorFactory, contractCreationProcessor, messageCallProcessor, false, @@ -142,12 +142,12 @@ public static ProtocolSpecBuilder frontierDefinition( FeeMarket.legacy(), CoinbaseFeePriceCalculator.frontier())) .privateTransactionProcessorBuilder( - (transactionValidator, + (transactionValidatorFactory, contractCreationProcessor, messageCallProcessor, privateTransactionValidator) -> new PrivateTransactionProcessor( - transactionValidator, + transactionValidatorFactory, contractCreationProcessor, messageCallProcessor, false, @@ -197,9 +197,9 @@ public static ProtocolSpecBuilder homesteadDefinition( true, Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)), 0)) - .transactionValidatorBuilder( - (gasCalculator, gasLimitCalculator) -> - new MainnetTransactionValidator( + .transactionValidatorFactoryBuilder( + (gasCalculator, gasLimitCalculator, feeMarket) -> + new TransactionValidatorFactory( gasCalculator, gasLimitCalculator, true, Optional.empty())) .difficultyCalculator(MainnetDifficultyCalculators.HOMESTEAD) .name("Homestead"); @@ -257,6 +257,7 @@ public static ProtocolSpecBuilder spuriousDragonDefinition( final int stackSizeLimit = configStackSizeLimit.orElse(MessageFrame.DEFAULT_MAX_STACK_SIZE); return tangerineWhistleDefinition(OptionalInt.empty(), configStackSizeLimit, evmConfiguration) + .isReplayProtectionSupported(true) .gasCalculator(SpuriousDragonGasCalculator::new) .skipZeroBlockRewards(true) .messageCallProcessorBuilder( @@ -274,11 +275,12 @@ public static ProtocolSpecBuilder spuriousDragonDefinition( Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)), 1, SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES)) - .transactionValidatorBuilder( - (gasCalculator, gasLimitCalculator) -> - new MainnetTransactionValidator(gasCalculator, gasLimitCalculator, true, chainId)) + .transactionValidatorFactoryBuilder( + (gasCalculator, gasLimitCalculator, feeMarket) -> + new TransactionValidatorFactory(gasCalculator, gasLimitCalculator, true, chainId)) .transactionProcessorBuilder( (gasCalculator, + feeMarket, transactionValidator, contractCreationProcessor, messageCallProcessor) -> @@ -290,7 +292,7 @@ public static ProtocolSpecBuilder spuriousDragonDefinition( true, false, stackSizeLimit, - FeeMarket.legacy(), + feeMarket, CoinbaseFeePriceCalculator.frontier())) .name("SpuriousDragon"); } @@ -315,12 +317,12 @@ public static ProtocolSpecBuilder byzantiumDefinition( .blockReward(BYZANTIUM_BLOCK_REWARD) .privateTransactionValidatorBuilder(() -> new PrivateTransactionValidator(chainId)) .privateTransactionProcessorBuilder( - (transactionValidator, + (transactionValidatorFactory, contractCreationProcessor, messageCallProcessor, privateTransactionValidator) -> new PrivateTransactionProcessor( - transactionValidator, + transactionValidatorFactory, contractCreationProcessor, messageCallProcessor, false, @@ -409,9 +411,9 @@ static ProtocolSpecBuilder berlinDefinition( return muirGlacierDefinition( chainId, contractSizeLimit, configStackSizeLimit, enableRevertReason, evmConfiguration) .gasCalculator(BerlinGasCalculator::new) - .transactionValidatorBuilder( - (gasCalculator, gasLimitCalculator) -> - new MainnetTransactionValidator( + .transactionValidatorFactoryBuilder( + (gasCalculator, gasLimitCalculator, feeMarket) -> + new TransactionValidatorFactory( gasCalculator, gasLimitCalculator, true, @@ -446,15 +448,18 @@ static ProtocolSpecBuilder londonDefinition( configStackSizeLimit, enableRevertReason, evmConfiguration) + .feeMarket(londonFeeMarket) .gasCalculator(LondonGasCalculator::new) - .gasLimitCalculator( - new LondonTargetingGasLimitCalculator(londonForkBlockNumber, londonFeeMarket)) - .transactionValidatorBuilder( - (gasCalculator, gasLimitCalculator) -> - new MainnetTransactionValidator( + .gasLimitCalculatorBuilder( + feeMarket -> + new LondonTargetingGasLimitCalculator( + londonForkBlockNumber, (BaseFeeMarket) feeMarket)) + .transactionValidatorFactoryBuilder( + (gasCalculator, gasLimitCalculator, feeMarket) -> + new TransactionValidatorFactory( gasCalculator, gasLimitCalculator, - londonFeeMarket, + feeMarket, true, chainId, Set.of( @@ -464,18 +469,19 @@ static ProtocolSpecBuilder londonDefinition( Integer.MAX_VALUE)) .transactionProcessorBuilder( (gasCalculator, - transactionValidator, + feeMarket, + transactionValidatorFactory, contractCreationProcessor, messageCallProcessor) -> new MainnetTransactionProcessor( gasCalculator, - transactionValidator, + transactionValidatorFactory, contractCreationProcessor, messageCallProcessor, true, false, stackSizeLimit, - londonFeeMarket, + feeMarket, CoinbaseFeePriceCalculator.eip1559())) .contractCreationProcessorBuilder( (gasCalculator, evm) -> @@ -490,13 +496,14 @@ static ProtocolSpecBuilder londonDefinition( (gasCalculator, jdCacheConfig) -> MainnetEVMs.london( gasCalculator, chainId.orElse(BigInteger.ZERO), evmConfiguration)) - .feeMarket(londonFeeMarket) .difficultyCalculator(MainnetDifficultyCalculators.LONDON) .blockHeaderValidatorBuilder( - feeMarket -> MainnetBlockHeaderValidator.createBaseFeeMarketValidator(londonFeeMarket)) + feeMarket -> + MainnetBlockHeaderValidator.createBaseFeeMarketValidator((BaseFeeMarket) feeMarket)) .ommerHeaderValidatorBuilder( feeMarket -> - MainnetBlockHeaderValidator.createBaseFeeMarketOmmerValidator(londonFeeMarket)) + MainnetBlockHeaderValidator.createBaseFeeMarketOmmerValidator( + (BaseFeeMarket) feeMarket)) .blockBodyValidatorBuilder(BaseFeeBlockBodyValidator::new) .name("London"); } @@ -573,11 +580,6 @@ static ProtocolSpecBuilder shanghaiDefinition( // extra variables need to support flipping the warm coinbase flag. final int stackSizeLimit = configStackSizeLimit.orElse(MessageFrame.DEFAULT_MAX_STACK_SIZE); - final long londonForkBlockNumber = genesisConfigOptions.getLondonBlockNumber().orElse(0L); - final BaseFeeMarket londonFeeMarket = - genesisConfigOptions.isZeroBaseFee() - ? FeeMarket.zeroBaseFee(londonForkBlockNumber) - : FeeMarket.london(londonForkBlockNumber, genesisConfigOptions.getBaseFeePerGas()); return parisDefinition( chainId, @@ -596,26 +598,27 @@ static ProtocolSpecBuilder shanghaiDefinition( // we need to flip the Warm Coinbase flag for EIP-3651 warm coinbase .transactionProcessorBuilder( (gasCalculator, - transactionValidator, + feeMarket, + transactionValidatorFactory, contractCreationProcessor, messageCallProcessor) -> new MainnetTransactionProcessor( gasCalculator, - transactionValidator, + transactionValidatorFactory, contractCreationProcessor, messageCallProcessor, true, true, stackSizeLimit, - londonFeeMarket, + feeMarket, CoinbaseFeePriceCalculator.eip1559())) // Contract creation rules for EIP-3860 Limit and meter intitcode - .transactionValidatorBuilder( - (gasCalculator, gasLimitCalculator) -> - new MainnetTransactionValidator( + .transactionValidatorFactoryBuilder( + (gasCalculator, gasLimitCalculator, feeMarket) -> + new TransactionValidatorFactory( gasCalculator, gasLimitCalculator, - londonFeeMarket, + feeMarket, true, chainId, Set.of( @@ -645,9 +648,6 @@ static ProtocolSpecBuilder cancunDefinition( ? FeeMarket.zeroBaseFee(londonForkBlockNumber) : FeeMarket.cancun(londonForkBlockNumber, genesisConfigOptions.getBaseFeePerGas()); - final GasLimitCalculator cancunGasLimitCalculator = - new CancunTargetingGasLimitCalculator(londonForkBlockNumber, cancunFeeMarket); - return shanghaiDefinition( chainId, configContractSizeLimit, @@ -656,10 +656,13 @@ static ProtocolSpecBuilder cancunDefinition( genesisConfigOptions, evmConfiguration) .feeMarket(cancunFeeMarket) - // gas calculator for EIP-4844 data gas + // gas calculator for EIP-4844 blob gas .gasCalculator(CancunGasCalculator::new) - // gas limit with EIP-4844 max data gas per block - .gasLimitCalculator(cancunGasLimitCalculator) + // gas limit with EIP-4844 max blob gas per block + .gasLimitCalculatorBuilder( + feeMarket -> + new CancunTargetingGasLimitCalculator( + londonForkBlockNumber, (BaseFeeMarket) feeMarket)) // EVM changes to support EOF EIPs (3670, 4200, 4750, 5450) .evmBuilder( (gasCalculator, jdCacheConfig) -> @@ -679,6 +682,7 @@ static ProtocolSpecBuilder cancunDefinition( // use Cancun fee market .transactionProcessorBuilder( (gasCalculator, + feeMarket, transactionValidator, contractCreationProcessor, messageCallProcessor) -> @@ -690,15 +694,15 @@ static ProtocolSpecBuilder cancunDefinition( true, true, stackSizeLimit, - cancunFeeMarket, + feeMarket, CoinbaseFeePriceCalculator.eip1559())) - // change to check for max data gas per block for EIP-4844 - .transactionValidatorBuilder( - (gasCalculator, gasLimitCalculator) -> - new MainnetTransactionValidator( + // change to check for max blob gas per block for EIP-4844 + .transactionValidatorFactoryBuilder( + (gasCalculator, gasLimitCalculator, feeMarket) -> + new TransactionValidatorFactory( gasCalculator, gasLimitCalculator, - cancunFeeMarket, + feeMarket, true, chainId, Set.of( @@ -708,6 +712,7 @@ static ProtocolSpecBuilder cancunDefinition( TransactionType.BLOB), SHANGHAI_INIT_CODE_SIZE_LIMIT)) .precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::cancun) + .blockHeaderValidatorBuilder(MainnetBlockHeaderValidator::cancunBlockHeaderValidator) .name("Cancun"); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java index 181b43e91f5..c6d8c20f2d5 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java @@ -43,7 +43,6 @@ import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import java.util.ArrayDeque; import java.util.Deque; import java.util.HashSet; import java.util.List; @@ -64,7 +63,7 @@ public class MainnetTransactionProcessor { protected final GasCalculator gasCalculator; - protected final MainnetTransactionValidator transactionValidator; + protected final TransactionValidatorFactory transactionValidatorFactory; private final AbstractMessageProcessor contractCreationProcessor; @@ -81,7 +80,7 @@ public class MainnetTransactionProcessor { public MainnetTransactionProcessor( final GasCalculator gasCalculator, - final MainnetTransactionValidator transactionValidator, + final TransactionValidatorFactory transactionValidatorFactory, final AbstractMessageProcessor contractCreationProcessor, final AbstractMessageProcessor messageCallProcessor, final boolean clearEmptyAccounts, @@ -90,7 +89,7 @@ public MainnetTransactionProcessor( final FeeMarket feeMarket, final CoinbaseFeePriceCalculator coinbaseFeePriceCalculator) { this.gasCalculator = gasCalculator; - this.transactionValidator = transactionValidator; + this.transactionValidatorFactory = transactionValidatorFactory; this.contractCreationProcessor = contractCreationProcessor; this.messageCallProcessor = messageCallProcessor; this.clearEmptyAccounts = clearEmptyAccounts; @@ -125,7 +124,7 @@ public TransactionProcessingResult processTransaction( final BlockHashLookup blockHashLookup, final Boolean isPersistingPrivateState, final TransactionValidationParams transactionValidationParams, - final Wei dataGasPrice) { + final Wei blobGasPrice) { return processTransaction( blockchain, worldState, @@ -137,7 +136,7 @@ public TransactionProcessingResult processTransaction( isPersistingPrivateState, transactionValidationParams, null, - dataGasPrice); + blobGasPrice); } /** @@ -167,7 +166,7 @@ public TransactionProcessingResult processTransaction( final Boolean isPersistingPrivateState, final TransactionValidationParams transactionValidationParams, final OperationTracer operationTracer, - final Wei dataGasPrice) { + final Wei blobGasPrice) { return processTransaction( blockchain, worldState, @@ -179,7 +178,7 @@ public TransactionProcessingResult processTransaction( isPersistingPrivateState, transactionValidationParams, null, - dataGasPrice); + blobGasPrice); } /** @@ -204,7 +203,7 @@ public TransactionProcessingResult processTransaction( final OperationTracer operationTracer, final BlockHashLookup blockHashLookup, final Boolean isPersistingPrivateState, - final Wei dataGasPrice) { + final Wei blobGasPrice) { return processTransaction( blockchain, worldState, @@ -216,7 +215,7 @@ public TransactionProcessingResult processTransaction( isPersistingPrivateState, ImmutableTransactionValidationParams.builder().build(), null, - dataGasPrice); + blobGasPrice); } /** @@ -243,7 +242,7 @@ public TransactionProcessingResult processTransaction( final BlockHashLookup blockHashLookup, final Boolean isPersistingPrivateState, final TransactionValidationParams transactionValidationParams, - final Wei dataGasPrice) { + final Wei blobGasPrice) { return processTransaction( blockchain, worldState, @@ -255,7 +254,7 @@ public TransactionProcessingResult processTransaction( isPersistingPrivateState, transactionValidationParams, null, - dataGasPrice); + blobGasPrice); } public TransactionProcessingResult processTransaction( @@ -269,8 +268,9 @@ public TransactionProcessingResult processTransaction( final Boolean isPersistingPrivateState, final TransactionValidationParams transactionValidationParams, final PrivateMetadataUpdater privateMetadataUpdater, - final Wei dataGasPrice) { + final Wei blobGasPrice) { try { + final var transactionValidator = transactionValidatorFactory.get(); LOG.trace("Starting execution of {}", transaction); ValidationResult validationResult = transactionValidator.validate( @@ -305,10 +305,10 @@ public TransactionProcessingResult processTransaction( final Wei transactionGasPrice = feeMarket.getTransactionPriceCalculator().price(transaction, blockHeader.getBaseFee()); - final long dataGas = gasCalculator.dataGasCost(transaction.getBlobCount()); + final long blobGas = gasCalculator.blobGasCost(transaction.getBlobCount()); final Wei upfrontGasCost = - transaction.getUpfrontGasCost(transactionGasPrice, dataGasPrice, dataGas); + transaction.getUpfrontGasCost(transactionGasPrice, blobGasPrice, blobGas); final Wei previousBalance = senderMutableAccount.decrementBalance(upfrontGasCost); LOG.trace( "Deducted sender {} upfront gas cost {} ({} -> {})", @@ -339,17 +339,16 @@ public TransactionProcessingResult processTransaction( transaction.getPayload(), transaction.isContractCreation()); final long accessListGas = gasCalculator.accessListGasCost(accessListEntries.size(), accessListStorageCount); - final long gasAvailable = transaction.getGasLimit() - intrinsicGas - accessListGas; LOG.trace( - "Gas available for execution {} = {} - {} - {} (limit - intrinsic - accessList)", + "Gas available for execution {} = {} - {} - {} - {} (limit - intrinsic - accessList - data)", gasAvailable, transaction.getGasLimit(), intrinsicGas, - accessListGas); + accessListGas, + blobGas); final WorldUpdater worldUpdater = worldState.updater(); - final Deque messageFrameStack = new ArrayDeque<>(); final ImmutableMap.Builder contextVariablesBuilder = ImmutableMap.builder() .put(KEY_IS_PERSISTING_PRIVATE_STATE, isPersistingPrivateState) @@ -361,7 +360,6 @@ public TransactionProcessingResult processTransaction( final MessageFrame.Builder commonMessageFrameBuilder = MessageFrame.builder() - .messageFrameStack(messageFrameStack) .maxStackSize(maxStackSize) .worldUpdater(worldUpdater.updater()) .initialGas(gasAvailable) @@ -371,7 +369,6 @@ public TransactionProcessingResult processTransaction( .value(transaction.getValue()) .apparentValue(transaction.getValue()) .blockValues(blockHeader) - .depth(0) .completer(__ -> {}) .miningBeneficiary(miningBeneficiary) .blockHashLookup(blockHashLookup) @@ -379,6 +376,13 @@ public TransactionProcessingResult processTransaction( .accessListWarmAddresses(addressList) .accessListWarmStorage(storageList); + if (transaction.getVersionedHashes().isPresent()) { + commonMessageFrameBuilder.versionedHashes( + Optional.of(transaction.getVersionedHashes().get().stream().toList())); + } else { + commonMessageFrameBuilder.versionedHashes(Optional.empty()); + } + final MessageFrame initialFrame; if (transaction.isContractCreation()) { final Address contractAddress = @@ -391,7 +395,6 @@ public TransactionProcessingResult processTransaction( .address(contractAddress) .contract(contractAddress) .inputData(Bytes.EMPTY) - .versionedHashes(transaction.getVersionedHashes()) .code(contractCreationProcessor.getCodeFromEVM(null, initCodeBytes)) .build(); } else { @@ -404,15 +407,13 @@ public TransactionProcessingResult processTransaction( .address(to) .contract(to) .inputData(transaction.getPayload()) - .versionedHashes(transaction.getVersionedHashes()) .code( maybeContract .map(c -> messageCallProcessor.getCodeFromEVM(c.getCodeHash(), c.getCode())) .orElse(CodeV0.EMPTY_CODE)) .build(); } - - messageFrameStack.addFirst(initialFrame); + Deque messageFrameStack = initialFrame.getMessageFrameStack(); if (initialFrame.getCode().isValid()) { while (!messageFrameStack.isEmpty()) { @@ -441,8 +442,15 @@ public TransactionProcessingResult processTransaction( final long baseRefundGas = initialFrame.getGasRefund() + selfDestructRefund; final long refundedGas = refunded(transaction, initialFrame.getRemainingGas(), baseRefundGas); final Wei refundedWei = transactionGasPrice.multiply(refundedGas); + final Wei balancePriorToRefund = sender.getBalance(); senderMutableAccount.incrementBalance(refundedWei); - + LOG.atTrace() + .setMessage("refunded sender {} {} wei ({} -> {})") + .addArgument(senderAddress) + .addArgument(refundedWei) + .addArgument(balancePriorToRefund) + .addArgument(sender.getBalance()) + .log(); final long gasUsedByTransaction = transaction.getGasLimit() - initialFrame.getRemainingGas(); // update the coinbase @@ -498,25 +506,17 @@ public TransactionProcessingResult processTransaction( } } - public MainnetTransactionValidator getTransactionValidator() { - return transactionValidator; - } - - protected void process(final MessageFrame frame, final OperationTracer operationTracer) { + public void process(final MessageFrame frame, final OperationTracer operationTracer) { final AbstractMessageProcessor executor = getMessageProcessor(frame.getType()); executor.process(frame, operationTracer); } private AbstractMessageProcessor getMessageProcessor(final MessageFrame.Type type) { - switch (type) { - case MESSAGE_CALL: - return messageCallProcessor; - case CONTRACT_CREATION: - return contractCreationProcessor; - default: - throw new IllegalStateException("Request for unsupported message processor type " + type); - } + return switch (type) { + case MESSAGE_CALL -> messageCallProcessor; + case CONTRACT_CREATION -> contractCreationProcessor; + }; } protected long refunded( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java index 549828ac906..f70645c407d 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java @@ -1,5 +1,5 @@ /* - * Copyright ConsenSys AG. + * Copyright Hyperledger Besu Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -18,28 +18,40 @@ import org.hyperledger.besu.crypto.SECPSignature; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.datatypes.Blob; +import org.hyperledger.besu.datatypes.BlobsWithCommitments; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.KZGCommitment; +import org.hyperledger.besu.datatypes.KZGProof; +import org.hyperledger.besu.datatypes.TransactionType; +import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.GasLimitCalculator; import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.ethereum.core.TransactionFilter; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.gascalculator.GasCalculator; -import org.hyperledger.besu.plugin.data.TransactionType; import java.math.BigInteger; +import java.util.List; import java.util.Optional; import java.util.Set; +import ethereum.ckzg4844.CKZG4844JNI; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.bouncycastle.crypto.digests.SHA256Digest; + /** * Validates a transaction based on Frontier protocol runtime requirements. * *

    The {@link MainnetTransactionValidator} performs the intrinsic gas cost check on the given * {@link Transaction}. */ -public class MainnetTransactionValidator { +public class MainnetTransactionValidator implements TransactionValidator { + + private static final byte BLOB_COMMITMENT_VERSION_KZG = 0x01; private final GasCalculator gasCalculator; private final GasLimitCalculator gasLimitCalculator; @@ -49,40 +61,10 @@ public class MainnetTransactionValidator { private final Optional chainId; - private Optional transactionFilter = Optional.empty(); private final Set acceptedTransactionTypes; private final int maxInitcodeSize; - public MainnetTransactionValidator( - final GasCalculator gasCalculator, - final GasLimitCalculator gasLimitCalculator, - final boolean checkSignatureMalleability, - final Optional chainId) { - this( - gasCalculator, - gasLimitCalculator, - checkSignatureMalleability, - chainId, - Set.of(TransactionType.FRONTIER)); - } - - public MainnetTransactionValidator( - final GasCalculator gasCalculator, - final GasLimitCalculator gasLimitCalculator, - final boolean checkSignatureMalleability, - final Optional chainId, - final Set acceptedTransactionTypes) { - this( - gasCalculator, - gasLimitCalculator, - FeeMarket.legacy(), - checkSignatureMalleability, - chainId, - acceptedTransactionTypes, - Integer.MAX_VALUE); - } - public MainnetTransactionValidator( final GasCalculator gasCalculator, final GasLimitCalculator gasLimitCalculator, @@ -100,16 +82,7 @@ public MainnetTransactionValidator( this.maxInitcodeSize = maxInitcodeSize; } - /** - * Asserts whether a transaction is valid. - * - * @param transaction the transaction to validate - * @param baseFee optional baseFee - * @param transactionValidationParams Validation parameters that will be used - * @return An empty {@link Optional} if the transaction is considered valid; otherwise an {@code - * Optional} containing a {@link TransactionInvalidReason} that identifies why the transaction - * is invalid. - */ + @Override public ValidationResult validate( final Transaction transaction, final Optional baseFee, @@ -120,6 +93,14 @@ public ValidationResult validate( return signatureResult; } + if (transaction.getType().supportsBlob() && transaction.getBlobsWithCommitments().isPresent()) { + final ValidationResult blobsResult = + validateTransactionsBlobs(transaction); + if (!blobsResult.isValid()) { + return blobsResult; + } + } + final TransactionType transactionType = transaction.getType(); if (!acceptedTransactionTypes.contains(transactionType)) { return ValidationResult.invalid( @@ -174,13 +155,24 @@ private ValidationResult validateCostAndFee( } if (transaction.getType().supportsBlob()) { - final long txTotalDataGas = gasCalculator.dataGasCost(transaction.getBlobCount()); - if (txTotalDataGas > gasLimitCalculator.currentDataGasLimit()) { + final long txTotalBlobGas = gasCalculator.blobGasCost(transaction.getBlobCount()); + if (txTotalBlobGas > gasLimitCalculator.currentBlobGasLimit()) { + return ValidationResult.invalid( + TransactionInvalidReason.TOTAL_BLOB_GAS_TOO_HIGH, + String.format( + "total blob gas %d exceeds max blob gas per block %d", + txTotalBlobGas, gasLimitCalculator.currentBlobGasLimit())); + } + } + + if (transaction.getType().supportsBlob()) { + final long txTotalBlobGas = gasCalculator.blobGasCost(transaction.getBlobCount()); + if (txTotalBlobGas > gasLimitCalculator.currentBlobGasLimit()) { return ValidationResult.invalid( - TransactionInvalidReason.TOTAL_DATA_GAS_TOO_HIGH, + TransactionInvalidReason.TOTAL_BLOB_GAS_TOO_HIGH, String.format( - "total data gas %d exceeds max data gas per block %d", - txTotalDataGas, gasLimitCalculator.currentDataGasLimit())); + "total blob gas %d exceeds max blob gas per block %d", + txTotalBlobGas, gasLimitCalculator.currentBlobGasLimit())); } } @@ -199,6 +191,7 @@ private ValidationResult validateCostAndFee( return ValidationResult.valid(); } + @Override public ValidationResult validateForSender( final Transaction transaction, final Account sender, @@ -214,7 +207,7 @@ public ValidationResult validateForSender( } final Wei upfrontCost = - transaction.getUpfrontCost(gasCalculator.dataGasCost(transaction.getBlobCount())); + transaction.getUpfrontCost(gasCalculator.blobGasCost(transaction.getBlobCount())); if (upfrontCost.compareTo(senderBalance) > 0) { return ValidationResult.invalid( TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE, @@ -247,20 +240,10 @@ public ValidationResult validateForSender( transaction.getSender())); } - if (!isSenderAllowed(transaction, validationParams)) { - return ValidationResult.invalid( - TransactionInvalidReason.TX_SENDER_NOT_AUTHORIZED, - String.format("Sender %s is not on the Account Allowlist", transaction.getSender())); - } - return ValidationResult.valid(); } - public boolean isReplayProtectionSupported() { - return chainId.isPresent(); - } - - public ValidationResult validateTransactionSignature( + private ValidationResult validateTransactionSignature( final Transaction transaction) { if (chainId.isPresent() && (transaction.getChainId().isPresent() && !transaction.getChainId().equals(chainId))) { @@ -299,46 +282,108 @@ public ValidationResult validateTransactionSignature( return ValidationResult.valid(); } - private boolean isSenderAllowed( - final Transaction transaction, final TransactionValidationParams validationParams) { - if (validationParams.checkLocalPermissions() || validationParams.checkOnchainPermissions()) { - return transactionFilter - .map( - c -> - c.permitted( - transaction, - validationParams.checkLocalPermissions(), - validationParams.checkOnchainPermissions())) - .orElse(true); - } else { - return true; + public ValidationResult validateTransactionsBlobs( + final Transaction transaction) { + + if (transaction.getType().supportsBlob() && transaction.getTo().isEmpty()) { + return ValidationResult.invalid( + TransactionInvalidReason.INVALID_TRANSACTION_FORMAT, + "transaction blob transactions cannot have a to address"); + } + + if (transaction.getBlobsWithCommitments().isEmpty()) { + return ValidationResult.invalid( + TransactionInvalidReason.INVALID_BLOBS, + "transaction blobs are empty, cannot verify without blobs"); + } + + BlobsWithCommitments blobsWithCommitments = transaction.getBlobsWithCommitments().get(); + + if (blobsWithCommitments.getBlobs().size() != blobsWithCommitments.getKzgCommitments().size()) { + return ValidationResult.invalid( + TransactionInvalidReason.INVALID_BLOBS, + "transaction blobs and commitments are not the same size"); + } + + if (transaction.getVersionedHashes().isEmpty()) { + return ValidationResult.invalid( + TransactionInvalidReason.INVALID_BLOBS, + "transaction versioned hashes are empty, cannot verify without versioned hashes"); } + final List versionedHashes = transaction.getVersionedHashes().get(); + + for (int i = 0; i < versionedHashes.size(); i++) { + final KZGCommitment commitment = blobsWithCommitments.getKzgCommitments().get(i); + final VersionedHash versionedHash = versionedHashes.get(i); + + if (versionedHash.getVersionId() != BLOB_COMMITMENT_VERSION_KZG) { + return ValidationResult.invalid( + TransactionInvalidReason.INVALID_BLOBS, + "transaction blobs commitment version is not supported. Expected " + + BLOB_COMMITMENT_VERSION_KZG + + ", found " + + versionedHash.getVersionId()); + } + + final VersionedHash calculatedVersionedHash = hashCommitment(commitment); + if (!calculatedVersionedHash.equals(versionedHash)) { + return ValidationResult.invalid( + TransactionInvalidReason.INVALID_BLOBS, + "transaction blobs commitment hash does not match commitment"); + } + } + + final Bytes blobs = + blobsWithCommitments.getBlobs().stream() + .map(Blob::getData) + .reduce(Bytes::concatenate) + .orElseThrow(); + + final Bytes kzgCommitments = + blobsWithCommitments.getKzgCommitments().stream() + .map(KZGCommitment::getData) + .reduce(Bytes::concatenate) + .orElseThrow(); + + final Bytes kzgProofs = + blobsWithCommitments.getKzgProofs().stream() + .map(KZGProof::getData) + .reduce(Bytes::concatenate) + .orElseThrow(); + + final boolean kzgVerification = + CKZG4844JNI.verifyBlobKzgProofBatch( + blobs.toArrayUnsafe(), + kzgCommitments.toArrayUnsafe(), + kzgProofs.toArrayUnsafe(), + blobsWithCommitments.getBlobs().size()); + + if (!kzgVerification) { + return ValidationResult.invalid( + TransactionInvalidReason.INVALID_BLOBS, + "transaction blobs kzg proof verification failed"); + } + + return ValidationResult.valid(); } - public void setTransactionFilter(final TransactionFilter transactionFilter) { - this.transactionFilter = Optional.of(transactionFilter); + /* + private VersionedHash hashCommitment(final Bytes32 commitment) { + return new VersionedHash( + VersionedHash.SHA256_VERSION_ID, Sha256Hash.hash(commitment)); } - /** - * Asserts whether a transaction is valid for the sender account's current state. - * - *

    Note: {@code validate} should be called before getting the sender {@link Account} used in - * this method to ensure that a sender can be extracted from the {@link Transaction}. - * - * @param transaction the transaction to validateMessageFrame.State.COMPLETED_FAILED - * @param sender the sender account state to validate against - * @param allowFutureNonce if true, transactions with nonce equal or higher than the account nonce - * will be considered valid (used when received transactions in the transaction pool). If - * false, only a transaction with the nonce equals the account nonce will be considered valid - * (used when processing transactions). - * @return An empty {@link Optional} if the transaction is considered valid; otherwise an {@code - * Optional} containing a {@link TransactionInvalidReason} that identifies why the transaction - * is invalid. */ - public ValidationResult validateForSender( - final Transaction transaction, final Account sender, final boolean allowFutureNonce) { - final TransactionValidationParams validationParams = - ImmutableTransactionValidationParams.builder().isAllowFutureNonce(allowFutureNonce).build(); - return validateForSender(transaction, sender, validationParams); + + private VersionedHash hashCommitment(final KZGCommitment commitment) { + final SHA256Digest digest = new SHA256Digest(); + digest.update(commitment.getData().toArrayUnsafe(), 0, commitment.getData().size()); + + final byte[] dig = new byte[digest.getDigestSize()]; + + digest.doFinal(dig, 0); + + dig[0] = BLOB_COMMITMENT_VERSION_KZG; + return new VersionedHash(Bytes32.wrap(dig)); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PermissionTransactionValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PermissionTransactionValidator.java new file mode 100644 index 00000000000..5325567d0f9 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PermissionTransactionValidator.java @@ -0,0 +1,75 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.mainnet; + +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.PermissionTransactionFilter; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; +import org.hyperledger.besu.evm.account.Account; + +import java.util.Optional; + +/** + * Validates a transaction based on Frontier protocol runtime requirements. + * + *

    The {@link PermissionTransactionValidator} performs the intrinsic gas cost check on the given + * {@link Transaction}. + */ +public class PermissionTransactionValidator implements TransactionValidator { + private final TransactionValidator delegate; + private final PermissionTransactionFilter permissionTransactionFilter; + + public PermissionTransactionValidator( + final TransactionValidator delegate, + final PermissionTransactionFilter permissionTransactionFilter) { + this.delegate = delegate; + this.permissionTransactionFilter = permissionTransactionFilter; + } + + @Override + public ValidationResult validate( + final Transaction transaction, + final Optional baseFee, + final TransactionValidationParams transactionValidationParams) { + return delegate.validate(transaction, baseFee, transactionValidationParams); + } + + @Override + public ValidationResult validateForSender( + final Transaction transaction, + final Account sender, + final TransactionValidationParams validationParams) { + + if (!isSenderAllowed(transaction, validationParams)) { + return ValidationResult.invalid( + TransactionInvalidReason.TX_SENDER_NOT_AUTHORIZED, + String.format("Sender %s is not on the Account Allowlist", transaction.getSender())); + } + + return delegate.validateForSender(transaction, sender, validationParams); + } + + private boolean isSenderAllowed( + final Transaction transaction, final TransactionValidationParams validationParams) { + if (validationParams.checkLocalPermissions() || validationParams.checkOnchainPermissions()) { + return permissionTransactionFilter.permitted( + transaction, + validationParams.checkLocalPermissions(), + validationParams.checkOnchainPermissions()); + } + return true; + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PrivacySupportingProtocolSchedule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PrivacySupportingProtocolSchedule.java index d841e4b9eba..e882c672fc6 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PrivacySupportingProtocolSchedule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PrivacySupportingProtocolSchedule.java @@ -17,12 +17,13 @@ package org.hyperledger.besu.ethereum.mainnet; -import org.hyperledger.besu.ethereum.core.TransactionFilter; +import org.hyperledger.besu.ethereum.core.PermissionTransactionFilter; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; public interface PrivacySupportingProtocolSchedule { - void setTransactionFilter(final TransactionFilter transactionFilter); + void setPermissionTransactionFilter( + final PermissionTransactionFilter permissionTransactionFilter); void setPublicWorldStateArchiveForPrivacyBlockProcessor( final WorldStateArchive publicWorldStateArchive); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSchedule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSchedule.java index e1a0afbdca3..a249a6b5285 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSchedule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSchedule.java @@ -47,6 +47,11 @@ default ProtocolSpec getForNextBlockHeader( void putTimestampMilestone(final long timestamp, final ProtocolSpec protocolSpec); + default Optional hardforkFor( + final Predicate predicate) { + throw new UnsupportedOperationException("Not implemented"); + } + boolean isOnMilestoneBoundary(final BlockHeader blockHeader); boolean anyMatch(Predicate predicate); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpec.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpec.java index 652acc26c49..3c69f12d648 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpec.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpec.java @@ -38,7 +38,7 @@ public class ProtocolSpec { private final GasLimitCalculator gasLimitCalculator; - private final MainnetTransactionValidator transactionValidator; + private final TransactionValidatorFactory transactionValidatorFactory; private final MainnetTransactionProcessor transactionProcessor; @@ -81,12 +81,13 @@ public class ProtocolSpec { private final DepositsValidator depositsValidator; private final boolean isPoS; + private final boolean isReplayProtectionSupported; /** * Creates a new protocol specification instance. * * @param name the protocol specification name * @param evm the EVM supporting the appropriate operations for this specification - * @param transactionValidator the transaction validator to use + * @param transactionValidatorFactory the transaction validator factory to use * @param transactionProcessor the transaction processor to use * @param privateTransactionProcessor the private transaction processor to use * @param blockHeaderValidator the block header validator to use @@ -111,11 +112,13 @@ public class ProtocolSpec { * @param withdrawalsProcessor the Withdrawals processor to use * @param depositsValidator the withdrawals validator to use * @param isPoS indicates whether the current spec is PoS + * @param isReplayProtectionSupported indicates whether the current spec supports replay + * protection */ public ProtocolSpec( final String name, final EVM evm, - final MainnetTransactionValidator transactionValidator, + final TransactionValidatorFactory transactionValidatorFactory, final MainnetTransactionProcessor transactionProcessor, final PrivateTransactionProcessor privateTransactionProcessor, final BlockHeaderValidator blockHeaderValidator, @@ -139,10 +142,11 @@ public ProtocolSpec( final WithdrawalsValidator withdrawalsValidator, final Optional withdrawalsProcessor, final DepositsValidator depositsValidator, - final boolean isPoS) { + final boolean isPoS, + final boolean isReplayProtectionSupported) { this.name = name; this.evm = evm; - this.transactionValidator = transactionValidator; + this.transactionValidatorFactory = transactionValidatorFactory; this.transactionProcessor = transactionProcessor; this.privateTransactionProcessor = privateTransactionProcessor; this.blockHeaderValidator = blockHeaderValidator; @@ -167,6 +171,7 @@ public ProtocolSpec( this.withdrawalsProcessor = withdrawalsProcessor; this.depositsValidator = depositsValidator; this.isPoS = isPoS; + this.isReplayProtectionSupported = isReplayProtectionSupported; } /** @@ -179,16 +184,16 @@ public String getName() { } /** - * Returns the transaction validator used in this specification. + * Returns the transaction validator factory used in this specification. * - * @return the transaction validator + * @return the transaction validator factory */ - public MainnetTransactionValidator getTransactionValidator() { - return transactionValidator; + public TransactionValidatorFactory getTransactionValidatorFactory() { + return transactionValidatorFactory; } public boolean isReplayProtectionSupported() { - return transactionValidator.isReplayProtectionSupported(); + return isReplayProtectionSupported; } /** diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java index b71ccbda046..7b39ebe2f5f 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java @@ -45,7 +45,7 @@ public class ProtocolSpecBuilder { private Supplier gasCalculatorBuilder; - private GasLimitCalculator gasLimitCalculator; + private Function gasLimitCalculatorBuilder; private Wei blockReward; private boolean skipZeroBlockRewards; private BlockHeaderFunctions blockHeaderFunctions; @@ -53,8 +53,7 @@ public class ProtocolSpecBuilder { private DifficultyCalculator difficultyCalculator; private EvmConfiguration evmConfiguration; private BiFunction evmBuilder; - private BiFunction - transactionValidatorBuilder; + private TransactionValidatorFactoryBuilder transactionValidatorFactoryBuilder; private Function blockHeaderValidatorBuilder; private Function ommerHeaderValidatorBuilder; private Function blockBodyValidatorBuilder; @@ -81,14 +80,16 @@ public class ProtocolSpecBuilder { private BadBlockManager badBlockManager; private PoWHasher powHasher = PoWHasher.ETHASH_LIGHT; private boolean isPoS = false; + private boolean isReplayProtectionSupported = false; public ProtocolSpecBuilder gasCalculator(final Supplier gasCalculatorBuilder) { this.gasCalculatorBuilder = gasCalculatorBuilder; return this; } - public ProtocolSpecBuilder gasLimitCalculator(final GasLimitCalculator gasLimitCalculator) { - this.gasLimitCalculator = gasLimitCalculator; + public ProtocolSpecBuilder gasLimitCalculatorBuilder( + final Function gasLimitCalculatorBuilder) { + this.gasLimitCalculatorBuilder = gasLimitCalculatorBuilder; return this; } @@ -124,10 +125,9 @@ public ProtocolSpecBuilder evmBuilder( return this; } - public ProtocolSpecBuilder transactionValidatorBuilder( - final BiFunction - transactionValidatorBuilder) { - this.transactionValidatorBuilder = transactionValidatorBuilder; + public ProtocolSpecBuilder transactionValidatorFactoryBuilder( + final TransactionValidatorFactoryBuilder transactionValidatorFactoryBuilder) { + this.transactionValidatorFactoryBuilder = transactionValidatorFactoryBuilder; return this; } @@ -270,12 +270,18 @@ public ProtocolSpecBuilder isPoS(final boolean isPoS) { return this; } + public ProtocolSpecBuilder isReplayProtectionSupported( + final boolean isReplayProtectionSupported) { + this.isReplayProtectionSupported = isReplayProtectionSupported; + return this; + } + public ProtocolSpec build(final ProtocolSchedule protocolSchedule) { checkNotNull(gasCalculatorBuilder, "Missing gasCalculator"); - checkNotNull(gasLimitCalculator, "Missing gasLimitCalculator"); + checkNotNull(gasLimitCalculatorBuilder, "Missing gasLimitCalculatorBuilder"); checkNotNull(evmBuilder, "Missing operation registry"); checkNotNull(evmConfiguration, "Missing evm configuration"); - checkNotNull(transactionValidatorBuilder, "Missing transaction validator"); + checkNotNull(transactionValidatorFactoryBuilder, "Missing transaction validator"); checkNotNull(privateTransactionValidatorBuilder, "Missing private transaction validator"); checkNotNull(contractCreationProcessorBuilder, "Missing contract creation processor"); checkNotNull(precompileContractRegistryBuilder, "Missing precompile contract registry"); @@ -299,11 +305,12 @@ public ProtocolSpec build(final ProtocolSchedule protocolSchedule) { checkNotNull(badBlockManager, "Missing bad blocks manager"); final GasCalculator gasCalculator = gasCalculatorBuilder.get(); + final GasLimitCalculator gasLimitCalculator = gasLimitCalculatorBuilder.apply(feeMarket); final EVM evm = evmBuilder.apply(gasCalculator, evmConfiguration); final PrecompiledContractConfiguration precompiledContractConfiguration = new PrecompiledContractConfiguration(gasCalculator, privacyParameters); - final MainnetTransactionValidator transactionValidator = - transactionValidatorBuilder.apply(gasCalculator, gasLimitCalculator); + final TransactionValidatorFactory transactionValidatorFactory = + transactionValidatorFactoryBuilder.apply(gasCalculator, gasLimitCalculator, feeMarket); final AbstractMessageProcessor contractCreationProcessor = contractCreationProcessorBuilder.apply(gasCalculator, evm); final PrecompileContractRegistry precompileContractRegistry = @@ -312,7 +319,11 @@ public ProtocolSpec build(final ProtocolSchedule protocolSchedule) { messageCallProcessorBuilder.apply(evm, precompileContractRegistry); final MainnetTransactionProcessor transactionProcessor = transactionProcessorBuilder.apply( - gasCalculator, transactionValidator, contractCreationProcessor, messageCallProcessor); + gasCalculator, + feeMarket, + transactionValidatorFactory, + contractCreationProcessor, + messageCallProcessor); final BlockHeaderValidator blockHeaderValidator = createBlockHeaderValidator(blockHeaderValidatorBuilder); @@ -326,7 +337,7 @@ public ProtocolSpec build(final ProtocolSchedule protocolSchedule) { // Set private Tx Processor PrivateTransactionProcessor privateTransactionProcessor = createPrivateTransactionProcessor( - transactionValidator, + transactionValidatorFactory, contractCreationProcessor, messageCallProcessor, precompileContractRegistry); @@ -350,7 +361,7 @@ public ProtocolSpec build(final ProtocolSchedule protocolSchedule) { return new ProtocolSpec( name, evm, - transactionValidator, + transactionValidatorFactory, transactionProcessor, privateTransactionProcessor, blockHeaderValidator, @@ -374,11 +385,12 @@ public ProtocolSpec build(final ProtocolSchedule protocolSchedule) { withdrawalsValidator, Optional.ofNullable(withdrawalsProcessor), depositsValidator, - isPoS); + isPoS, + isReplayProtectionSupported); } private PrivateTransactionProcessor createPrivateTransactionProcessor( - final MainnetTransactionValidator transactionValidator, + final TransactionValidatorFactory transactionValidatorFactory, final AbstractMessageProcessor contractCreationProcessor, final AbstractMessageProcessor messageCallProcessor, final PrecompileContractRegistry precompileContractRegistry) { @@ -388,7 +400,7 @@ private PrivateTransactionProcessor createPrivateTransactionProcessor( privateTransactionValidatorBuilder.apply(); privateTransactionProcessor = privateTransactionProcessorBuilder.apply( - transactionValidator, + transactionValidatorFactory, contractCreationProcessor, messageCallProcessor, privateTransactionValidator); @@ -435,14 +447,15 @@ private BlockHeaderValidator createBlockHeaderValidator( public interface TransactionProcessorBuilder { MainnetTransactionProcessor apply( GasCalculator gasCalculator, - MainnetTransactionValidator transactionValidator, + FeeMarket feeMarket, + TransactionValidatorFactory transactionValidatorFactory, AbstractMessageProcessor contractCreationProcessor, AbstractMessageProcessor messageCallProcessor); } public interface PrivateTransactionProcessorBuilder { PrivateTransactionProcessor apply( - MainnetTransactionValidator transactionValidator, + TransactionValidatorFactory transactionValidatorFactory, AbstractMessageProcessor contractCreationProcessor, AbstractMessageProcessor messageCallProcessor, PrivateTransactionValidator privateTransactionValidator); @@ -473,4 +486,9 @@ BlockValidator apply( public interface BlockImporterBuilder { BlockImporter apply(BlockValidator blockValidator); } + + public interface TransactionValidatorFactoryBuilder { + TransactionValidatorFactory apply( + GasCalculator gasCalculator, GasLimitCalculator gasLimitCalculator, FeeMarket feeMarket); + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ScheduledProtocolSpec.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ScheduledProtocolSpec.java index 278f45b9abb..012bb469c6a 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ScheduledProtocolSpec.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ScheduledProtocolSpec.java @@ -25,10 +25,26 @@ public interface ScheduledProtocolSpec { boolean isOnMilestoneBoundary(ProcessableBlockHeader header); - long milestone(); + Hardfork fork(); ProtocolSpec spec(); + public record Hardfork(String name, long milestone) implements Comparable { + @Override + public int compareTo(final Hardfork h) { + if (h == null) { // all non-null hardforks are greater than null + return 1; + } + return this.milestone == h.milestone ? 0 : this.milestone < h.milestone ? -1 : 1; + } + + @Override + public String toString() { + return String.format("%s:%d", name, milestone); + } + } + ; + class TimestampProtocolSpec implements ScheduledProtocolSpec { private final long timestamp; @@ -55,8 +71,8 @@ public boolean isOnMilestoneBoundary(final ProcessableBlockHeader header) { } @Override - public long milestone() { - return timestamp; + public Hardfork fork() { + return new Hardfork(protocolSpec.getName(), timestamp); } @Override @@ -90,8 +106,8 @@ public boolean isOnMilestoneBoundary(final ProcessableBlockHeader header) { } @Override - public long milestone() { - return blockNumber; + public Hardfork fork() { + return new Hardfork(protocolSpec.getName(), blockNumber); } @Override diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidator.java new file mode 100644 index 00000000000..a70de0bcd7f --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidator.java @@ -0,0 +1,55 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.mainnet; + +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; +import org.hyperledger.besu.evm.account.Account; + +import java.util.Optional; + +public interface TransactionValidator { + + /** + * Asserts whether a transaction is valid. + * + * @param transaction the transaction to validate + * @param baseFee optional baseFee + * @param transactionValidationParams Validation parameters that will be used + * @return the result of the validation, in case of invalid transaction the invalid reason is + * present + */ + ValidationResult validate( + Transaction transaction, + Optional baseFee, + TransactionValidationParams transactionValidationParams); + + /** + * Asserts whether a transaction is valid for the sender account's current state. + * + *

    Note: {@code validate} should be called before getting the sender {@link Account} used in + * this method to ensure that a sender can be extracted from the {@link Transaction}. + * + * @param transaction the transaction to validate + * @param sender the account of the sender of the transaction + * @param validationParams to customize the validation according to different scenarios, like + * processing block, adding to the txpool, etc... + * @return the result of the validation, in case of invalid transaction the invalid reason is + * present + */ + ValidationResult validateForSender( + Transaction transaction, Account sender, TransactionValidationParams validationParams); +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidatorFactory.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidatorFactory.java new file mode 100644 index 00000000000..e89ca469a8a --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidatorFactory.java @@ -0,0 +1,96 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.mainnet; + +import org.hyperledger.besu.datatypes.TransactionType; +import org.hyperledger.besu.ethereum.GasLimitCalculator; +import org.hyperledger.besu.ethereum.core.PermissionTransactionFilter; +import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; + +import java.math.BigInteger; +import java.util.Optional; +import java.util.Set; + +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; + +public class TransactionValidatorFactory { + + private volatile Supplier transactionValidatorSupplier; + + public TransactionValidatorFactory( + final GasCalculator gasCalculator, + final GasLimitCalculator gasLimitCalculator, + final boolean checkSignatureMalleability, + final Optional chainId) { + this( + gasCalculator, + gasLimitCalculator, + checkSignatureMalleability, + chainId, + Set.of(TransactionType.FRONTIER)); + } + + public TransactionValidatorFactory( + final GasCalculator gasCalculator, + final GasLimitCalculator gasLimitCalculator, + final boolean checkSignatureMalleability, + final Optional chainId, + final Set acceptedTransactionTypes) { + this( + gasCalculator, + gasLimitCalculator, + FeeMarket.legacy(), + checkSignatureMalleability, + chainId, + acceptedTransactionTypes, + Integer.MAX_VALUE); + } + + public TransactionValidatorFactory( + final GasCalculator gasCalculator, + final GasLimitCalculator gasLimitCalculator, + final FeeMarket feeMarket, + final boolean checkSignatureMalleability, + final Optional chainId, + final Set acceptedTransactionTypes, + final int maxInitcodeSize) { + + this.transactionValidatorSupplier = + Suppliers.memoize( + () -> + new MainnetTransactionValidator( + gasCalculator, + gasLimitCalculator, + feeMarket, + checkSignatureMalleability, + chainId, + acceptedTransactionTypes, + maxInitcodeSize)); + } + + public void setPermissionTransactionFilter( + final PermissionTransactionFilter permissionTransactionFilter) { + final TransactionValidator baseTxValidator = transactionValidatorSupplier.get(); + transactionValidatorSupplier = + Suppliers.memoize( + () -> new PermissionTransactionValidator(baseTxValidator, permissionTransactionFilter)); + } + + public TransactionValidator get() { + return transactionValidatorSupplier.get(); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarket.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarket.java index 68f0ba26a63..ab46beadca5 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarket.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarket.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.mainnet.feemarket; -import org.hyperledger.besu.datatypes.DataGas; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Wei; import java.math.BigInteger; @@ -25,8 +25,8 @@ public class CancunFeeMarket extends LondonFeeMarket { private static final Logger LOG = LoggerFactory.getLogger(CancunFeeMarket.class); - private static final BigInteger MIN_DATA_GAS_PRICE = BigInteger.ONE; - private static final BigInteger DATA_GAS_PRICE_UPDATE_FRACTION = BigInteger.valueOf(2225652); + private static final BigInteger BLOB_GAS_PRICE = BigInteger.ONE; + private static final BigInteger BLOB_GAS_PRICE_UPDATE_FRACTION = BigInteger.valueOf(3338477); public CancunFeeMarket( final long londonForkBlockNumber, final Optional baseFeePerGasOverride) { @@ -39,18 +39,18 @@ public boolean implementsDataFee() { } @Override - public Wei dataPrice(final DataGas excessDataGas) { - final var dataGasPrice = + public Wei blobGasPricePerGas(final BlobGas excessBlobGas) { + final var blobGasPrice = Wei.of( fakeExponential( - MIN_DATA_GAS_PRICE, excessDataGas.toBigInteger(), DATA_GAS_PRICE_UPDATE_FRACTION)); + BLOB_GAS_PRICE, excessBlobGas.toBigInteger(), BLOB_GAS_PRICE_UPDATE_FRACTION)); LOG.atTrace() - .setMessage("parentExcessDataGas: {} dataGasPrice: {}") - .addArgument(excessDataGas::toShortHexString) - .addArgument(dataGasPrice::toHexString) + .setMessage("parentExcessBlobGas: {} blobGasPrice: {}") + .addArgument(excessBlobGas::toShortHexString) + .addArgument(blobGasPrice::toHexString) .log(); - return dataGasPrice; + return blobGasPrice; } private BigInteger fakeExponential( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ExcessBlobGasCalculator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ExcessBlobGasCalculator.java new file mode 100644 index 00000000000..f6372097b7f --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ExcessBlobGasCalculator.java @@ -0,0 +1,42 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.mainnet.feemarket; + +import org.hyperledger.besu.datatypes.BlobGas; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; + +/** Calculates the excess blob gas for a parent block header. */ +public class ExcessBlobGasCalculator { + /** + * public class ExcessBlobGasCalculator { /** Calculates the excess blob gas for a parent block + * header. + * + * @param protocolSpec The protocol specification. + * @param parentHeader The parent block header. + * @return The excess blob gas. + */ + public static BlobGas calculateExcessBlobGasForParent( + final ProtocolSpec protocolSpec, final BlockHeader parentHeader) { + // Blob Data Excess + long headerExcess = + protocolSpec + .getGasCalculator() + .computeExcessBlobGas( + parentHeader.getExcessBlobGas().map(BlobGas::toLong).orElse(0L), + parentHeader.getBlobGasUsed().orElse(0L)); + return BlobGas.of(headerExcess); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/FeeMarket.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/FeeMarket.java index dc20b43438f..637ffb471ec 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/FeeMarket.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/FeeMarket.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.mainnet.feemarket; -import org.hyperledger.besu.datatypes.DataGas; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.feemarket.TransactionPriceCalculator; @@ -57,7 +57,7 @@ static FeeMarket legacy() { return new LegacyFeeMarket(); } - default Wei dataPrice(final DataGas excessDataGas) { + default Wei blobGasPricePerGas(final BlobGas excessBlobGas) { return Wei.ZERO; } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java index 6f454b464eb..2fff3a629fa 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java @@ -46,7 +46,14 @@ public LondonFeeMarket(final long londonForkBlockNumber) { public LondonFeeMarket( final long londonForkBlockNumber, final Optional baseFeePerGasOverride) { - this.txPriceCalculator = TransactionPriceCalculator.eip1559(); + this(TransactionPriceCalculator.eip1559(), londonForkBlockNumber, baseFeePerGasOverride); + } + + protected LondonFeeMarket( + final TransactionPriceCalculator txPriceCalculator, + final long londonForkBlockNumber, + final Optional baseFeePerGasOverride) { + this.txPriceCalculator = txPriceCalculator; this.londonForkBlockNumber = londonForkBlockNumber; this.baseFeeInitialValue = baseFeePerGasOverride.orElse(DEFAULT_BASEFEE_INITIAL_VALUE); this.baseFeeFloor = baseFeeInitialValue.isZero() ? Wei.ZERO : DEFAULT_BASEFEE_FLOOR; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BlobGasValidationRule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BlobGasValidationRule.java new file mode 100644 index 00000000000..e58d378562f --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BlobGasValidationRule.java @@ -0,0 +1,58 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.mainnet.headervalidationrules; + +import org.hyperledger.besu.datatypes.BlobGas; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.mainnet.DetachedBlockHeaderValidationRule; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** Validation rule to check if the block header's excess blob gas matches the calculated value. */ +public class BlobGasValidationRule implements DetachedBlockHeaderValidationRule { + + private static final Logger LOG = LoggerFactory.getLogger(BlobGasValidationRule.class); + + private final GasCalculator gasCalculator; + + public BlobGasValidationRule(final GasCalculator gasCalculator) { + this.gasCalculator = gasCalculator; + } + + /** + * Validates the block header by checking if the header's excess blob gas matches the calculated + * value based on the parent header. + */ + @Override + public boolean validate(final BlockHeader header, final BlockHeader parent) { + long headerExcessBlobGas = header.getExcessBlobGas().map(BlobGas::toLong).orElse(0L); + long parentExcessBlobGas = parent.getExcessBlobGas().map(BlobGas::toLong).orElse(0L); + long parentBlobGasUsed = parent.getBlobGasUsed().orElse(0L); + + long calculatedExcessBlobGas = + gasCalculator.computeExcessBlobGas(parentExcessBlobGas, parentBlobGasUsed); + + if (headerExcessBlobGas != calculatedExcessBlobGas) { + LOG.info( + "Invalid block header: header excessBlobGas {} and calculated excessBlobGas {} do not match", + headerExcessBlobGas, + calculatedExcessBlobGas); + return false; + } + return true; + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionProcessor.java index 4628ef6b151..2eeb29cf32b 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionProcessor.java @@ -20,7 +20,7 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; -import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionValidator; +import org.hyperledger.besu.ethereum.mainnet.TransactionValidatorFactory; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; @@ -34,7 +34,6 @@ import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import java.util.ArrayDeque; import java.util.Deque; import java.util.Map; import java.util.Optional; @@ -49,7 +48,7 @@ public class PrivateTransactionProcessor { private static final Logger LOG = LoggerFactory.getLogger(PrivateTransactionProcessor.class); @SuppressWarnings("unused") - private final MainnetTransactionValidator transactionValidator; + private final TransactionValidatorFactory transactionValidatorFactory; private final PrivateTransactionValidator privateTransactionValidator; @@ -63,13 +62,13 @@ public class PrivateTransactionProcessor { private final boolean clearEmptyAccounts; public PrivateTransactionProcessor( - final MainnetTransactionValidator transactionValidator, + final TransactionValidatorFactory transactionValidatorFactory, final AbstractMessageProcessor contractCreationProcessor, final AbstractMessageProcessor messageCallProcessor, final boolean clearEmptyAccounts, final int maxStackSize, final PrivateTransactionValidator privateTransactionValidator) { - this.transactionValidator = transactionValidator; + this.transactionValidatorFactory = transactionValidatorFactory; this.contractCreationProcessor = contractCreationProcessor; this.messageCallProcessor = messageCallProcessor; this.clearEmptyAccounts = clearEmptyAccounts; @@ -112,10 +111,8 @@ public TransactionProcessingResult processTransaction( final WorldUpdater mutablePrivateWorldStateUpdater = new DefaultMutablePrivateWorldStateUpdater(publicWorldState, privateWorldState); - final Deque messageFrameStack = new ArrayDeque<>(); final MessageFrame.Builder commonMessageFrameBuilder = MessageFrame.builder() - .messageFrameStack(messageFrameStack) .maxStackSize(maxStackSize) .worldUpdater(mutablePrivateWorldStateUpdater) .initialGas(Long.MAX_VALUE) @@ -125,7 +122,6 @@ public TransactionProcessingResult processTransaction( .value(transaction.getValue()) .apparentValue(transaction.getValue()) .blockValues(blockHeader) - .depth(0) .completer(__ -> {}) .miningBeneficiary(miningBeneficiary) .blockHashLookup(blockHashLookup) @@ -169,8 +165,7 @@ public TransactionProcessingResult processTransaction( .build(); } - messageFrameStack.addFirst(initialFrame); - + final Deque messageFrameStack = initialFrame.getMessageFrameStack(); while (!messageFrameStack.isEmpty()) { process(messageFrameStack.peekFirst(), operationTracer); } @@ -211,13 +206,9 @@ private void process(final MessageFrame frame, final OperationTracer operationTr } private AbstractMessageProcessor getMessageProcessor(final MessageFrame.Type type) { - switch (type) { - case MESSAGE_CALL: - return messageCallProcessor; - case CONTRACT_CREATION: - return contractCreationProcessor; - default: - throw new IllegalStateException("Request for unsupported message processor type " + type); - } + return switch (type) { + case MESSAGE_CALL -> messageCallProcessor; + case CONTRACT_CREATION -> contractCreationProcessor; + }; } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/markertransaction/SigningPrivateMarkerTransactionFactory.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/markertransaction/SigningPrivateMarkerTransactionFactory.java index db5156a364c..5463311598b 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/markertransaction/SigningPrivateMarkerTransactionFactory.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/markertransaction/SigningPrivateMarkerTransactionFactory.java @@ -15,10 +15,10 @@ package org.hyperledger.besu.ethereum.privacy.markertransaction; import org.hyperledger.besu.crypto.KeyPair; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.plugin.data.UnsignedPrivateMarkerTransaction; import org.apache.tuweni.bytes.Bytes; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/proof/WorldStateProofProvider.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/proof/WorldStateProofProvider.java index d9f23f39566..16023264b7d 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/proof/WorldStateProofProvider.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/proof/WorldStateProofProvider.java @@ -62,7 +62,7 @@ public Optional getAccountProof( if (!worldStateStorage.isWorldStateAvailable(worldStateRoot, null)) { return Optional.empty(); } else { - final Hash accountHash = Hash.hash(accountAddress); + final Hash accountHash = accountAddress.addressHash(); final Proof accountProof = newAccountStateTrie(worldStateRoot).getValueWithProof(accountHash); @@ -150,7 +150,7 @@ public boolean isValidRangeProof( final Bytes32 endKeyHash, final Bytes32 rootHash, final List proofs, - final TreeMap keys) { + final SortedMap keys) { // check if it's monotonic increasing if (!Ordering.natural().isOrdered(keys.keySet())) { diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/StorageProvider.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/StorageProvider.java index fea099d5769..6cc9741cb22 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/StorageProvider.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/StorageProvider.java @@ -22,9 +22,10 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; -import org.hyperledger.besu.plugin.services.storage.SnappableKeyValueStorage; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; import java.io.Closeable; +import java.util.List; public interface StorageProvider extends Closeable { @@ -39,9 +40,5 @@ BlockchainStorage createBlockchainStorage( KeyValueStorage getStorageBySegmentIdentifier(SegmentIdentifier segment); - SnappableKeyValueStorage getSnappableStorageBySegmentIdentifier(SegmentIdentifier segment); - - boolean isWorldStateIterable(); - - boolean isWorldStateSnappable(); + SegmentedKeyValueStorage getStorageBySegmentIdentifiers(List segment); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueStorageProvider.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueStorageProvider.java index 13ad3270f01..8a7eef8ee5d 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueStorageProvider.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueStorageProvider.java @@ -26,35 +26,35 @@ import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; -import org.hyperledger.besu.plugin.services.storage.SnappableKeyValueStorage; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; +import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorageAdapter; import java.io.IOException; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.function.Function; +import java.util.stream.Collectors; -public class KeyValueStorageProvider implements StorageProvider { +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; - public static final boolean SEGMENT_ISOLATION_SUPPORTED = true; - public static final boolean SNAPSHOT_ISOLATION_UNSUPPORTED = false; +public class KeyValueStorageProvider implements StorageProvider { + private static final Logger LOG = LoggerFactory.getLogger(StorageProvider.class); - protected final Function storageCreator; + protected final Function, SegmentedKeyValueStorage> + segmentedStorageCreator; private final KeyValueStorage worldStatePreimageStorage; - private final boolean isWorldStateIterable; - private final boolean isWorldStateSnappable; - protected final Map storageInstances = new HashMap<>(); + protected final Map, SegmentedKeyValueStorage> storageInstances = + new HashMap<>(); private final ObservableMetricsSystem metricsSystem; public KeyValueStorageProvider( - final Function storageCreator, + final Function, SegmentedKeyValueStorage> segmentedStorageCreator, final KeyValueStorage worldStatePreimageStorage, - final boolean segmentIsolationSupported, - final boolean storageSnapshotIsolationSupported, final ObservableMetricsSystem metricsSystem) { - this.storageCreator = storageCreator; + this.segmentedStorageCreator = segmentedStorageCreator; this.worldStatePreimageStorage = worldStatePreimageStorage; - this.isWorldStateIterable = segmentIsolationSupported; - this.isWorldStateSnappable = storageSnapshotIsolationSupported; this.metricsSystem = metricsSystem; } @@ -90,29 +90,34 @@ public WorldStatePreimageStorage createWorldStatePreimageStorage() { @Override public KeyValueStorage getStorageBySegmentIdentifier(final SegmentIdentifier segment) { - return storageInstances.computeIfAbsent(segment, storageCreator); - } - - @Override - public SnappableKeyValueStorage getSnappableStorageBySegmentIdentifier( - final SegmentIdentifier segment) { - return (SnappableKeyValueStorage) getStorageBySegmentIdentifier(segment); + return new SegmentedKeyValueStorageAdapter( + segment, storageInstances.computeIfAbsent(List.of(segment), segmentedStorageCreator)); } @Override - public boolean isWorldStateIterable() { - return isWorldStateIterable; - } - - @Override - public boolean isWorldStateSnappable() { - return isWorldStateSnappable; + public SegmentedKeyValueStorage getStorageBySegmentIdentifiers( + final List segments) { + return segmentedStorageCreator.apply(segments); } @Override public void close() throws IOException { - for (final KeyValueStorage kvs : storageInstances.values()) { - kvs.close(); - } + storageInstances.entrySet().stream() + .filter(storage -> storage instanceof AutoCloseable) + .forEach( + storage -> { + try { + storage.getValue().close(); + } catch (final IOException e) { + LOG.atWarn() + .setMessage("Failed to close storage instance {}") + .addArgument( + storage.getKey().stream() + .map(SegmentIdentifier::getName) + .collect(Collectors.joining(","))) + .setCause(e) + .log(); + } + }); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueStorageProviderBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueStorageProviderBuilder.java index 2bddd3d5825..47635c9d27a 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueStorageProviderBuilder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueStorageProviderBuilder.java @@ -58,13 +58,9 @@ public KeyValueStorageProvider build() { final KeyValueStorage worldStatePreImageStorage = new LimitedInMemoryKeyValueStorage(DEFAULT_WORLD_STATE_PRE_IMAGE_CACHE_SIZE); - // this tickles init needed for isSegmentIsolationSupported - storageFactory.create(KeyValueSegmentIdentifier.BLOCKCHAIN, commonConfiguration, metricsSystem); return new KeyValueStorageProvider( - segment -> storageFactory.create(segment, commonConfiguration, metricsSystem), + segments -> storageFactory.create(segments, commonConfiguration, metricsSystem), worldStatePreImageStorage, - storageFactory.isSegmentIsolationSupported(), - storageFactory.isSnapshotIsolationSupported(), (ObservableMetricsSystem) metricsSystem); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/WorldStateKeyValueStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/WorldStateKeyValueStorage.java index 007a65f2138..74051b5e9b7 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/WorldStateKeyValueStorage.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/WorldStateKeyValueStorage.java @@ -78,6 +78,11 @@ private Optional getTrieNode(final Bytes32 nodeHash) { } } + @Override + public Optional getTrieNodeUnsafe(final Bytes key) { + return keyValueStorage.get(key.toArrayUnsafe()).map(Bytes::wrap); + } + @Override public FlatDbMode getFlatDbMode() { return FlatDbMode.NO_FLATTENED; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionInvalidReason.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionInvalidReason.java index 12735850953..5b00d5fe521 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionInvalidReason.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionInvalidReason.java @@ -40,14 +40,14 @@ public enum TransactionInvalidReason { INITCODE_TOO_LARGE, NONCE_TOO_FAR_IN_FUTURE_FOR_SENDER, LOWER_NONCE_INVALID_TRANSACTION_EXISTS, - TOTAL_DATA_GAS_TOO_HIGH, + TOTAL_BLOB_GAS_TOO_HIGH, GAS_PRICE_TOO_LOW, GAS_PRICE_BELOW_CURRENT_BASE_FEE, MAX_FEE_PER_GAS_BELOW_CURRENT_BASE_FEE, TX_FEECAP_EXCEEDED, INTERNAL_ERROR, TX_POOL_DISABLED, - + INVALID_BLOBS, // Private Transaction Invalid Reasons PRIVATE_TRANSACTION_INVALID, PRIVATE_TRANSACTION_FAILED, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java index bc457e87e5d..4906378e9f2 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java @@ -14,11 +14,13 @@ */ package org.hyperledger.besu.ethereum.transaction; +import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent; + import org.hyperledger.besu.crypto.SECPSignature; import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.DataGas; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -26,6 +28,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.mainnet.ImmutableTransactionValidationParams; import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; @@ -100,7 +103,10 @@ public Optional process( public Optional processAtHead(final CallParameter callParams) { return process( callParams, - TransactionValidationParams.transactionSimulator(), + ImmutableTransactionValidationParams.builder() + .from(TransactionValidationParams.transactionSimulator()) + .isAllowExceedingBalance(true) + .build(), OperationTracer.NO_TRACING, (mutableWorldState, transactionSimulatorResult) -> transactionSimulatorResult, blockchain.getChainHeadHeader()); @@ -227,11 +233,13 @@ public Optional processWithWorldUpdater( final Optional maybeParentHeader = blockchain.getBlockHeader(blockHeaderToProcess.getParentHash()); - final Wei dataGasPrice = + final Wei blobGasPrice = protocolSpec .getFeeMarket() - .dataPrice( - maybeParentHeader.flatMap(BlockHeader::getExcessDataGas).orElse(DataGas.ZERO)); + .blobGasPricePerGas( + maybeParentHeader + .map(parent -> calculateExcessBlobGasForParent(protocolSpec, parent)) + .orElse(BlobGas.ZERO)); final Transaction transaction = maybeTransaction.get(); final TransactionProcessingResult result = @@ -247,7 +255,7 @@ public Optional processWithWorldUpdater( false, transactionValidationParams, operationTracer, - dataGasPrice); + blobGasPrice); return Optional.of(new TransactionSimulatorResult(transaction, result)); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracer.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracer.java index 8d8287a82de..07a10e218ab 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracer.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracer.java @@ -49,6 +49,7 @@ public class DebugOperationTracer implements OperationTracer { private long gasRemaining; private Bytes inputData; private int pc; + private int depth; public DebugOperationTracer(final TraceOptions options) { this.options = options; @@ -58,16 +59,16 @@ public DebugOperationTracer(final TraceOptions options) { public void tracePreExecution(final MessageFrame frame) { preExecutionStack = captureStack(frame); gasRemaining = frame.getRemainingGas(); - if (lastFrame != null && frame.getMessageStackDepth() > lastFrame.getDepth()) + if (lastFrame != null && frame.getDepth() > lastFrame.getDepth()) inputData = frame.getInputData().copy(); else inputData = frame.getInputData(); pc = frame.getPC(); + depth = frame.getDepth(); } @Override public void tracePostExecution(final MessageFrame frame, final OperationResult operationResult) { final Operation currentOperation = frame.getCurrentOperation(); - final int depth = frame.getMessageStackDepth(); final String opcode = currentOperation.getName(); final WorldUpdater worldUpdater = frame.getWorldUpdater(); final Bytes outputData = frame.getOutputData(); @@ -122,7 +123,7 @@ public void tracePrecompileCall( frame.getRemainingGas(), OptionalLong.empty(), frame.getGasRefund(), - frame.getMessageStackDepth(), + frame.getDepth(), Optional.empty(), frame.getRecipientAddress(), frame.getValue(), @@ -168,7 +169,7 @@ public void traceAccountCreationResult( frame.getRemainingGas(), OptionalLong.empty(), frame.getGasRefund(), - frame.getMessageStackDepth(), + frame.getDepth(), Optional.of(exceptionalHaltReason), frame.getRecipientAddress(), frame.getValue(), diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutableWorldState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutableWorldState.java index e18931a4ef1..b9283d50da0 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutableWorldState.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutableWorldState.java @@ -112,7 +112,7 @@ public Hash frontierRootHash() { @Override public Account get(final Address address) { - final Hash addressHash = Hash.hash(address); + final Hash addressHash = address.addressHash(); return accountStateTrie .get(addressHash) .map(bytes -> deserializeAccount(address, addressHash, bytes)) @@ -344,7 +344,7 @@ protected Updater(final DefaultMutableWorldState world) { @Override protected WorldStateAccount getForMutation(final Address address) { final DefaultMutableWorldState wrapped = wrappedWorldView(); - final Hash addressHash = Hash.hash(address); + final Hash addressHash = address.addressHash(); return wrapped .accountStateTrie .get(addressHash) @@ -373,7 +373,7 @@ public void commit() { final DefaultMutableWorldState wrapped = wrappedWorldView(); for (final Address address : getDeletedAccounts()) { - final Hash addressHash = Hash.hash(address); + final Hash addressHash = address.addressHash(); wrapped.accountStateTrie.remove(addressHash); wrapped.updatedStorageTries.remove(address); wrapped.updatedAccountCode.remove(address); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateStorage.java index 87527ed75b5..3bb6a0dfe78 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateStorage.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateStorage.java @@ -33,6 +33,15 @@ public interface WorldStateStorage { Optional getAccountStorageTrieNode(Hash accountHash, Bytes location, Bytes32 nodeHash); + /** + * This method allows obtaining a TrieNode in an unsafe manner, without verifying the consistency + * of the obtained node. Checks such as node hash verification are not performed here. + * + * @param key of the trie node + * @return value of the trie node + */ + Optional getTrieNodeUnsafe(Bytes key); + Optional getNodeData(Bytes location, Bytes32 hash); FlatDbMode getFlatDbMode(); diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlobTestFixture.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlobTestFixture.java new file mode 100644 index 00000000000..41a70803427 --- /dev/null +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlobTestFixture.java @@ -0,0 +1,102 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hyperledger.besu.ethereum.core; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +import org.hyperledger.besu.datatypes.Blob; +import org.hyperledger.besu.datatypes.BlobsWithCommitments; +import org.hyperledger.besu.datatypes.KZGCommitment; +import org.hyperledger.besu.datatypes.KZGProof; +import org.hyperledger.besu.datatypes.VersionedHash; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import ethereum.ckzg4844.CKZG4844JNI; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.bouncycastle.crypto.digests.SHA256Digest; + +public class BlobTestFixture { + + public BlobTestFixture() { + try { + CKZG4844JNI.loadNativeLibrary(CKZG4844JNI.Preset.MAINNET); + CKZG4844JNI.loadTrustedSetupFromResource( + "/kzg-trusted-setups/mainnet.txt", BlobTestFixture.class); + + } catch (Exception e) { + fail("Failed to compute commitment", e); + } + } + + record BlobTriplet( + Blob blob, KZGCommitment kzgCommitment, KZGProof kzgProof, VersionedHash versionedHash) {} + ; + + public BlobTriplet createBlobTriplet() { + byte[] rawMaterial = {}; + try (InputStream readme = + BlobTestFixture.class.getResourceAsStream( + "/org/hyperledger/besu/ethereum/core/encoding/BlobDataFixture.bin")) { + rawMaterial = readme.readAllBytes(); + } catch (IOException e) { + fail("Failed to read blob file", e); + } + + Bytes commitment = Bytes.wrap(CKZG4844JNI.blobToKzgCommitment(rawMaterial)); + + assertThat(commitment.size()).isEqualTo(48); + Bytes proof = Bytes.wrap(CKZG4844JNI.computeBlobKzgProof(rawMaterial, commitment.toArray())); + VersionedHash versionedHash = hashCommitment(new KZGCommitment(commitment)); + return new BlobTriplet( + new Blob(Bytes.wrap(rawMaterial)), + new KZGCommitment(commitment), + new KZGProof(proof), + versionedHash); + } + + public BlobsWithCommitments createBlobsWithCommitments(final int blobCount) { + List blobs = new ArrayList<>(); + List commitments = new ArrayList<>(); + List proofs = new ArrayList<>(); + List versionedHashes = new ArrayList<>(); + for (int i = 0; i < blobCount; i++) { + BlobTriplet blobTriplet = createBlobTriplet(); + blobs.add(blobTriplet.blob()); + commitments.add(blobTriplet.kzgCommitment()); + proofs.add(blobTriplet.kzgProof()); + versionedHashes.add(blobTriplet.versionedHash()); + } + return new BlobsWithCommitments(commitments, blobs, proofs, versionedHashes); + } + + private VersionedHash hashCommitment(final KZGCommitment commitment) { + final SHA256Digest digest = new SHA256Digest(); + digest.update(commitment.getData().toArrayUnsafe(), 0, commitment.getData().size()); + + final byte[] dig = new byte[digest.getDigestSize()]; + + digest.doFinal(dig, 0); + + dig[0] = VersionedHash.SHA256_VERSION_ID; + return new VersionedHash(Bytes32.wrap(dig)); + } +} diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java index 000d2e45e4c..cb17b1ee036 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java @@ -25,6 +25,8 @@ import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; +import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.mainnet.BodyValidation; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; @@ -36,7 +38,6 @@ import org.hyperledger.besu.evm.log.LogTopic; import org.hyperledger.besu.evm.log.LogsBloomFilter; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import org.hyperledger.besu.plugin.data.TransactionType; import java.math.BigInteger; import java.security.InvalidAlgorithmParameterException; @@ -441,8 +442,8 @@ private Transaction blobTransaction(final Bytes payload, final Address to) { .value(Wei.of(positiveLong())) .payload(payload) .chainId(BigInteger.ONE) - .maxFeePerDataGas(Wei.of(1)) - .versionedHashes(List.of(Hash.fromHexStringLenient("0x29"))) + .maxFeePerBlobGas(Wei.of(1)) + .versionedHashes(List.of(VersionedHash.DEFAULT_VERSIONED_HASH)) .signAndBuild(generateKeyPair()); } @@ -673,7 +674,7 @@ public static class BlockOptions { private Optional withdrawalsRoot = Optional.empty(); private Optional depositsRoot = Optional.empty(); - private Optional> maybeMaxFeePerDataGas = Optional.empty(); + private Optional> maybeMaxFeePerBlobGas = Optional.empty(); public static BlockOptions create() { return new BlockOptions(); @@ -873,12 +874,12 @@ public BlockOptions setDepositsRoot(final Hash depositsRoot) { return this; } - public Optional getMaxFeePerDataGas(final Optional defaultValue) { - return maybeMaxFeePerDataGas.orElse(defaultValue); + public Optional getMaxFeePerBlobGas(final Optional defaultValue) { + return maybeMaxFeePerBlobGas.orElse(defaultValue); } - public BlockOptions setMaxFeePerDataGas(final Optional maxFeePerDataGas) { - this.maybeMaxFeePerDataGas = Optional.of(maxFeePerDataGas); + public BlockOptions setMaxFeePerBlobGas(final Optional maxFeePerBlobGas) { + this.maybeMaxFeePerBlobGas = Optional.of(maxFeePerBlobGas); return this; } } diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockHeaderTestFixture.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockHeaderTestFixture.java index d6778a2eaa4..221c32ff00f 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockHeaderTestFixture.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockHeaderTestFixture.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.core; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; @@ -51,6 +52,8 @@ public class BlockHeaderTestFixture { private Optional withdrawalsRoot = Optional.empty(); private Optional depositsRoot = Optional.empty(); private BlockHeaderFunctions blockHeaderFunctions = new MainnetBlockHeaderFunctions(); + private Optional excessBlobGas = Optional.empty(); + private Optional blobGasUsed = Optional.empty(); public BlockHeader buildHeader() { final BlockHeaderBuilder builder = BlockHeaderBuilder.create(); @@ -72,6 +75,8 @@ public BlockHeader buildHeader() { builder.mixHash(mixHash); builder.nonce(nonce); withdrawalsRoot.ifPresent(builder::withdrawalsRoot); + excessBlobGas.ifPresent(builder::excessBlobGas); + blobGasUsed.ifPresent(builder::blobGasUsed); depositsRoot.ifPresent(builder::depositsRoot); builder.blockHeaderFunctions(blockHeaderFunctions); @@ -173,6 +178,16 @@ public BlockHeaderTestFixture depositsRoot(final Hash depositsRoot) { return this; } + public BlockHeaderTestFixture excessBlobGas(final BlobGas excessBlobGas) { + this.excessBlobGas = Optional.ofNullable(excessBlobGas); + return this; + } + + public BlockHeaderTestFixture blobGasUsed(final Long blobGasUsed) { + this.blobGasUsed = Optional.ofNullable(blobGasUsed); + return this; + } + public BlockHeaderTestFixture blockHeaderFunctions( final BlockHeaderFunctions blockHeaderFunctions) { this.blockHeaderFunctions = blockHeaderFunctions; diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockSyncTestUtils.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockSyncTestUtils.java index a2d3740de96..7ff04db539a 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockSyncTestUtils.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockSyncTestUtils.java @@ -19,12 +19,11 @@ import org.hyperledger.besu.testutil.BlockTestUtil; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; -import org.junit.rules.TemporaryFolder; - public final class BlockSyncTestUtils { private BlockSyncTestUtils() { @@ -33,10 +32,9 @@ private BlockSyncTestUtils() { public static List firstBlocks(final int count) { final List result = new ArrayList<>(count); - final TemporaryFolder temp = new TemporaryFolder(); try { - temp.create(); - final Path blocks = temp.newFile().toPath(); + Path tempDir = Files.createTempDirectory("tempDir"); + final Path blocks = tempDir.resolve("blocks"); final BlockHeaderFunctions blockHeaderFunctions = new MainnetBlockHeaderFunctions(); BlockTestUtil.write1000Blocks(blocks); try (final RawBlockIterator iterator = new RawBlockIterator(blocks, blockHeaderFunctions)) { @@ -46,8 +44,6 @@ public static List firstBlocks(final int count) { } } catch (final IOException ex) { throw new IllegalStateException(ex); - } finally { - temp.delete(); } return result; } diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockchainSetupUtil.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockchainSetupUtil.java index 5b9fc1fb01a..c80f4d7705f 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockchainSetupUtil.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockchainSetupUtil.java @@ -52,7 +52,6 @@ import com.google.common.base.Charsets; import com.google.common.io.Resources; -import org.junit.rules.TemporaryFolder; public class BlockchainSetupUtil { private final GenesisState genesisState; @@ -162,9 +161,7 @@ private static BlockchainSetupUtil create( final ProtocolScheduleProvider protocolScheduleProvider, final ProtocolContextProvider protocolContextProvider, final EthScheduler scheduler) { - final TemporaryFolder temp = new TemporaryFolder(); try { - temp.create(); final String genesisJson = Resources.toString(chainResources.getGenesisURL(), Charsets.UTF_8); final GenesisConfigFile genesisConfigFile = GenesisConfigFile.fromConfig(genesisJson); @@ -202,8 +199,6 @@ private static BlockchainSetupUtil create( scheduler); } catch (final IOException | URISyntaxException ex) { throw new IllegalStateException(ex); - } finally { - temp.delete(); } } diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/InMemoryKeyValueStorageProvider.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/InMemoryKeyValueStorageProvider.java index 7c1dd689bcf..3687643c6d9 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/InMemoryKeyValueStorageProvider.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/InMemoryKeyValueStorageProvider.java @@ -33,15 +33,14 @@ import org.hyperledger.besu.ethereum.worldstate.DefaultWorldStateArchive; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; +import org.hyperledger.besu.services.kvstore.SegmentedInMemoryKeyValueStorage; public class InMemoryKeyValueStorageProvider extends KeyValueStorageProvider { public InMemoryKeyValueStorageProvider() { super( - segmentIdentifier -> new InMemoryKeyValueStorage(), + segmentIdentifiers -> new SegmentedInMemoryKeyValueStorage(), new InMemoryKeyValueStorage(), - SEGMENT_ISOLATION_SUPPORTED, - SNAPSHOT_ISOLATION_UNSUPPORTED, new NoOpMetricsSystem()); } diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/MessageFrameTestFixture.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/MessageFrameTestFixture.java index 6a3165c5118..bfd56cbaa5d 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/MessageFrameTestFixture.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/MessageFrameTestFixture.java @@ -26,9 +26,7 @@ import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Deque; import java.util.List; import java.util.Optional; @@ -40,8 +38,8 @@ public class MessageFrameTestFixture { public static final Address DEFAUT_ADDRESS = AddressHelpers.ofValue(244259721); private static final int maxStackSize = DEFAULT_MAX_STACK_SIZE; + private MessageFrame parentFrame; private MessageFrame.Type type = MessageFrame.Type.MESSAGE_CALL; - private Deque messageFrameStack = new ArrayDeque<>(); private Optional blockchain = Optional.empty(); private Optional worldUpdater = Optional.empty(); private long initialGas = Long.MAX_VALUE; @@ -55,17 +53,16 @@ public class MessageFrameTestFixture { private Code code = CodeV0.EMPTY_CODE; private final List stackItems = new ArrayList<>(); private Optional blockHeader = Optional.empty(); - private int depth = 0; private Optional blockHashLookup = Optional.empty(); private ExecutionContextTestFixture executionContextTestFixture; - public MessageFrameTestFixture type(final MessageFrame.Type type) { - this.type = type; + public MessageFrameTestFixture parentFrame(final MessageFrame parentFrame) { + this.parentFrame = parentFrame; return this; } - MessageFrameTestFixture messageFrameStack(final Deque messageFrameStack) { - this.messageFrameStack = messageFrameStack; + public MessageFrameTestFixture type(final MessageFrame.Type type) { + this.type = type; return this; } @@ -140,11 +137,6 @@ public MessageFrameTestFixture blockHeader(final BlockHeader blockHeader) { return this; } - public MessageFrameTestFixture depth(final int depth) { - this.depth = depth; - return this; - } - public MessageFrameTestFixture pushStackItem(final UInt256 item) { stackItems.add(item); return this; @@ -161,8 +153,8 @@ public MessageFrame build() { this.blockHeader.orElseGet(() -> localBlockchain.getBlockHeader(0).get()); final MessageFrame frame = MessageFrame.builder() + .parentMessageFrame(parentFrame) .type(type) - .messageFrameStack(messageFrameStack) .worldUpdater(worldUpdater.orElseGet(this::createDefaultWorldUpdater)) .initialGas(initialGas) .address(address) @@ -175,7 +167,6 @@ public MessageFrame build() { .contract(contract) .code(code) .blockValues(localBlockHeader) - .depth(depth) .completer(c -> {}) .miningBeneficiary(localBlockHeader.getCoinbase()) .blockHashLookup( diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/MilestoneStreamingProtocolSchedule.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/MilestoneStreamingProtocolSchedule.java index ed30fee9a50..4f50d83476f 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/MilestoneStreamingProtocolSchedule.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/MilestoneStreamingProtocolSchedule.java @@ -29,7 +29,7 @@ public MilestoneStreamingProtocolSchedule(final DefaultProtocolSchedule protocol public Stream streamMilestoneBlocks() { return protocolSpecs.stream() - .sorted(Comparator.comparing(ScheduledProtocolSpec::milestone)) - .map(ScheduledProtocolSpec::milestone); + .sorted(Comparator.comparing(ScheduledProtocolSpec::fork)) + .map(s -> s.fork().milestone()); } } diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/NonBesuBlockHeader.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/NonBesuBlockHeader.java index e8c1b58c66b..f1185d9a781 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/NonBesuBlockHeader.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/NonBesuBlockHeader.java @@ -124,7 +124,12 @@ public Hash getBlockHash() { } @Override - public Optional getExcessDataGas() { + public Optional getExcessBlobGas() { + return Optional.empty(); + } + + @Override + public Optional getBlobGasUsed() { return Optional.empty(); } } diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/PrivateTransactionDataFixture.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/PrivateTransactionDataFixture.java index a27c7ad0f89..8a6ce281b9c 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/PrivateTransactionDataFixture.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/PrivateTransactionDataFixture.java @@ -23,6 +23,7 @@ import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.enclave.types.ReceiveResponse; import org.hyperledger.besu.ethereum.privacy.PrivateTransaction; @@ -31,7 +32,6 @@ import org.hyperledger.besu.ethereum.privacy.storage.PrivateBlockMetadata; import org.hyperledger.besu.ethereum.privacy.storage.PrivateTransactionMetadata; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; -import org.hyperledger.besu.plugin.data.TransactionType; import java.math.BigInteger; import java.util.Collections; diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TransactionTestFixture.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TransactionTestFixture.java index d766abf1017..631158ce46d 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TransactionTestFixture.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TransactionTestFixture.java @@ -16,23 +16,19 @@ import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.BlobsWithCommitments; +import org.hyperledger.besu.datatypes.TransactionType; +import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.evm.AccessListEntry; -import org.hyperledger.besu.plugin.data.TransactionType; import java.math.BigInteger; import java.util.List; import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; public class TransactionTestFixture { - private static final Hash DEFAULT_VERSIONED_HASH = - Hash.wrap( - Bytes32.wrap( - Bytes.concatenate(Bytes.fromHexString("0x01"), Bytes.repeat((byte) 42, 31)))); private TransactionType transactionType = TransactionType.FRONTIER; @@ -53,11 +49,12 @@ public class TransactionTestFixture { private Optional maxPriorityFeePerGas = Optional.empty(); private Optional maxFeePerGas = Optional.empty(); - private Optional maxFeePerDataGas = Optional.empty(); + private Optional maxFeePerBlobGas = Optional.empty(); private Optional> accessListEntries = Optional.empty(); - private Optional> versionedHashes = Optional.empty(); + private Optional> versionedHashes = Optional.empty(); + private Optional blobs = Optional.empty(); private Optional v = Optional.empty(); public Transaction createTransaction(final KeyPair keys) { @@ -87,8 +84,13 @@ public Transaction createTransaction(final KeyPair keys) { builder.maxPriorityFeePerGas(maxPriorityFeePerGas.orElse(Wei.of(500))); builder.maxFeePerGas(maxFeePerGas.orElse(Wei.of(5000))); builder.accessList(accessListEntries.orElse(List.of())); - builder.maxFeePerDataGas(maxFeePerDataGas.orElse(Wei.ONE)); - builder.versionedHashes(versionedHashes.orElse(List.of(DEFAULT_VERSIONED_HASH))); + builder.maxFeePerBlobGas(maxFeePerBlobGas.orElse(Wei.ONE)); + builder.versionedHashes( + versionedHashes.orElse(List.of(VersionedHash.DEFAULT_VERSIONED_HASH))); + blobs.ifPresent( + bwc -> { + builder.kzgBlobs(bwc.getKzgCommitments(), bwc.getBlobs(), bwc.getKzgProofs()); + }); break; } @@ -154,8 +156,8 @@ public TransactionTestFixture maxFeePerGas(final Optional maxFeePerGas) { return this; } - public TransactionTestFixture maxFeePerDataGas(final Optional maxFeePerDataGas) { - this.maxFeePerDataGas = maxFeePerDataGas; + public TransactionTestFixture maxFeePerBlobGas(final Optional maxFeePerBlobGas) { + this.maxFeePerBlobGas = maxFeePerBlobGas; return this; } @@ -164,8 +166,9 @@ public TransactionTestFixture accessList(final List accessListE return this; } - public TransactionTestFixture versionedHashes(final List versionedHashes) { - this.versionedHashes = Optional.ofNullable(versionedHashes); + public TransactionTestFixture versionedHashes( + final Optional> versionedHashes) { + this.versionedHashes = versionedHashes; return this; } @@ -173,4 +176,9 @@ public TransactionTestFixture v(final Optional v) { this.v = v; return this; } + + public TransactionTestFixture blobsWithCommitments(final Optional blobs) { + this.blobs = blobs; + return this; + } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/BlockImportExceptionHandlingTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/BlockImportExceptionHandlingTest.java index e1b4bc9b8e1..b936ed28fa3 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/BlockImportExceptionHandlingTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/BlockImportExceptionHandlingTest.java @@ -52,8 +52,8 @@ import java.util.Optional; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; public class BlockImportExceptionHandlingTest { @@ -101,7 +101,7 @@ public class BlockImportExceptionHandlingTest { private MainnetBlockValidator mainnetBlockValidator; - @Before + @BeforeEach public void setup() { when(protocolContext.getBlockchain()).thenReturn(blockchain); when(protocolContext.getWorldStateArchive()).thenReturn(worldStateArchive); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/MainnetBlockValidatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/MainnetBlockValidatorTest.java index dbee1a7ceaa..9973fe8212c 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/MainnetBlockValidatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/MainnetBlockValidatorTest.java @@ -39,8 +39,8 @@ import java.util.Optional; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class MainnetBlockValidatorTest { @@ -55,7 +55,7 @@ public class MainnetBlockValidatorTest { private MainnetBlockValidator mainnetBlockValidator; private Block badBlock; - @Before + @BeforeEach public void setup() { when(protocolContext.getBlockchain()).thenReturn(blockchain); when(protocolContext.getWorldStateArchive()).thenReturn(worldStateArchive); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/AbstractIsolationTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/AbstractIsolationTests.java index a441408c240..e787b766849 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/AbstractIsolationTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/AbstractIsolationTests.java @@ -16,6 +16,10 @@ package org.hyperledger.besu.ethereum.bonsai; import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryBlockchain; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import org.hyperledger.besu.config.GenesisAllocation; import org.hyperledger.besu.config.GenesisConfigFile; @@ -37,13 +41,17 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.SealableBlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; +import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolReplacementHandler; @@ -62,8 +70,6 @@ import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBFactoryConfiguration; -import java.io.File; -import java.io.IOException; import java.nio.file.Path; import java.util.Arrays; import java.util.Collections; @@ -76,14 +82,14 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Before; -import org.junit.Rule; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.io.TempDir; public abstract class AbstractIsolationTests { protected BonsaiWorldStateProvider archive; protected BonsaiWorldStateKeyValueStorage bonsaiWorldStateStorage; protected ProtocolContext protocolContext; + protected EthContext ethContext; final Function asKeyPair = key -> SignatureAlgorithmFactory.getInstance() @@ -125,10 +131,11 @@ public abstract class AbstractIsolationTests { .collect(Collectors.toList()); KeyPair sender1 = asKeyPair.apply(accounts.get(0).getPrivateKey().get()); + TransactionPool transactionPool; - @Rule public final TemporaryFolder tempData = new TemporaryFolder(); + @TempDir private Path tempData; - @Before + @BeforeEach public void createStorage() { bonsaiWorldStateStorage = (BonsaiWorldStateKeyValueStorage) @@ -144,48 +151,55 @@ public void createStorage() { var ws = archive.getMutable(); genesisState.writeStateTo(ws); protocolContext = new ProtocolContext(blockchain, archive, null, Optional.empty()); + ethContext = mock(EthContext.class, RETURNS_DEEP_STUBS); + when(ethContext.getEthPeers().subscribeConnect(any())).thenReturn(1L); + transactionPool = + new TransactionPool( + () -> sorter, + protocolSchedule, + protocolContext, + mock(TransactionBroadcaster.class), + ethContext, + mock(MiningParameters.class), + txPoolMetrics, + poolConfiguration); + transactionPool.setEnabled(); } // storage provider which uses a temporary directory based rocksdb protected StorageProvider createKeyValueStorageProvider() { - try { - tempData.create(); - return new KeyValueStorageProviderBuilder() - .withStorageFactory( - new RocksDBKeyValueStorageFactory( - () -> - new RocksDBFactoryConfiguration( - 1024 /* MAX_OPEN_FILES*/, - 4 /*BACKGROUND_THREAD_COUNT*/, - 8388608 /*CACHE_CAPACITY*/, - false), - Arrays.asList(KeyValueSegmentIdentifier.values()), - 2, - RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS)) - .withCommonConfiguration( - new BesuConfiguration() { + return new KeyValueStorageProviderBuilder() + .withStorageFactory( + new RocksDBKeyValueStorageFactory( + () -> + new RocksDBFactoryConfiguration( + 1024 /* MAX_OPEN_FILES*/, + 4 /*BACKGROUND_THREAD_COUNT*/, + 8388608 /*CACHE_CAPACITY*/, + false), + Arrays.asList(KeyValueSegmentIdentifier.values()), + 2, + RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS)) + .withCommonConfiguration( + new BesuConfiguration() { - @Override - public Path getStoragePath() { - return new File(tempData.getRoot().toString() + File.pathSeparator + "database") - .toPath(); - } + @Override + public Path getStoragePath() { + return tempData.resolve("database"); + } - @Override - public Path getDataPath() { - return tempData.getRoot().toPath(); - } + @Override + public Path getDataPath() { + return tempData; + } - @Override - public int getDatabaseVersion() { - return 2; - } - }) - .withMetricsSystem(new NoOpMetricsSystem()) - .build(); - } catch (IOException e) { - throw new RuntimeException(e); - } + @Override + public int getDatabaseVersion() { + return 2; + } + }) + .withMetricsSystem(new NoOpMetricsSystem()) + .build(); } static class TestBlockCreator extends AbstractBlockCreator { @@ -194,7 +208,7 @@ private TestBlockCreator( final MiningBeneficiaryCalculator miningBeneficiaryCalculator, final Supplier> targetGasLimitSupplier, final ExtraDataCalculator extraDataCalculator, - final PendingTransactions pendingTransactions, + final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, final Wei minTransactionGasPrice, @@ -205,7 +219,7 @@ private TestBlockCreator( miningBeneficiaryCalculator, targetGasLimitSupplier, extraDataCalculator, - pendingTransactions, + transactionPool, protocolContext, protocolSchedule, minTransactionGasPrice, @@ -218,13 +232,13 @@ static TestBlockCreator forHeader( final BlockHeader parentHeader, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, - final PendingTransactions sorter) { + final TransactionPool transactionPool) { return new TestBlockCreator( Address.ZERO, __ -> Address.ZERO, () -> Optional.of(30_000_000L), __ -> Bytes.fromHexString("deadbeef"), - sorter, + transactionPool, protocolContext, protocolSchedule, Wei.of(1L), @@ -260,7 +274,7 @@ protected Block forTransactions(final List transactions) { protected Block forTransactions( final List transactions, final BlockHeader forHeader) { - return TestBlockCreator.forHeader(forHeader, protocolContext, protocolSchedule, sorter) + return TestBlockCreator.forHeader(forHeader, protocolContext, protocolSchedule, transactionPool) .createBlock(transactions, Collections.emptyList(), System.currentTimeMillis()) .getBlock(); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiSnapshotIsolationTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiSnapshotIsolationTests.java index 384e667bda9..ed4b4549674 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiSnapshotIsolationTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiSnapshotIsolationTests.java @@ -24,11 +24,11 @@ import java.util.List; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class BonsaiSnapshotIsolationTests extends AbstractIsolationTests { @Test diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchiveTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchiveTest.java index eff31c523a9..b492b67ffdb 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchiveTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchiveTest.java @@ -18,7 +18,10 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage.WORLD_BLOCK_HASH_KEY; import static org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage.WORLD_ROOT_HASH_KEY; +import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.BLOCKCHAIN; +import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; @@ -39,53 +42,61 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.ethereum.storage.StorageProvider; -import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; +import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction; -import org.hyperledger.besu.plugin.services.storage.SnappableKeyValueStorage; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction; import java.util.Optional; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class BonsaiWorldStateArchiveTest { - final BlockHeaderTestFixture blockBuilder = new BlockHeaderTestFixture(); @Mock Blockchain blockchain; @Mock StorageProvider storageProvider; - @Mock SnappableKeyValueStorage keyValueStorage; - + @Mock SegmentedKeyValueStorage segmentedKeyValueStorage; + @Mock KeyValueStorage trieLogStorage; + @Mock SegmentedKeyValueStorageTransaction segmentedKeyValueStorageTransaction; BonsaiWorldStateProvider bonsaiWorldStateArchive; @Mock TrieLogManager trieLogManager; - @Before + @BeforeEach public void setUp() { - when(storageProvider.getStorageBySegmentIdentifier(any(KeyValueSegmentIdentifier.class))) - .thenReturn(keyValueStorage); + when(storageProvider.getStorageBySegmentIdentifiers(anyList())) + .thenReturn(segmentedKeyValueStorage); + when(segmentedKeyValueStorage.startTransaction()) + .thenReturn(segmentedKeyValueStorageTransaction); + when(storageProvider.getStorageBySegmentIdentifier(any())).thenReturn(trieLogStorage); + when(trieLogStorage.startTransaction()).thenReturn(mock(KeyValueStorageTransaction.class)); } @Test public void testGetMutableReturnPersistedStateWhenNeeded() { final BlockHeader chainHead = blockBuilder.number(0).buildHeader(); - when(keyValueStorage.get(WORLD_ROOT_HASH_KEY)) + when(segmentedKeyValueStorage.get(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY)) .thenReturn(Optional.of(chainHead.getStateRoot().toArrayUnsafe())); - when(keyValueStorage.get(WORLD_BLOCK_HASH_KEY)) + when(segmentedKeyValueStorage.get(TRIE_BRANCH_STORAGE, WORLD_BLOCK_HASH_KEY)) .thenReturn(Optional.of(chainHead.getHash().toArrayUnsafe())); - when(keyValueStorage.get(WORLD_ROOT_HASH_KEY)) + when(segmentedKeyValueStorage.get(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY)) .thenReturn(Optional.of(chainHead.getStateRoot().toArrayUnsafe())); - when(keyValueStorage.get(WORLD_BLOCK_HASH_KEY)) + when(segmentedKeyValueStorage.get(TRIE_BRANCH_STORAGE, WORLD_BLOCK_HASH_KEY)) .thenReturn(Optional.of(chainHead.getHash().toArrayUnsafe())); bonsaiWorldStateArchive = new BonsaiWorldStateProvider( @@ -142,7 +153,6 @@ public void testGetMutableWhenLoadLessThanLimitLayersBack() { @Test public void testGetMutableWithStorageInconsistencyRollbackTheState() { - when(keyValueStorage.startTransaction()).thenReturn(mock(KeyValueStorageTransaction.class)); doAnswer(__ -> Optional.of(mock(TrieLogLayer.class))) .when(trieLogManager) .getTrieLogLayer(any(Hash.class)); @@ -167,12 +177,10 @@ public void testGetMutableWithStorageInconsistencyRollbackTheState() { verify(trieLogManager).getTrieLogLayer(Hash.ZERO); } - @SuppressWarnings({"unchecked", "rawtypes"}) + // @SuppressWarnings({"unchecked", "rawtypes"}) @Test public void testGetMutableWithStorageConsistencyNotRollbackTheState() { - when(keyValueStorage.startTransaction()).thenReturn(mock(KeyValueStorageTransaction.class)); - var worldStateStorage = new BonsaiWorldStateKeyValueStorage(storageProvider, new NoOpMetricsSystem()); bonsaiWorldStateArchive = @@ -198,7 +206,6 @@ public void testGetMutableWithStorageConsistencyNotRollbackTheState() { @SuppressWarnings({"unchecked"}) @Test public void testGetMutableWithStorageConsistencyToRollbackAndRollForwardTheState() { - when(keyValueStorage.startTransaction()).thenReturn(mock(KeyValueStorageTransaction.class)); final BlockHeader genesis = blockBuilder.number(0).buildHeader(); final BlockHeader blockHeaderChainA = blockBuilder.number(1).timestamp(1).parentHash(genesis.getHash()).buildHeader(); @@ -237,11 +244,10 @@ public void testGetMutableWithStorageConsistencyToRollbackAndRollForwardTheState @SuppressWarnings({"unchecked"}) @Test // TODO: refactor to test original intent - @Ignore("needs refactor, getMutable(hash, hash) cannot trigger saveTrieLog") + @Disabled("needs refactor, getMutable(hash, hash) cannot trigger saveTrieLog") public void testGetMutableWithRollbackNotOverrideTrieLogLayer() { - final KeyValueStorageTransaction keyValueStorageTransaction = - mock(KeyValueStorageTransaction.class); - when(keyValueStorage.startTransaction()).thenReturn(keyValueStorageTransaction); + when(segmentedKeyValueStorage.startTransaction()) + .thenReturn(segmentedKeyValueStorageTransaction); final BlockHeader genesis = blockBuilder.number(0).buildHeader(); final BlockHeader blockHeaderChainA = blockBuilder.number(1).timestamp(1).parentHash(genesis.getHash()).buildHeader(); @@ -267,7 +273,7 @@ public void testGetMutableWithRollbackNotOverrideTrieLogLayer() { final TrieLogLayer trieLogLayerBlockB = new TrieLogLayer(); trieLogLayerBlockB.setBlockHash(blockHeaderChainB.getHash()); TrieLogFactoryImpl.writeTo(trieLogLayerBlockB, rlpLogBlockB); - when(keyValueStorage.get(blockHeaderChainB.getHash().toArrayUnsafe())) + when(segmentedKeyValueStorage.get(BLOCKCHAIN, blockHeaderChainB.getHash().toArrayUnsafe())) .thenReturn(Optional.of(rlpLogBlockB.encoded().toArrayUnsafe())); when(blockchain.getBlockHeader(eq(blockHeaderChainB.getHash()))) @@ -278,9 +284,9 @@ public void testGetMutableWithRollbackNotOverrideTrieLogLayer() { .containsInstanceOf(BonsaiWorldState.class); // verify is not persisting if already present - verify(keyValueStorageTransaction, never()) - .put(eq(blockHeaderChainA.getHash().toArrayUnsafe()), any()); - verify(keyValueStorageTransaction, never()) - .put(eq(blockHeaderChainB.getHash().toArrayUnsafe()), any()); + verify(segmentedKeyValueStorageTransaction, never()) + .put(BLOCKCHAIN, eq(blockHeaderChainA.getHash().toArrayUnsafe()), any()); + verify(segmentedKeyValueStorageTransaction, never()) + .put(BLOCKCHAIN, eq(blockHeaderChainB.getHash().toArrayUnsafe()), any()); } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateKeyValueStorageTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateKeyValueStorageTest.java index a3314b2ee3b..6f67f657f02 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateKeyValueStorageTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateKeyValueStorageTest.java @@ -16,6 +16,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage.WORLD_ROOT_HASH_KEY; +import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.spy; @@ -44,67 +45,68 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mockito; -@RunWith(Parameterized.class) public class BonsaiWorldStateKeyValueStorageTest { - private final FlatDbMode flatDbMode; - - public BonsaiWorldStateKeyValueStorageTest(final FlatDbMode flatDbMode) { - this.flatDbMode = flatDbMode; - } - - @Parameterized.Parameters public static Collection data() { return Arrays.asList(new Object[][] {{FlatDbMode.FULL}, {FlatDbMode.PARTIAL}}); } final BonsaiWorldStateKeyValueStorage storage = emptyStorage(); - @Before - public void setUp() { + public void setUp(final FlatDbMode flatDbMode) { if (flatDbMode.equals(FlatDbMode.FULL)) { storage.upgradeToFullFlatDbMode(); } } - @Test - public void getCode_returnsEmpty() { + @ParameterizedTest + @MethodSource("data") + void getCode_returnsEmpty(final FlatDbMode flatDbMode) { + setUp(flatDbMode); assertThat(storage.getCode(Hash.EMPTY, Hash.EMPTY)).contains(Bytes.EMPTY); } - @Test - public void getAccountStateTrieNode_returnsEmptyNode() { + @ParameterizedTest + @MethodSource("data") + void getAccountStateTrieNode_returnsEmptyNode(final FlatDbMode flatDbMode) { + setUp(flatDbMode); assertThat(storage.getAccountStateTrieNode(Bytes.EMPTY, MerkleTrie.EMPTY_TRIE_NODE_HASH)) .contains(MerkleTrie.EMPTY_TRIE_NODE); } - @Test - public void getAccountStorageTrieNode_returnsEmptyNode() { + @ParameterizedTest + @MethodSource("data") + void getAccountStorageTrieNode_returnsEmptyNode(final FlatDbMode flatDbMode) { + setUp(flatDbMode); assertThat( storage.getAccountStorageTrieNode( Hash.EMPTY, Bytes.EMPTY, MerkleTrie.EMPTY_TRIE_NODE_HASH)) .contains(MerkleTrie.EMPTY_TRIE_NODE); } - @Test - public void getNodeData_returnsEmptyValue() { + @ParameterizedTest + @MethodSource("data") + void getNodeData_returnsEmptyValue(final FlatDbMode flatDbMode) { + setUp(flatDbMode); assertThat(storage.getNodeData(null, null)).isEmpty(); } - @Test - public void getNodeData_returnsEmptyNode() { + @ParameterizedTest + @MethodSource("data") + void getNodeData_returnsEmptyNode(final FlatDbMode flatDbMode) { + setUp(flatDbMode); assertThat(storage.getNodeData(Bytes.EMPTY, MerkleTrie.EMPTY_TRIE_NODE_HASH)).isEmpty(); } - @Test - public void getCode_saveAndGetSpecialValues() { + @ParameterizedTest + @MethodSource("data") + void getCode_saveAndGetSpecialValues(final FlatDbMode flatDbMode) { + setUp(flatDbMode); storage .updater() .putCode(Hash.EMPTY, MerkleTrie.EMPTY_TRIE_NODE) @@ -115,16 +117,20 @@ public void getCode_saveAndGetSpecialValues() { .contains(MerkleTrie.EMPTY_TRIE_NODE); } - @Test - public void getCode_saveAndGetRegularValue() { + @ParameterizedTest + @MethodSource("data") + void getCode_saveAndGetRegularValue(final FlatDbMode flatDbMode) { + setUp(flatDbMode); final Bytes bytes = Bytes.fromHexString("0x123456"); storage.updater().putCode(Hash.EMPTY, bytes).commit(); assertThat(storage.getCode(Hash.hash(bytes), Hash.EMPTY)).contains(bytes); } - @Test - public void getAccountStateTrieNode_saveAndGetSpecialValues() { + @ParameterizedTest + @MethodSource("data") + void getAccountStateTrieNode_saveAndGetSpecialValues(final FlatDbMode flatDbMode) { + setUp(flatDbMode); storage .updater() .putAccountStateTrieNode( @@ -137,8 +143,10 @@ public void getAccountStateTrieNode_saveAndGetSpecialValues() { assertThat(storage.getAccountStateTrieNode(Bytes.EMPTY, Hash.EMPTY)).contains(Bytes.EMPTY); } - @Test - public void getAccountStateTrieNode_saveAndGetRegularValue() { + @ParameterizedTest + @MethodSource("data") + void getAccountStateTrieNode_saveAndGetRegularValue(final FlatDbMode flatDbMode) { + setUp(flatDbMode); final Bytes location = Bytes.fromHexString("0x01"); final Bytes bytes = Bytes.fromHexString("0x123456"); @@ -147,8 +155,10 @@ public void getAccountStateTrieNode_saveAndGetRegularValue() { assertThat(storage.getAccountStateTrieNode(location, Hash.hash(bytes))).contains(bytes); } - @Test - public void getAccountStorageTrieNode_saveAndGetSpecialValues() { + @ParameterizedTest + @MethodSource("data") + void getAccountStorageTrieNode_saveAndGetSpecialValues(final FlatDbMode flatDbMode) { + setUp(flatDbMode); storage .updater() @@ -168,9 +178,11 @@ public void getAccountStorageTrieNode_saveAndGetSpecialValues() { .contains(Bytes.EMPTY); } - @Test - public void getAccountStorageTrieNode_saveAndGetRegularValue() { - final Hash accountHash = Hash.hash(Address.fromHexString("0x1")); + @ParameterizedTest + @MethodSource("data") + void getAccountStorageTrieNode_saveAndGetRegularValue(final FlatDbMode flatDbMode) { + setUp(flatDbMode); + final Hash accountHash = Address.fromHexString("0x1").addressHash(); final Bytes location = Bytes.fromHexString("0x01"); final Bytes bytes = Bytes.fromHexString("0x123456"); @@ -183,9 +195,11 @@ public void getAccountStorageTrieNode_saveAndGetRegularValue() { .contains(bytes); } - @Test - public void getAccount_notLoadFromTrieWhenEmptyAndFlatDbFullMode() { - Assume.assumeTrue(flatDbMode == FlatDbMode.FULL); + @ParameterizedTest + @MethodSource("data") + void getAccount_notLoadFromTrieWhenEmptyAndFlatDbFullMode(final FlatDbMode flatDbMode) { + setUp(flatDbMode); + Assumptions.assumeTrue(flatDbMode == FlatDbMode.FULL); final BonsaiWorldStateKeyValueStorage storage = spy(emptyStorage()); final MerkleTrie trie = TrieGenerator.generateTrie(storage, 1); @@ -197,8 +211,8 @@ public void getAccount_notLoadFromTrieWhenEmptyAndFlatDbFullMode() { // save world state root hash final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updater = storage.updater(); updater - .getTrieBranchStorageTransaction() - .put(WORLD_ROOT_HASH_KEY, trie.getRootHash().toArrayUnsafe()); + .getWorldStateTransaction() + .put(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY, trie.getRootHash().toArrayUnsafe()); updater.commit(); // remove flat database @@ -213,9 +227,11 @@ public void getAccount_notLoadFromTrieWhenEmptyAndFlatDbFullMode() { verify(storage, times(0)).getAccountStateTrieNode(any(), eq(trie.getRootHash())); } - @Test - public void getAccount_loadFromTrieWhenEmptyAndFlatDbPartialMode() { - Assume.assumeTrue(flatDbMode == FlatDbMode.PARTIAL); + @ParameterizedTest + @MethodSource("data") + void getAccount_loadFromTrieWhenEmptyAndFlatDbPartialMode(final FlatDbMode flatDbMode) { + setUp(flatDbMode); + Assumptions.assumeTrue(flatDbMode == FlatDbMode.PARTIAL); final BonsaiWorldStateKeyValueStorage storage = spy(emptyStorage()); final MerkleTrie trie = TrieGenerator.generateTrie(storage, 1); final TreeMap accounts = @@ -225,8 +241,8 @@ public void getAccount_loadFromTrieWhenEmptyAndFlatDbPartialMode() { // save world state root hash final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updater = storage.updater(); updater - .getTrieBranchStorageTransaction() - .put(WORLD_ROOT_HASH_KEY, trie.getRootHash().toArrayUnsafe()); + .getWorldStateTransaction() + .put(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY, trie.getRootHash().toArrayUnsafe()); updater.commit(); // remove flat database @@ -240,9 +256,11 @@ public void getAccount_loadFromTrieWhenEmptyAndFlatDbPartialMode() { verify(storage, times(1)).getAccountStateTrieNode(any(), eq(trie.getRootHash())); } - @Test - public void shouldUsePartialDBStrategyAfterDowngradingMode() { - Assume.assumeTrue(flatDbMode == FlatDbMode.PARTIAL); + @ParameterizedTest + @MethodSource("data") + void shouldUsePartialDBStrategyAfterDowngradingMode(final FlatDbMode flatDbMode) { + setUp(flatDbMode); + Assumptions.assumeTrue(flatDbMode == FlatDbMode.PARTIAL); final BonsaiWorldStateKeyValueStorage storage = spy(emptyStorage()); final MerkleTrie trie = TrieGenerator.generateTrie(storage, 1); @@ -253,8 +271,8 @@ public void shouldUsePartialDBStrategyAfterDowngradingMode() { // save world state root hash final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updater = storage.updater(); updater - .getTrieBranchStorageTransaction() - .put(WORLD_ROOT_HASH_KEY, trie.getRootHash().toArrayUnsafe()); + .getWorldStateTransaction() + .put(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY, trie.getRootHash().toArrayUnsafe()); updater.commit(); Mockito.reset(storage); @@ -270,9 +288,11 @@ public void shouldUsePartialDBStrategyAfterDowngradingMode() { .contains(accounts.firstEntry().getValue()); } - @Test - public void getStorage_loadFromTrieWhenEmptyWithPartialMode() { - Assume.assumeTrue(flatDbMode == FlatDbMode.PARTIAL); + @ParameterizedTest + @MethodSource("data") + void getStorage_loadFromTrieWhenEmptyWithPartialMode(final FlatDbMode flatDbMode) { + setUp(flatDbMode); + Assumptions.assumeTrue(flatDbMode == FlatDbMode.PARTIAL); final BonsaiWorldStateKeyValueStorage storage = spy(emptyStorage()); final MerkleTrie trie = TrieGenerator.generateTrie(storage, 1); final TreeMap accounts = @@ -298,8 +318,8 @@ public void getStorage_loadFromTrieWhenEmptyWithPartialMode() { // save world state root hash final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updater = storage.updater(); updater - .getTrieBranchStorageTransaction() - .put(WORLD_ROOT_HASH_KEY, trie.getRootHash().toArrayUnsafe()); + .getWorldStateTransaction() + .put(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY, trie.getRootHash().toArrayUnsafe()); updater.commit(); // remove flat database @@ -317,9 +337,11 @@ public void getStorage_loadFromTrieWhenEmptyWithPartialMode() { eq(Hash.wrap(accounts.firstKey())), any(), eq(storageTrie.getRootHash())); } - @Test - public void getStorage_loadFromTrieWhenEmptyWithFullMode() { - Assume.assumeTrue(flatDbMode == FlatDbMode.FULL); + @ParameterizedTest + @MethodSource("data") + void getStorage_loadFromTrieWhenEmptyWithFullMode(final FlatDbMode flatDbMode) { + setUp(flatDbMode); + Assumptions.assumeTrue(flatDbMode == FlatDbMode.FULL); final BonsaiWorldStateKeyValueStorage storage = spy(emptyStorage()); storage.upgradeToFullFlatDbMode(); final MerkleTrie trie = TrieGenerator.generateTrie(storage, 1); @@ -327,16 +349,18 @@ public void getStorage_loadFromTrieWhenEmptyWithFullMode() { // save world state root hash final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updater = storage.updater(); updater - .getTrieBranchStorageTransaction() - .put(WORLD_ROOT_HASH_KEY, trie.getRootHash().toArrayUnsafe()); + .getWorldStateTransaction() + .put(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY, trie.getRootHash().toArrayUnsafe()); updater.commit(); // remove flat database storage.clearFlatDatabase(); } - @Test - public void clear_reloadFlatDbStrategy() { + @ParameterizedTest + @MethodSource("data") + void clear_reloadFlatDbStrategy(final FlatDbMode flatDbMode) { + setUp(flatDbMode); final BonsaiWorldStateKeyValueStorage storage = spy(emptyStorage()); // save world state root hash @@ -353,11 +377,13 @@ public void clear_reloadFlatDbStrategy() { assertThat(storage.getAccount(Hash.ZERO)).isEmpty(); } - @Test - public void reconcilesNonConflictingUpdaters() { - final Hash accountHashA = Hash.hash(Address.fromHexString("0x1")); - final Hash accountHashB = Hash.hash(Address.fromHexString("0x2")); - final Hash accountHashD = Hash.hash(Address.fromHexString("0x4")); + @ParameterizedTest + @MethodSource("data") + void reconcilesNonConflictingUpdaters(final FlatDbMode flatDbMode) { + setUp(flatDbMode); + final Hash accountHashA = Address.fromHexString("0x1").addressHash(); + final Hash accountHashB = Address.fromHexString("0x2").addressHash(); + final Hash accountHashD = Address.fromHexString("0x4").addressHash(); final Bytes bytesA = Bytes.fromHexString("0x12"); final Bytes bytesB = Bytes.fromHexString("0x1234"); final Bytes bytesC = Bytes.fromHexString("0x123456"); @@ -377,24 +403,32 @@ public void reconcilesNonConflictingUpdaters() { assertThat(storage.getCode(Hash.hash(bytesC), accountHashD)).contains(bytesC); } - @Test - public void isWorldStateAvailable_defaultIsFalse() { + @ParameterizedTest + @MethodSource("data") + void isWorldStateAvailable_defaultIsFalse(final FlatDbMode flatDbMode) { + setUp(flatDbMode); assertThat(emptyStorage().isWorldStateAvailable(UInt256.valueOf(1), Hash.EMPTY)).isFalse(); } - @Test - public void isWorldStateAvailable_StateAvailableByRootHash() { + @ParameterizedTest + @MethodSource("data") + void isWorldStateAvailable_StateAvailableByRootHash(final FlatDbMode flatDbMode) { + setUp(flatDbMode); final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updater = storage.updater(); final Bytes rootHashKey = Bytes32.fromHexString("0x01"); - updater.getTrieBranchStorageTransaction().put(WORLD_ROOT_HASH_KEY, rootHashKey.toArrayUnsafe()); + updater + .getWorldStateTransaction() + .put(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY, rootHashKey.toArrayUnsafe()); updater.commit(); assertThat(storage.isWorldStateAvailable(Hash.wrap(Bytes32.wrap(rootHashKey)), Hash.EMPTY)) .isTrue(); } - @Test - public void isWorldStateAvailable_afterCallingSaveWorldstate() { + @ParameterizedTest + @MethodSource("data") + void isWorldStateAvailable_afterCallingSaveWorldstate(final FlatDbMode flatDbMode) { + setUp(flatDbMode); final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updater = storage.updater(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/CachedMerkleTrieLoaderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/CachedMerkleTrieLoaderTest.java index 00bd789288f..dfb247ee29b 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/CachedMerkleTrieLoaderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/CachedMerkleTrieLoaderTest.java @@ -39,11 +39,11 @@ import java.util.stream.Collectors; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; -public class CachedMerkleTrieLoaderTest { +class CachedMerkleTrieLoaderTest { private CachedMerkleTrieLoader merkleTrieLoader; private final StorageProvider storageProvider = new InMemoryKeyValueStorageProvider(); @@ -55,16 +55,17 @@ public class CachedMerkleTrieLoaderTest { private MerkleTrie trie; - @Before + @BeforeEach public void setup() { trie = TrieGenerator.generateTrie( - inMemoryWorldState, accounts.stream().map(Hash::hash).collect(Collectors.toList())); + inMemoryWorldState, + accounts.stream().map(Address::addressHash).collect(Collectors.toList())); merkleTrieLoader = new CachedMerkleTrieLoader(new NoOpMetricsSystem()); } @Test - public void shouldAddAccountNodesInCacheDuringPreload() { + void shouldAddAccountNodesInCacheDuringPreload() { merkleTrieLoader.cacheAccountNodes( inMemoryWorldState, Hash.wrap(trie.getRootHash()), accounts.get(0)); @@ -79,13 +80,13 @@ public void shouldAddAccountNodesInCacheDuringPreload() { Function.identity(), Function.identity()); - final Hash hashAccountZero = Hash.hash(accounts.get(0)); + final Hash hashAccountZero = accounts.get(0).addressHash(); assertThat(cachedTrie.get(hashAccountZero)).isEqualTo(trie.get(hashAccountZero)); } @Test - public void shouldAddStorageNodesInCacheDuringPreload() { - final Hash hashAccountZero = Hash.hash(accounts.get(0)); + void shouldAddStorageNodesInCacheDuringPreload() { + final Hash hashAccountZero = accounts.get(0).addressHash(); final StateTrieAccountValue stateTrieAccountValue = StateTrieAccountValue.readFrom(RLP.input(trie.get(hashAccountZero).orElseThrow())); final StoredMerklePatriciaTrie storageTrie = @@ -123,12 +124,11 @@ public void shouldAddStorageNodesInCacheDuringPreload() { cachedSlots.add(node.getEncodedBytes()); return TrieIterator.State.CONTINUE; }); - assertThat(originalSlots).isNotEmpty(); - assertThat(originalSlots).isEqualTo(cachedSlots); + assertThat(originalSlots).isNotEmpty().isEqualTo(cachedSlots); } @Test - public void shouldFallbackWhenAccountNodesIsNotInCache() { + void shouldFallbackWhenAccountNodesIsNotInCache() { final StoredMerklePatriciaTrie cachedTrie = new StoredMerklePatriciaTrie<>( (location, hash) -> @@ -136,13 +136,13 @@ public void shouldFallbackWhenAccountNodesIsNotInCache() { trie.getRootHash(), Function.identity(), Function.identity()); - final Hash hashAccountZero = Hash.hash(accounts.get(0)); + final Hash hashAccountZero = accounts.get(0).addressHash(); assertThat(cachedTrie.get(hashAccountZero)).isEqualTo(trie.get(hashAccountZero)); } @Test - public void shouldFallbackWhenStorageNodesIsNotInCache() { - final Hash hashAccountZero = Hash.hash(accounts.get(0)); + void shouldFallbackWhenStorageNodesIsNotInCache() { + final Hash hashAccountZero = accounts.get(0).addressHash(); final StateTrieAccountValue stateTrieAccountValue = StateTrieAccountValue.readFrom(RLP.input(trie.get(hashAccountZero).orElseThrow())); final StoredMerklePatriciaTrie storageTrie = @@ -173,7 +173,6 @@ public void shouldFallbackWhenStorageNodesIsNotInCache() { cachedSlots.add(node.getEncodedBytes()); return TrieIterator.State.CONTINUE; }); - assertThat(originalSlots).isNotEmpty(); - assertThat(originalSlots).isEqualTo(cachedSlots); + assertThat(originalSlots).isNotEmpty().isEqualTo(cachedSlots); } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/LogRollingTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/LogRollingTests.java index c6cc9b58c8f..ac586332081 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/LogRollingTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/LogRollingTests.java @@ -41,37 +41,36 @@ import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction; -import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import java.util.Optional; import java.util.stream.Collectors; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class LogRollingTests { private BonsaiWorldStateProvider archive; private InMemoryKeyValueStorageProvider provider; - private InMemoryKeyValueStorage accountStorage; - private InMemoryKeyValueStorage codeStorage; - private InMemoryKeyValueStorage storageStorage; - private InMemoryKeyValueStorage trieBranchStorage; - private InMemoryKeyValueStorage trieLogStorage; + private KeyValueStorage accountStorage; + private KeyValueStorage codeStorage; + private KeyValueStorage storageStorage; + private KeyValueStorage trieBranchStorage; + private KeyValueStorage trieLogStorage; private InMemoryKeyValueStorageProvider secondProvider; private BonsaiWorldStateProvider secondArchive; - private InMemoryKeyValueStorage secondAccountStorage; - private InMemoryKeyValueStorage secondCodeStorage; - private InMemoryKeyValueStorage secondStorageStorage; - private InMemoryKeyValueStorage secondTrieBranchStorage; - private InMemoryKeyValueStorage secondTrieLogStorage; + private KeyValueStorage secondAccountStorage; + private KeyValueStorage secondCodeStorage; + private KeyValueStorage secondStorageStorage; + private KeyValueStorage secondTrieBranchStorage; + private KeyValueStorage secondTrieLogStorage; private final Blockchain blockchain = mock(Blockchain.class); private static final Address addressOne = @@ -96,6 +95,7 @@ public class LogRollingTests { Hash.ZERO, 0, null, + null, // blobGasUSed null, null, new MainnetBlockHeaderFunctions()); @@ -118,11 +118,12 @@ public class LogRollingTests { Hash.ZERO, 0, null, + null, // blobGasUsed null, null, new MainnetBlockHeaderFunctions()); - @Before + @BeforeEach public void createStorage() { provider = new InMemoryKeyValueStorageProvider(); final CachedMerkleTrieLoader cachedMerkleTrieLoader = @@ -131,21 +132,14 @@ public void createStorage() { new BonsaiWorldStateProvider( provider, blockchain, cachedMerkleTrieLoader, new NoOpMetricsSystem(), null); accountStorage = - (InMemoryKeyValueStorage) - provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE); - codeStorage = - (InMemoryKeyValueStorage) - provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.CODE_STORAGE); + provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE); + codeStorage = provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.CODE_STORAGE); storageStorage = - (InMemoryKeyValueStorage) - provider.getStorageBySegmentIdentifier( - KeyValueSegmentIdentifier.ACCOUNT_STORAGE_STORAGE); + provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.ACCOUNT_STORAGE_STORAGE); trieBranchStorage = - (InMemoryKeyValueStorage) - provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE); + provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE); trieLogStorage = - (InMemoryKeyValueStorage) - provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.TRIE_LOG_STORAGE); + provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.TRIE_LOG_STORAGE); secondProvider = new InMemoryKeyValueStorageProvider(); final CachedMerkleTrieLoader secondOptimizedMerkleTrieLoader = @@ -158,24 +152,16 @@ public void createStorage() { new NoOpMetricsSystem(), null); secondAccountStorage = - (InMemoryKeyValueStorage) - secondProvider.getStorageBySegmentIdentifier( - KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE); + secondProvider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE); secondCodeStorage = - (InMemoryKeyValueStorage) - secondProvider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.CODE_STORAGE); + secondProvider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.CODE_STORAGE); secondStorageStorage = - (InMemoryKeyValueStorage) - secondProvider.getStorageBySegmentIdentifier( - KeyValueSegmentIdentifier.ACCOUNT_STORAGE_STORAGE); + secondProvider.getStorageBySegmentIdentifier( + KeyValueSegmentIdentifier.ACCOUNT_STORAGE_STORAGE); secondTrieBranchStorage = - (InMemoryKeyValueStorage) - secondProvider.getStorageBySegmentIdentifier( - KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE); + secondProvider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE); secondTrieLogStorage = - (InMemoryKeyValueStorage) - secondProvider.getStorageBySegmentIdentifier( - KeyValueSegmentIdentifier.TRIE_LOG_STORAGE); + secondProvider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.TRIE_LOG_STORAGE); } @Test @@ -327,7 +313,7 @@ public void rollBackOnce() { assertThat(secondWorldState.rootHash()).isEqualByComparingTo(worldState.rootHash()); } - private TrieLogLayer getTrieLogLayer(final InMemoryKeyValueStorage storage, final Bytes key) { + private TrieLogLayer getTrieLogLayer(final KeyValueStorage storage, final Bytes key) { return storage .get(key.toArrayUnsafe()) .map(bytes -> TrieLogFactoryImpl.readFrom(new BytesValueRLPInput(Bytes.wrap(bytes), false))) diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/RollingImport.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/RollingImport.java index 98e991574d8..46e5b6af9f8 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/RollingImport.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/RollingImport.java @@ -17,6 +17,10 @@ package org.hyperledger.besu.ethereum.bonsai; import static com.google.common.base.Preconditions.checkArgument; +import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE; +import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_STORAGE_STORAGE; +import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.CODE_STORAGE; +import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE; import org.hyperledger.besu.ethereum.bonsai.cache.CachedMerkleTrieLoader; import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage; @@ -29,10 +33,12 @@ import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; +import org.hyperledger.besu.services.kvstore.SegmentedInMemoryKeyValueStorage; import org.hyperledger.besu.util.io.RollingFileReader; import java.io.IOException; import java.nio.file.Path; +import java.util.List; import org.apache.tuweni.bytes.Bytes; @@ -53,19 +59,15 @@ public static void main(final String[] arg) throws IOException { final BonsaiWorldState bonsaiState = new BonsaiWorldState( archive, new BonsaiWorldStateKeyValueStorage(provider, new NoOpMetricsSystem())); - final InMemoryKeyValueStorage accountStorage = - (InMemoryKeyValueStorage) - provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE); - final InMemoryKeyValueStorage codeStorage = - (InMemoryKeyValueStorage) - provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.CODE_STORAGE); - final InMemoryKeyValueStorage storageStorage = - (InMemoryKeyValueStorage) - provider.getStorageBySegmentIdentifier( - KeyValueSegmentIdentifier.ACCOUNT_STORAGE_STORAGE); - final InMemoryKeyValueStorage trieBranchStorage = - (InMemoryKeyValueStorage) - provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE); + final SegmentedInMemoryKeyValueStorage worldStateStorage = + (SegmentedInMemoryKeyValueStorage) + provider.getStorageBySegmentIdentifiers( + List.of( + ACCOUNT_INFO_STATE, + CODE_STORAGE, + ACCOUNT_STORAGE_STORAGE, + TRIE_BRANCH_STORAGE)); + final InMemoryKeyValueStorage trieLogStorage = (InMemoryKeyValueStorage) provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.TRIE_LOG_STORAGE); @@ -125,10 +127,7 @@ public static void main(final String[] arg) throws IOException { } } System.out.printf("Back to zero!%n"); - accountStorage.dump(System.out); - codeStorage.dump(System.out); - storageStorage.dump(System.out); - trieBranchStorage.dump(System.out); + worldStateStorage.dump(System.out); trieLogStorage.dump(System.out); } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogFactoryTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogFactoryTests.java index 7f0c6f6f6cb..78161826acb 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogFactoryTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogFactoryTests.java @@ -31,11 +31,11 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class TrieLogFactoryTests { final BlockchainSetupUtil setup = BlockchainSetupUtil.forTesting(DataStorageFormat.BONSAI); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogLayerTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogLayerTests.java index 4dedd8e2b08..cd45bce5d92 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogLayerTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogLayerTests.java @@ -27,14 +27,14 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class TrieLogLayerTests { private TrieLogLayer trieLogLayer; private TrieLogLayer otherTrieLogLayer; - @Before + @BeforeEach public void setUp() { trieLogLayer = new TrieLogLayer(); otherTrieLogLayer = new TrieLogLayer(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogManagerTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogManagerTests.java index 9ab0cff2a22..35ce1b77c06 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogManagerTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogManagerTests.java @@ -31,14 +31,14 @@ import java.util.concurrent.atomic.AtomicBoolean; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Answers; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class TrieLogManagerTests { BlockHeader blockHeader = new BlockHeaderTestFixture().buildHeader(); @@ -55,7 +55,7 @@ public class TrieLogManagerTests { TrieLogManager trieLogManager; - @Before + @BeforeEach public void setup() { trieLogManager = new CachedWorldStorageManager( diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java index b3523e1d9b7..80c8eee5d37 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java @@ -44,7 +44,7 @@ import java.util.stream.Collectors; import com.google.common.collect.Lists; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class DefaultBlockchainTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/GenesisStateTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/GenesisStateTest.java index 16347e80bbc..da26192f932 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/GenesisStateTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/GenesisStateTest.java @@ -18,6 +18,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; import org.hyperledger.besu.ethereum.core.MutableWorldState; @@ -30,7 +31,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; import org.bouncycastle.util.encoders.Hex; -import org.junit.Test; +import org.junit.jupiter.api.Test; public final class GenesisStateTest { @@ -150,4 +151,100 @@ private void assertStorageValue(final Account contract, final String key, final assertThat(contract.getStorageValue(UInt256.fromHexString(key))) .isEqualTo(UInt256.fromHexString(value)); } + + @Test + public void genesisFromShanghai() throws Exception { + final GenesisState genesisState = + GenesisState.fromJson( + Resources.toString( + GenesisStateTest.class.getResource("genesis_shanghai.json"), Charsets.UTF_8), + ProtocolScheduleFixture.MAINNET); + final BlockHeader header = genesisState.getBlock().getHeader(); + assertThat(header.getHash()) + .isEqualTo( + Hash.fromHexString( + "0xfdc41f92053811b877be43e61cab6b0d9ee55501ae2443df0970c753747f12d8")); + assertThat(header.getGasLimit()).isEqualTo(0x2fefd8); + assertThat(header.getGasUsed()).isEqualTo(0); + assertThat(header.getNumber()).isEqualTo(0); + assertThat(header.getReceiptsRoot()) + .isEqualTo( + Hash.fromHexString( + "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")); + assertThat(header.getTransactionsRoot()).isEqualTo(Hash.EMPTY_TRIE_HASH); + assertThat(header.getOmmersHash()) + .isEqualTo( + Hash.fromHexString( + "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")); + assertThat(header.getExtraData()).isEqualTo(Bytes.EMPTY); + assertThat(header.getParentHash()).isEqualTo(Hash.ZERO); + + final MutableWorldState worldState = InMemoryKeyValueStorageProvider.createInMemoryWorldState(); + genesisState.writeStateTo(worldState); + Hash computedStateRoot = worldState.rootHash(); + assertThat(computedStateRoot).isEqualTo(header.getStateRoot()); + assertThat(header.getStateRoot()) + .isEqualTo( + Hash.fromHexString( + "0x7f5cfe1375a61009a22d24512d18035bc8f855129452fa9c6a6be2ef4e9da7db")); + final Account first = + worldState.get(Address.fromHexString("0000000000000000000000000000000000000100")); + final Account last = + worldState.get(Address.fromHexString("fb289e2b2b65fb63299a682d000744671c50417b")); + assertThat(first).isNotNull(); + assertThat(first.getBalance().toLong()).isEqualTo(0); + assertThat(first.getCode()) + .isEqualTo(Bytes.fromHexString("0x5f804955600180495560028049556003804955")); + assertThat(last).isNotNull(); + Wei lastBalance = last.getBalance(); + assertThat(lastBalance).isEqualTo(Wei.fromHexString("0x123450000000000000000")); + } + + @Test + public void genesisFromCancun() throws Exception { + final GenesisState genesisState = + GenesisState.fromJson( + Resources.toString( + GenesisStateTest.class.getResource("genesis_cancun.json"), Charsets.UTF_8), + ProtocolScheduleFixture.MAINNET); + final BlockHeader header = genesisState.getBlock().getHeader(); + assertThat(header.getHash()) + .isEqualTo( + Hash.fromHexString( + "0xf48e1c6ee02ec8da09e8e5a0084e48c081ae26522d29e398db68d945cd5a6890")); + assertThat(header.getGasLimit()).isEqualTo(0x2fefd8); + assertThat(header.getGasUsed()).isEqualTo(0); + assertThat(header.getNumber()).isEqualTo(0); + assertThat(header.getReceiptsRoot()) + .isEqualTo( + Hash.fromHexString( + "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")); + assertThat(header.getTransactionsRoot()).isEqualTo(Hash.EMPTY_TRIE_HASH); + assertThat(header.getOmmersHash()) + .isEqualTo( + Hash.fromHexString( + "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")); + assertThat(header.getExtraData()).isEqualTo(Bytes.EMPTY); + assertThat(header.getParentHash()).isEqualTo(Hash.ZERO); + + final MutableWorldState worldState = InMemoryKeyValueStorageProvider.createInMemoryWorldState(); + genesisState.writeStateTo(worldState); + Hash computedStateRoot = worldState.rootHash(); + assertThat(computedStateRoot).isEqualTo(header.getStateRoot()); + assertThat(header.getStateRoot()) + .isEqualTo( + Hash.fromHexString( + "0x7f5cfe1375a61009a22d24512d18035bc8f855129452fa9c6a6be2ef4e9da7db")); + final Account first = + worldState.get(Address.fromHexString("0000000000000000000000000000000000000100")); + final Account last = + worldState.get(Address.fromHexString("fb289e2b2b65fb63299a682d000744671c50417b")); + assertThat(first).isNotNull(); + assertThat(first.getBalance().toLong()).isEqualTo(0); + assertThat(first.getCode()) + .isEqualTo(Bytes.fromHexString("0x5f804955600180495560028049556003804955")); + assertThat(last).isNotNull(); + Wei lastBalance = last.getBalance(); + assertThat(lastBalance).isEqualTo(Wei.fromHexString("0x123450000000000000000")); + } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/AccountTransactionOrderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/AccountTransactionOrderTest.java index ef30a275c30..8f6c76ce03d 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/AccountTransactionOrderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/AccountTransactionOrderTest.java @@ -21,7 +21,7 @@ import java.util.stream.Stream; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class AccountTransactionOrderTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/BlockValueCalculatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/BlockValueCalculatorTest.java index 2d2b4c75f2b..e819064d9f2 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/BlockValueCalculatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/BlockValueCalculatorTest.java @@ -18,15 +18,15 @@ import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.Collections; import java.util.List; import java.util.Optional; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class BlockValueCalculatorTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/LogTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/LogTest.java index 854ab2aadd7..18fb8f3328d 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/LogTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/LogTest.java @@ -19,7 +19,7 @@ import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.evm.log.Log; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class LogTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionBuilderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionBuilderTest.java index a4ffbb27948..3633c393805 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionBuilderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionBuilderTest.java @@ -22,9 +22,9 @@ import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.evm.AccessListEntry; -import org.hyperledger.besu.plugin.data.TransactionType; import java.math.BigInteger; import java.util.List; @@ -34,7 +34,7 @@ import java.util.stream.Stream; import com.google.common.base.Suppliers; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class TransactionBuilderTest { private static final Supplier SIGNATURE_ALGORITHM = @@ -57,9 +57,7 @@ public void guessTypeCanGuessAllTypes() { assertThat(guessedTypes) .containsExactlyInAnyOrder( - new TransactionType[] { - TransactionType.FRONTIER, TransactionType.ACCESS_LIST, TransactionType.EIP1559 - }); + TransactionType.FRONTIER, TransactionType.ACCESS_LIST, TransactionType.EIP1559); } @Test @@ -68,7 +66,10 @@ public void zeroBlobTransactionIsInvalid() { new TransactionTestFixture() .type(TransactionType.BLOB) .chainId(Optional.of(BigInteger.ONE)) - .versionedHashes(List.of()) + .versionedHashes(Optional.of(List.of())) + .maxFeePerGas(Optional.of(Wei.of(5))) + .maxPriorityFeePerGas(Optional.of(Wei.of(5))) + .maxFeePerBlobGas(Optional.of(Wei.of(5))) .createTransaction(senderKeys); fail(); } catch (IllegalArgumentException iea) { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionIntegrationTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionIntegrationTest.java index da914033bd5..3c613d72397 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionIntegrationTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionIntegrationTest.java @@ -24,7 +24,7 @@ import java.math.BigInteger; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class TransactionIntegrationTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionReceiptTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionReceiptTest.java index 6e873f5bcaf..00a04354c69 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionReceiptTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionReceiptTest.java @@ -19,7 +19,7 @@ import org.hyperledger.besu.ethereum.rlp.RLP; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class TransactionReceiptTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/UtilTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/UtilTest.java index c0fcc780b5a..f5df655236f 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/UtilTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/UtilTest.java @@ -16,7 +16,7 @@ import static org.assertj.core.api.Java6Assertions.assertThat; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class UtilTest { @Test diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncodingTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncodingTest.java new file mode 100644 index 00000000000..920582390b8 --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncodingTest.java @@ -0,0 +1,113 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.core.encoding; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; +import org.hyperledger.besu.ethereum.rlp.RLP; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.stream.Stream; + +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class BlobTransactionEncodingTest { + private static Stream provideTypedTransactionBytes() throws IOException { + return Stream.of( + createArgument( + "0x03f89d850120b996ed3685012a1a646085012a1a64608303345094ffb38a7a99e3e2335be83fc74b7faa19d55312418308a80280c085012a1a6460e1a00153a6a1e053cf4c5a09e84088ed8ad7cb53d76c8168f1b82f7cfebfcd06da1a01a007785223eec68459d72265f10bdb30ec3415252a63100605a03142fa211ebbe9a07dbbf9e081fa7b9a01202e4d9ee0e0e513f80efbbab6c784635429905389ce86"), + createArgument( + "0x03f889850120b996ed81f0847735940084b2d05e158307a1208001855f495f4955c084b2d05e15e1a001d343d3cd62abd9c5754cbe5128c25ea90786a8ae75fb79c8cf95f4dcdd08ec80a014103732b5a9789bbf5ea859ed904155398abbef343f8fd63007efb70795d382a07272e847382789a092eadf08e2b9002e727376f8466fff0e4d4639fd60a528f2"), + createArgument( + "0x03f889850120b996ed81f1843b9aca00847735940e8307a1208001855f495f4955c0847735940ee1a001d552e24560ec2f168be1d4a6385df61c70afe4288f00a3ad172da1a6f2b4f280a0b6690786e5fe79df67dcb60e8a9e8555142c3c96ffd5097c838717f0a7f64129a0112f01ed0cd3b86495f01736fbbc1b793f71565223aa26f093471a4d8605d198"), + createArgument( + "0x03f897850120b996ed80840bebc200843b9aca078303345094c8d369b164361a8961286cfbab3bc10f962185a88080c08411e1a300e1a0011df88a2971c8a7ac494a7ba37ec1acaa1fc1edeeb38c839b5d1693d47b69b080a032f122f06e5802224db4c8a58fd22c75173a713f63f89936f811c144b9e40129a043a2a872cbfa5727007adf6a48febe5f190d2e4cd5ed6122823fb6ff47ecda32")); + } + + private static Stream provideTypedTransactionBytesForNetwork() throws IOException { + return Stream.of(createArgumentFromFile("blob1.txt")); + } + + @ParameterizedTest(name = "{index} {0}") + @MethodSource("provideTypedTransactionBytesForNetwork") + public void blobTransactionEncodingDecodingForNetWorkTest( + final TypedTransactionBytesArgument argument) { + Bytes bytes = argument.bytes; + // Decode the transaction from the wire using the TransactionDecoder. + final Transaction transaction = TransactionDecoder.decodeForWire(RLP.input(bytes)); + + final BytesValueRLPOutput bytesValueRLPOutput = new BytesValueRLPOutput(); + BlobTransactionEncoder.encodeForWireNetwork(transaction, bytesValueRLPOutput); + Bytes encodedRLP = bytesValueRLPOutput.encoded(); + assertThat(encodedRLP.size()).isEqualTo(bytes.size()); + assertThat(encodedRLP).isEqualTo(bytes); + } + + @ParameterizedTest(name = "{index} {0}") + @MethodSource("provideTypedTransactionBytes") + public void blobTransactionEncodingDecodingTest(final TypedTransactionBytesArgument argument) { + Bytes bytes = argument.bytes; + // Decode the transaction from the wire using the TransactionDecoder. + final Transaction transaction = TransactionDecoder.decodeForWire(RLP.input(bytes)); + final BytesValueRLPOutput output = new BytesValueRLPOutput(); + // Encode the transaction for wire using the TransactionEncoder. + TransactionEncoder.encodeForWire(transaction, output); + // Assert that the encoded transaction matches the original bytes. + assertThat(output.encoded().toHexString()).isEqualTo(bytes.toHexString()); + } + + private static Arguments createArgumentFromFile(final String path) throws IOException { + StringBuilder contentBuilder = new StringBuilder(); + + try (InputStream inputStream = BlobTransactionEncodingTest.class.getResourceAsStream(path)) { + try (InputStreamReader inputStreamReader = + new InputStreamReader(inputStream, StandardCharsets.UTF_8); + BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) { + + String line; + while ((line = bufferedReader.readLine()) != null) { + contentBuilder.append(line); + } + } + } + + return createArgument(contentBuilder.toString()); + } + + private static Arguments createArgument(final String hex) { + BytesValueRLPOutput out = new BytesValueRLPOutput(); + out.writeBytes(Bytes.fromHexString(hex)); + return Arguments.of(new TypedTransactionBytesArgument(out.encoded())); + } + + @SuppressWarnings("UnusedVariable") + private record TypedTransactionBytesArgument(Bytes bytes) { + @Override + public String toString() { + return bytes.size() > 32 + ? String.format("%s...%s", bytes.slice(0, 16), bytes.slice(bytes.size() - 16, 16)) + : bytes.toString(); + } + } +} diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPDecoderTest.java similarity index 99% rename from ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoderTest.java rename to ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPDecoderTest.java index 4b762a3b553..a3729713551 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPDecoderTest.java @@ -32,7 +32,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -class TransactionDecoderTest { +class TransactionRLPDecoderTest { private static final String FRONTIER_TX_RLP = "0xf901fc8032830138808080b901ae60056013565b6101918061001d6000396000f35b3360008190555056006001600060e060020a6000350480630a874df61461003a57806341c0e1b514610058578063a02b161e14610066578063dbbdf0831461007757005b610045600435610149565b80600160a060020a031660005260206000f35b610060610161565b60006000f35b6100716004356100d4565b60006000f35b61008560043560243561008b565b60006000f35b600054600160a060020a031632600160a060020a031614156100ac576100b1565b6100d0565b8060018360005260205260406000208190555081600060005260206000a15b5050565b600054600160a060020a031633600160a060020a031614158015610118575033600160a060020a0316600182600052602052604060002054600160a060020a031614155b61012157610126565b610146565b600060018260005260205260406000208190555080600060005260206000a15b50565b60006001826000526020526040600020549050919050565b600054600160a060020a031633600160a060020a0316146101815761018f565b600054600160a060020a0316ff5b561ca0c5689ed1ad124753d54576dfb4b571465a41900a1dff4058d8adf16f752013d0a01221cbd70ec28c94a3b55ec771bcbc70778d6ee0b51ca7ea9514594c861b1884"; diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPEncoderTest.java similarity index 99% rename from ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoderTest.java rename to ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPEncoderTest.java index 738004c8464..4e9f2187e16 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPEncoderTest.java @@ -26,7 +26,7 @@ import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.Test; -class TransactionEncoderTest { +class TransactionRLPEncoderTest { private static final String FRONTIER_TX_RLP = "0xf901fc8032830138808080b901ae60056013565b6101918061001d6000396000f35b3360008190555056006001600060e060020a6000350480630a874df61461003a57806341c0e1b514610058578063a02b161e14610066578063dbbdf0831461007757005b610045600435610149565b80600160a060020a031660005260206000f35b610060610161565b60006000f35b6100716004356100d4565b60006000f35b61008560043560243561008b565b60006000f35b600054600160a060020a031632600160a060020a031614156100ac576100b1565b6100d0565b8060018360005260205260406000208190555081600060005260206000a15b5050565b600054600160a060020a031633600160a060020a031614158015610118575033600160a060020a0316600182600052602052604060002054600160a060020a031614155b61012157610126565b610146565b600060018260005260205260406000208190555080600060005260206000a15b50565b60006001826000526020526040600020549050919050565b600054600160a060020a031633600160a060020a0316146101815761018f565b600054600160a060020a0316ff5b561ca0c5689ed1ad124753d54576dfb4b571465a41900a1dff4058d8adf16f752013d0a01221cbd70ec28c94a3b55ec771bcbc70778d6ee0b51ca7ea9514594c861b1884"; private static final String EIP1559_TX_RLP = diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/WithdrawalEncoderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/WithdrawalEncoderTest.java index 3c80cd78712..7dd79e229a0 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/WithdrawalEncoderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/WithdrawalEncoderTest.java @@ -29,8 +29,7 @@ class WithdrawalEncoderTest { "0xd8808094000000000000000000000000000000000000000080"; public static final String WITHDRAWAL_MAX_VALUE = "0xf088ffffffffffffffff88ffffffffffffffff94ffffffffffffffffffffffffffffffffffffffff88ffffffffffffffff"; - public static final Address MAX_ADDRESS = - Address.fromHexString(Bytes.repeat((byte) 0xff, 20).toHexString()); + public static final Address MAX_ADDRESS = Address.fromHexString("ff".repeat(20)); @Test void shouldEncodeWithdrawalForZeroCase() { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/BaseFeeMarketBaseFeeTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/BaseFeeMarketBaseFeeTest.java index 81580cf529c..d6d94c8453d 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/BaseFeeMarketBaseFeeTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/BaseFeeMarketBaseFeeTest.java @@ -23,25 +23,22 @@ import java.net.URL; import java.util.ArrayList; -import java.util.Collection; import java.util.List; +import java.util.stream.Stream; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Charsets; import com.google.common.io.Resources; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public class BaseFeeMarketBaseFeeTest { private final BaseFeeMarket baseFeeMarket = FeeMarket.london(0); - @Parameters - public static Collection data() { + public static Stream data() { try { final List data = new ArrayList<>(); final String testFilePath = "basefee-test.json"; @@ -60,31 +57,20 @@ public static Collection data() { testCase.expectedBaseFee }); } - return data; + return data.stream().map(Arguments::of); } catch (final Exception e) { throw new RuntimeException(e); } } - private final Wei parentBaseFee; - private final long parentGasUsed; - private final long parentTargetGasUsed; - private final Wei expectedBaseFee; - - public BaseFeeMarketBaseFeeTest( + @ParameterizedTest + @MethodSource("data") + @Disabled("Need to have spec frozen to define correct values") + public void assertThatBaseFeeIsCorrect( final Wei parentBaseFee, final long parentGasUsed, final long parentTargetGasUsed, final Wei expectedBaseFee) { - this.parentBaseFee = parentBaseFee; - this.parentGasUsed = parentGasUsed; - this.parentTargetGasUsed = parentTargetGasUsed; - this.expectedBaseFee = expectedBaseFee; - } - - @Test - @Ignore("Need to have spec frozen to define correct values") - public void assertThatBaseFeeIsCorrect() { assertThat(baseFeeMarket.computeBaseFee(0L, parentBaseFee, parentGasUsed, parentTargetGasUsed)) .isEqualTo(expectedBaseFee); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/BaseFeeMarketTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/BaseFeeMarketTest.java index e92617f4b74..af90a9b0fff 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/BaseFeeMarketTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/BaseFeeMarketTest.java @@ -20,7 +20,7 @@ import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class BaseFeeMarketTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/CoinbaseFeePriceCalculatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/CoinbaseFeePriceCalculatorTest.java index c653f763870..2706444f83f 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/CoinbaseFeePriceCalculatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/CoinbaseFeePriceCalculatorTest.java @@ -18,15 +18,13 @@ import org.hyperledger.besu.datatypes.Wei; -import java.util.Arrays; -import java.util.Collection; import java.util.Optional; +import java.util.stream.Stream; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public class CoinbaseFeePriceCalculatorTest { private static final CoinbaseFeePriceCalculator FRONTIER_CALCULATOR = @@ -34,40 +32,25 @@ public class CoinbaseFeePriceCalculatorTest { private static final CoinbaseFeePriceCalculator EIP_1559_CALCULATOR = CoinbaseFeePriceCalculator.eip1559(); - private final CoinbaseFeePriceCalculator coinbaseFeePriceCalculator; - private final long coinbaseFee; - private final Wei transactionGasPrice; - private final Optional baseFee; - private final Wei expectedPrice; + public static Stream data() { + return Stream.of( + // legacy transaction must return gas price * gas + Arguments.of(FRONTIER_CALCULATOR, 100L, Wei.of(10L), Optional.empty(), Wei.of(1000L)), + // EIP-1559 must return gas * (gas price - base fee) + Arguments.of(EIP_1559_CALCULATOR, 100L, Wei.of(10L), Optional.of(Wei.of(4L)), Wei.of(600L)) + // Negative transaction gas price case + // {EIP_1559_CALCULATOR, Gas.of(100), Wei.of(95L), Optional.of(100L), Wei.of(-500L)} + ); + } - public CoinbaseFeePriceCalculatorTest( + @ParameterizedTest + @MethodSource("data") + public void assertThatCalculatorWorks( final CoinbaseFeePriceCalculator coinbaseFeePriceCalculator, final long coinbaseFee, final Wei transactionGasPrice, final Optional baseFee, final Wei expectedPrice) { - this.coinbaseFeePriceCalculator = coinbaseFeePriceCalculator; - this.coinbaseFee = coinbaseFee; - this.transactionGasPrice = transactionGasPrice; - this.baseFee = baseFee; - this.expectedPrice = expectedPrice; - } - - @Parameterized.Parameters - public static Collection data() { - return Arrays.asList( - new Object[][] { - // legacy transaction must return gas price * gas - {FRONTIER_CALCULATOR, 100L, Wei.of(10L), Optional.empty(), Wei.of(1000L)}, - // EIP-1559 must return gas * (gas price - base fee) - {EIP_1559_CALCULATOR, 100L, Wei.of(10L), Optional.of(Wei.of(4L)), Wei.of(600L)}, - // Negative transaction gas price case - // {EIP_1559_CALCULATOR, Gas.of(100), Wei.of(95L), Optional.of(100L), Wei.of(-500L)} - }); - } - - @Test - public void assertThatCalculatorWorks() { assertThat(coinbaseFeePriceCalculator.price(coinbaseFee, transactionGasPrice, baseFee)) .isEqualByComparingTo(expectedPrice); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculatorTest.java index 3caa7234908..c23061ac8f1 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculatorTest.java @@ -15,25 +15,24 @@ package org.hyperledger.besu.ethereum.core.feemarket; import static org.assertj.core.api.Assertions.assertThat; -import static org.hyperledger.besu.plugin.data.TransactionType.ACCESS_LIST; -import static org.hyperledger.besu.plugin.data.TransactionType.EIP1559; -import static org.hyperledger.besu.plugin.data.TransactionType.FRONTIER; +import static org.hyperledger.besu.datatypes.TransactionType.ACCESS_LIST; +import static org.hyperledger.besu.datatypes.TransactionType.EIP1559; +import static org.hyperledger.besu.datatypes.TransactionType.FRONTIER; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.plugin.data.TransactionType; import java.math.BigInteger; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.Optional; +import java.util.stream.Stream; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public class TransactionPriceCalculatorTest { private static final TransactionPriceCalculator FRONTIER_CALCULATOR = @@ -41,15 +40,92 @@ public class TransactionPriceCalculatorTest { private static final TransactionPriceCalculator EIP_1559_CALCULATOR = TransactionPriceCalculator.eip1559(); - private final TransactionPriceCalculator transactionPriceCalculator; - private final TransactionType transactionType; - private final Wei gasPrice; - private final Wei maxPriorityFeePerGas; - private final Wei maxFeePerGas; - private final Optional baseFee; - private final Wei expectedPrice; + public static Stream data() { + return Arrays.stream( + new Object[][] { + // legacy transaction must return gas price + { + FRONTIER_CALCULATOR, + FRONTIER, + Wei.of(578L), + null, + null, + Optional.empty(), + Wei.of(578L) + }, + // legacy transaction zero price + {FRONTIER_CALCULATOR, FRONTIER, Wei.ZERO, null, null, Optional.empty(), Wei.ZERO}, + // ACCESSLIST transaction must return gas price + { + FRONTIER_CALCULATOR, + ACCESS_LIST, + Wei.of(578L), + null, + null, + Optional.empty(), + Wei.of(578L) + }, + // legacy transaction must return gas price + { + EIP_1559_CALCULATOR, + FRONTIER, + Wei.of(578L), + null, + null, + Optional.of(Wei.of(150L)), + Wei.of(578L) + }, + // london legacy transaction zero price + { + EIP_1559_CALCULATOR, FRONTIER, Wei.ZERO, null, null, Optional.of(Wei.ZERO), Wei.ZERO + }, + // ACCESSLIST transaction must return gas price + { + EIP_1559_CALCULATOR, + ACCESS_LIST, + Wei.of(578L), + null, + null, + Optional.of(Wei.of(150L)), + Wei.of(578L) + }, + // EIP-1559 must return maxPriorityFeePerGas + base fee + { + EIP_1559_CALCULATOR, + EIP1559, + null, + Wei.of(100L), + Wei.of(300L), + Optional.of(Wei.of(150L)), + Wei.of(250L) + }, + // EIP-1559 must return fee cap + { + EIP_1559_CALCULATOR, + EIP1559, + null, + Wei.of(100L), + Wei.of(300L), + Optional.of(Wei.of(250L)), + Wei.of(300L) + }, + // EIP-1559 transaction zero price + { + EIP_1559_CALCULATOR, + EIP1559, + null, + Wei.ZERO, + Wei.ZERO, + Optional.of(Wei.ZERO), + Wei.ZERO + } + }) + .map(Arguments::of); + } - public TransactionPriceCalculatorTest( + @ParameterizedTest + @MethodSource("data") + public void assertThatCalculatorWorks( final TransactionPriceCalculator transactionPriceCalculator, final TransactionType transactionType, final Wei gasPrice, @@ -57,82 +133,6 @@ public TransactionPriceCalculatorTest( final Wei maxFeePerGas, final Optional baseFee, final Wei expectedPrice) { - this.transactionPriceCalculator = transactionPriceCalculator; - this.transactionType = transactionType; - this.gasPrice = gasPrice; - this.maxPriorityFeePerGas = maxPriorityFeePerGas; - this.maxFeePerGas = maxFeePerGas; - this.baseFee = baseFee; - this.expectedPrice = expectedPrice; - } - - @Parameterized.Parameters - public static Collection data() { - return Arrays.asList( - new Object[][] { - // legacy transaction must return gas price - {FRONTIER_CALCULATOR, FRONTIER, Wei.of(578L), null, null, Optional.empty(), Wei.of(578L)}, - // legacy transaction zero price - {FRONTIER_CALCULATOR, FRONTIER, Wei.ZERO, null, null, Optional.empty(), Wei.ZERO}, - // ACCESSLIST transaction must return gas price - { - FRONTIER_CALCULATOR, - ACCESS_LIST, - Wei.of(578L), - null, - null, - Optional.empty(), - Wei.of(578L) - }, - // legacy transaction must return gas price - { - EIP_1559_CALCULATOR, - FRONTIER, - Wei.of(578L), - null, - null, - Optional.of(Wei.of(150L)), - Wei.of(578L) - }, - // london legacy transaction zero price - {EIP_1559_CALCULATOR, FRONTIER, Wei.ZERO, null, null, Optional.of(Wei.ZERO), Wei.ZERO}, - // ACCESSLIST transaction must return gas price - { - EIP_1559_CALCULATOR, - ACCESS_LIST, - Wei.of(578L), - null, - null, - Optional.of(Wei.of(150L)), - Wei.of(578L) - }, - // EIP-1559 must return maxPriorityFeePerGas + base fee - { - EIP_1559_CALCULATOR, - EIP1559, - null, - Wei.of(100L), - Wei.of(300L), - Optional.of(Wei.of(150L)), - Wei.of(250L) - }, - // EIP-1559 must return fee cap - { - EIP_1559_CALCULATOR, - EIP1559, - null, - Wei.of(100L), - Wei.of(300L), - Optional.of(Wei.of(250L)), - Wei.of(300L) - }, - // EIP-1559 transaction zero price - {EIP_1559_CALCULATOR, EIP1559, null, Wei.ZERO, Wei.ZERO, Optional.of(Wei.ZERO), Wei.ZERO} - }); - } - - @Test - public void assertThatCalculatorWorks() { assertThat( transactionPriceCalculator.price( Transaction.builder() diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedProtocolScheduleTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedProtocolScheduleTest.java index d78092792cd..9f192cf833b 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedProtocolScheduleTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedProtocolScheduleTest.java @@ -22,7 +22,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.evm.internal.EvmConfiguration; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class FixedProtocolScheduleTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdBackwardCompatibilityTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdBackwardCompatibilityTest.java index a7dbbbe6854..cd28e6e9aa6 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdBackwardCompatibilityTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdBackwardCompatibilityTest.java @@ -19,100 +19,75 @@ import static org.hyperledger.besu.ethereum.forkid.ForkIdTestUtil.mockBlockchain; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -@RunWith(Parameterized.class) public class ForkIdBackwardCompatibilityTest { private static final Logger LOG = LoggerFactory.getLogger(ForkIdBackwardCompatibilityTest.class); - private final String name; - private final String genesisHash; - private final long head; - private final List forks; - private final boolean legacyEth64; - private final ForkId wantForkId; - - public ForkIdBackwardCompatibilityTest( - final String name, - final String genesisHash, - final long head, - final List forks, - final boolean legacyEth64, - final ForkId wantForkId) { - this.name = name; - this.genesisHash = genesisHash; - this.head = head; - this.forks = forks; - this.legacyEth64 = legacyEth64; - this.wantForkId = wantForkId; - } - - @Parameterized.Parameters(name = "{index}: {0}") - public static Collection data() { - return Arrays.asList( - new Object[][] { - { + public static Stream data() { + return Stream.of( + Arguments.of( "with 0 forks and legacyEth64=false", GenesisHash.PRIVATE, 2L, Arrays.asList(0L, 0L, 4L, 5L, 6L), false, - new ForkId(Bytes.fromHexString("0x190a55ad"), 4L) - }, - { + new ForkId(Bytes.fromHexString("0x190a55ad"), 4L)), + Arguments.of( "with 0 forks and legacyEth64=true", GenesisHash.PRIVATE, 2L, Arrays.asList(0L, 0L, 4L, 5L, 6L), true, - null - }, - { + null), + Arguments.of( "with no 0 forks and legacyEth64=false", GenesisHash.PRIVATE, 2L, Arrays.asList(4L, 5L, 6L), false, - new ForkId(Bytes.fromHexString("0x190a55ad"), 4L) - }, - { + new ForkId(Bytes.fromHexString("0x190a55ad"), 4L)), + Arguments.of( "with no 0 forks and legacyEth64=true", GenesisHash.PRIVATE, 2L, Arrays.asList(4L, 5L, 6L), true, - null - }, - { + null), + Arguments.of( "post head with 0 forks and legacyEth64=false", GenesisHash.PRIVATE, 8L, Arrays.asList(0L, 0L, 4L, 5L, 6L), false, - new ForkId(Bytes.fromHexString("0x033462fc"), 0L) - }, - { + new ForkId(Bytes.fromHexString("0x033462fc"), 0L)), + Arguments.of( "post head with 0 forks and legacyEth64=true", GenesisHash.PRIVATE, 8L, Arrays.asList(0L, 0L, 4L, 5L, 6L), true, - null - }, - }); + null)); } - @Test - public void assertBackwardCompatibilityWorks() { + @ParameterizedTest(name = "{index}: {0}") + @MethodSource("data") + public void assertBackwardCompatibilityWorks( + final String name, + final String genesisHash, + final long head, + final List forks, + final boolean legacyEth64, + final ForkId wantForkId) { LOG.info("Running test case {}", name); final ForkIdManager forkIdManager = new ForkIdManager( diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdTest.java index 6a4a4503b7f..5e7b28514d1 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdTest.java @@ -26,458 +26,406 @@ import org.hyperledger.besu.ethereum.forkid.ForkIdTestUtil.Network; import org.hyperledger.besu.ethereum.forkid.ForkIdTestUtil.PeerCheckCase; -import java.util.Arrays; -import java.util.Collection; import java.util.List; import java.util.Optional; +import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -@RunWith(Parameterized.class) public class ForkIdTest { private static final Logger LOG = LoggerFactory.getLogger(ForkIdTest.class); - @Parameters(name = "{index}: {0}") - public static Collection data() { - return Arrays.asList( - new Object[][] { - // Mainnet test cases - { + public static Stream data() { + return Stream.of( + // Mainnet test cases + Arguments.of( "Mainnet // Unsynced", Network.MAINNET, 0L, 0L, ForkIdTestUtil.wantForkId("0xfc64ec04", 1150000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // First Homestead block", Network.MAINNET, 1150000L, 0L, ForkIdTestUtil.wantForkId("0x97c2c34c", 1920000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // Last Homestead block", Network.MAINNET, 1919999L, 0L, ForkIdTestUtil.wantForkId("0x97c2c34c", 1920000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // First DAO block", Network.MAINNET, 1920000L, 0L, ForkIdTestUtil.wantForkId("0x91d1f948", 2463000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // Last DAO block", Network.MAINNET, 2462999L, 0L, ForkIdTestUtil.wantForkId("0x91d1f948", 2463000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // First Tangerine block", Network.MAINNET, 2463000L, 0L, ForkIdTestUtil.wantForkId("0x7a64da13", 2675000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // Last Tangerine block", Network.MAINNET, 2674999L, 0L, ForkIdTestUtil.wantForkId("0x7a64da13", 2675000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // First Spurious block", Network.MAINNET, 2675000L, 0L, ForkIdTestUtil.wantForkId("0x3edd5b10", 4370000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // Last Spurious block", Network.MAINNET, 4369999L, 0L, ForkIdTestUtil.wantForkId("0x3edd5b10", 4370000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // First Byzantium block", Network.MAINNET, 4370000L, 0L, ForkIdTestUtil.wantForkId("0xa00bc324", 7280000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // Last Byzantium block", Network.MAINNET, 7279999L, 0L, ForkIdTestUtil.wantForkId("0xa00bc324", 7280000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // First and last Constantinople, first Petersburg block", Network.MAINNET, 7280000L, 0L, ForkIdTestUtil.wantForkId("0x668db0af", 9069000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // Last Petersburg block", Network.MAINNET, 9068999L, 0L, ForkIdTestUtil.wantForkId("0x668db0af", 9069000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // First Istanbul block", Network.MAINNET, 9069000L, 0L, ForkIdTestUtil.wantForkId("0x879d6e30", 9200000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // Last Istanbul block", Network.MAINNET, 9199999L, 0L, ForkIdTestUtil.wantForkId("0x879d6e30", 9200000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // First Muir Glacier block", Network.MAINNET, 9200000L, 0L, ForkIdTestUtil.wantForkId("0xe029e991", 12244000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // Last Muir Glacier block", Network.MAINNET, 12243999L, 0L, ForkIdTestUtil.wantForkId("0xe029e991", 12244000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // First Berlin block", Network.MAINNET, 12244000L, 0L, ForkIdTestUtil.wantForkId("0x0eb440f6", 12965000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // Last Berlin block", Network.MAINNET, 12964999L, 0L, ForkIdTestUtil.wantForkId("0x0eb440f6", 12965000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // First London block", Network.MAINNET, 12965000L, 0L, ForkIdTestUtil.wantForkId("0xb715077d", 13773000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // Last London block", Network.MAINNET, 13772999L, 0L, ForkIdTestUtil.wantForkId("0xb715077d", 13773000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // First Arrow Glacier block", Network.MAINNET, 13773000L, 0L, ForkIdTestUtil.wantForkId("0x20c327fc", 15050000L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // First Gray Glacier block", Network.MAINNET, 15050000L, 0L, ForkIdTestUtil.wantForkId("0xf0afd0e3", 0L), Optional.of(ForkIds.MAINNET), - empty() - }, - { + empty()), + Arguments.of( "Mainnet // Future Gray Glacier block", Network.MAINNET, 20000000L, 0L, ForkIdTestUtil.wantForkId("0xf0afd0e3", 0L), Optional.of(ForkIds.MAINNET), - empty() - }, - // Fork ID test cases with block number and timestamp based forks - // Withdrawals test cases - { + empty()), + // Fork ID test cases with block number and timestamp based forks + // Withdrawals test cases + Arguments.of( "Mainnet Withdrawals // First Merge Start block", Network.MAINNET_WITH_SHANGHAI, 18000000L, 0L, ForkIdTestUtil.wantForkId("0x4fb8a872", 1668000000L), Optional.of(ForkIdTestUtil.ForkIds.WITHDRAWALS), - empty() - }, - { + empty()), + Arguments.of( "Mainnet Withdrawals // Last Merge Start block", Network.MAINNET_WITH_SHANGHAI, 20000000L, 0L, ForkIdTestUtil.wantForkId("0x4fb8a872", 1668000000L), Optional.of(ForkIdTestUtil.ForkIds.WITHDRAWALS), - empty() - }, - { + empty()), + Arguments.of( "Mainnet Withdrawals // First Shanghai block", Network.MAINNET_WITH_SHANGHAI, 20000000L, 1668000000L, ForkIdTestUtil.wantForkId("0xc1fdf181", 0L), Optional.of(ForkIdTestUtil.ForkIds.WITHDRAWALS), - empty() - }, - { + empty()), + Arguments.of( "Mainnet Withdrawals // Last Shanghai block", Network.MAINNET_WITH_SHANGHAI, 20100000L, 2669000000L, ForkIdTestUtil.wantForkId("0xc1fdf181", 0L), Optional.of(ForkIdTestUtil.ForkIds.WITHDRAWALS), - empty() - }, - // Sepolia test cases - { + empty()), + // sepolia + Arguments.of( "Sepolia // mergenetsplit block", Network.SEPOLIA, 0L, 0L, ForkIdTestUtil.wantForkId("0xfe3366e7", 1735371L), Optional.of(ForkIds.SEPOLIA), - empty() - }, - { + empty()), + Arguments.of( "Sepolia // Shanghai", Network.SEPOLIA, 1735371L, 0L, ForkIdTestUtil.wantForkId("0xb96cbd13", 1677557088L), Optional.of(ForkIds.SEPOLIA), - empty() - }, - { + empty()), + Arguments.of( "Sepolia // Future", Network.SEPOLIA, 1735372L, 1677557088L, ForkIdTestUtil.wantForkId("0xf7f9bc08", 0L), Optional.of(ForkIds.SEPOLIA), - empty() - }, - // Goerli test cases - { + empty()), + // goerli + Arguments.of( "Goerli // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block", Network.GOERLI, 0L, 0L, ForkIdTestUtil.wantForkId("0xa3f5ab08", 1561651L), Optional.of(ForkIds.GOERLI), - empty() - }, - { + empty()), + Arguments.of( "Goerli // Last Petersburg block", Network.GOERLI, 1561650L, 0L, ForkIdTestUtil.wantForkId("0xa3f5ab08", 1561651L), Optional.of(ForkIds.GOERLI), - empty() - }, - { + empty()), + Arguments.of( "Goerli // First Istanbul block", Network.GOERLI, 1561651L, 0L, ForkIdTestUtil.wantForkId("0xc25efa5c", 0L), Optional.of(ForkIds.GOERLI), - empty() - }, - { + empty()), + Arguments.of( "Goerli // Future Istanbul block", Network.GOERLI, 2000000L, 0L, ForkIdTestUtil.wantForkId("0xc25efa5c", 0L), Optional.of(ForkIds.GOERLI), - empty() - }, - // Private network test cases - { + empty()), + // private + Arguments.of( "Private // Unsynced", Network.PRIVATE, 0L, 0L, ForkIdTestUtil.wantForkId("0x190a55ad", 0L), empty(), - empty() - }, - { + empty()), + Arguments.of( "Private // First block", Network.PRIVATE, 1L, 0L, ForkIdTestUtil.wantForkId("0x190a55ad", 0L), empty(), - empty() - }, - { + empty()), + Arguments.of( "Private // Future block", Network.PRIVATE, 1000000L, 0L, ForkIdTestUtil.wantForkId("0x190a55ad", 0L), empty(), - empty() - }, - // Peer check cases - { + empty()), + // peer check + Arguments.of( "check1PetersburgWithRemoteAnnouncingTheSame", Network.MAINNET, 7987396L, 0L, empty(), empty(), - wantPeerCheck("0x668db0af", 0L, true) - }, - { + wantPeerCheck("0x668db0af", 0L, true)), + Arguments.of( "check2PetersburgWithRemoteAnnouncingTheSameAndNextFork", Network.MAINNET, 7987396L, 0L, empty(), empty(), - wantPeerCheck("0x668db0af", Long.MAX_VALUE, true) - }, - { + wantPeerCheck("0x668db0af", Long.MAX_VALUE, true)), + Arguments.of( "check3ByzantiumAwareOfPetersburgRemoteUnawareOfPetersburg", Network.MAINNET, 7279999L, 0L, empty(), empty(), - wantPeerCheck("0xa00bc324", 0L, true) - }, - { + wantPeerCheck("0xa00bc324", 0L, true)), + Arguments.of( "check4ByzantiumAwareOfPetersburgRemoteAwareOfPetersburg", Network.MAINNET, 7987396L, 0L, empty(), empty(), - wantPeerCheck("0xa00bc324", 7280000L, true) - }, - { + wantPeerCheck("0xa00bc324", 7280000L, true)), + Arguments.of( "check5ByzantiumAwareOfPetersburgRemoteAnnouncingUnknownFork", Network.MAINNET, 7279999L, 0L, empty(), empty(), - wantPeerCheck("0xa00bc324", Long.MAX_VALUE, true) - }, - { + wantPeerCheck("0xa00bc324", Long.MAX_VALUE, true)), + Arguments.of( "check6PetersburgWithRemoteAnnouncingByzantiumAwareOfPetersburg", Network.MAINNET, 7987396L, 0L, empty(), empty(), - wantPeerCheck("0x668db0af", 7280000L, true) - }, - { + wantPeerCheck("0x668db0af", 7280000L, true)), + Arguments.of( "check7PetersburgWithRemoteAnnouncingSpuriousAwareOfByzantiumRemoteMayNeedUpdate", Network.MAINNET, 7987396L, 0L, empty(), empty(), - wantPeerCheck("0x3edd5b10", 4370000L, true) - }, - { + wantPeerCheck("0x3edd5b10", 4370000L, true)), + Arguments.of( "check8ByzantiumWithRemoteAnnouncingPetersburgLocalOutOfSync", Network.MAINNET, 727999L, 0L, empty(), empty(), - wantPeerCheck("0x668db0af", 0L, true) - }, - { + wantPeerCheck("0x668db0af", 0L, true)), + Arguments.of( "check9SpuriousWithRemoteAnnouncingByzantiumRemoteUnawareOfPetersburg", Network.MAINNET, 4369999L, 0L, empty(), empty(), - wantPeerCheck("0xa00bc324", 0L, true) - }, - { + wantPeerCheck("0xa00bc324", 0L, true)), + Arguments.of( "check10PetersburgWithRemoteAnnouncingByzantiumRemoteUnawareOfAdditionalForks", Network.network( GenesisHash.MAINNET, @@ -487,9 +435,8 @@ public static Collection data() { 0L, empty(), empty(), - wantPeerCheck("0xa00bc324", 0L, false) - }, - { + wantPeerCheck("0xa00bc324", 0L, false)), + Arguments.of( "check11PetersburgWithRemoteAnnouncingPetersburgAndFutureForkLocalNeedsUpdate", Network.network( GenesisHash.MAINNET, @@ -499,9 +446,8 @@ public static Collection data() { 0L, empty(), empty(), - wantPeerCheck("0x5cddc0e1", 0L, false) - }, - { + wantPeerCheck("0x5cddc0e1", 0L, false)), + Arguments.of( "check12ByzantiumWithRemoteAnnouncingPetersburgAndFutureForkLocalNeedsUpdate", ForkIdTestUtil.Network.network( GenesisHash.MAINNET, @@ -511,148 +457,132 @@ public static Collection data() { 0L, empty(), empty(), - wantPeerCheck("0x5cddc0e1", 0L, false) - }, - // Timestamp based peer check cases adapted from EIP-6122 test cases - { + wantPeerCheck("0x5cddc0e1", 0L, false)), + // Timestamp based peer check cases adapted from EIP-6122 test cases + Arguments.of( "withdrawalsCheck1ShanghaiWithRemoteAnnouncingTheSame", Network.MAINNET_WITH_SHANGHAI, 20000000L, 1668000001L, empty(), empty(), - wantPeerCheck("0xc1fdf181", 0L, true) - }, - { + wantPeerCheck("0xc1fdf181", 0L, true)), + Arguments.of( "withdrawalsCheck2ShanghaiWithRemoteAnnouncingSameAndNextFork", Network.MAINNET_WITH_SHANGHAI, 20000000L, 1668000001L, empty(), empty(), - wantPeerCheck("0xc1fdf181", Long.MAX_VALUE, true) - }, - { + wantPeerCheck("0xc1fdf181", Long.MAX_VALUE, true)), + Arguments.of( "withdrawalsCheck3ByzantiumWithRemoteAnnouncingByzantiumNotAwareOfPetersburg", Network.MAINNET_WITH_SHANGHAI, 7279999L, 1667999999L, empty(), empty(), - wantPeerCheck("0xa00bc324", 0L, true) - }, - { + wantPeerCheck("0xa00bc324", 0L, true)), + Arguments.of( "withdrawalsCheck4ByzantiumWithRemoteAnnouncingByzantiumAwareOfPetersburg", Network.MAINNET_WITH_SHANGHAI, 7279999L, 1667999999L, empty(), empty(), - wantPeerCheck("0xa00bc324", 7280000L, true) - }, - { + wantPeerCheck("0xa00bc324", 7280000L, true)), + Arguments.of( "withdrawalsCheck5ByzantiumWithRemoteAnnouncingByzantiumAwareOfUnknownFork", Network.MAINNET_WITH_SHANGHAI, 7279999L, 1667999999L, empty(), empty(), - wantPeerCheck("0xa00bc324", Long.MAX_VALUE, true) - }, - { + wantPeerCheck("0xa00bc324", Long.MAX_VALUE, true)), + Arguments.of( "withdrawalsCheck6ExactlyShanghaiWithRemoteAnnouncingByzantiumAwareOfPetersburgRemoteOutOfSync", Network.MAINNET_WITH_SHANGHAI, 20000000L, 1668000000L, empty(), empty(), - wantPeerCheck("0xa00bc324", 7280000L, true) - }, - { + wantPeerCheck("0xa00bc324", 7280000L, true)), + Arguments.of( "withdrawalsCheck7ShanghaiWithRemoteAnnouncingByzantiumAwareOfPetersburgRemoteOutOfSync", Network.MAINNET_WITH_SHANGHAI, 20000000L, 1668000001L, empty(), empty(), - wantPeerCheck("0xa00bc324", 7280000L, true) - }, - { + wantPeerCheck("0xa00bc324", 7280000L, true)), + Arguments.of( "withdrawalsCheck8ShanghaiWithRemoteAnnouncingSpuriousAwareOfByzantium", Network.MAINNET_WITH_SHANGHAI, 20000000L, 1668000001L, empty(), empty(), - wantPeerCheck("0x3edd5b10", 4370000, true) - }, - { + wantPeerCheck("0x3edd5b10", 4370000, true)), + Arguments.of( "withdrawalsCheck9ByzantiumWithRemoteAnnouncingPetersburgLocalOutOfSync", Network.MAINNET_WITH_SHANGHAI, 7279999L, 1667999999L, empty(), empty(), - wantPeerCheck("0x668db0af", 4370000, true) - }, - { + wantPeerCheck("0x668db0af", 4370000, true)), + Arguments.of( "withdrawalsCheck10SpuriousWithRemoteAnnouncingByzantiumNotAwareOfPetersburgLocalOutOfSync", Network.MAINNET_WITH_SHANGHAI, 4369999L, 1667999999L, empty(), empty(), - wantPeerCheck("0xa00bc324", 0L, true) - }, - { + wantPeerCheck("0xa00bc324", 0L, true)), + Arguments.of( "withdrawalsCheck11ShanghaiWithRemoteAnnouncingByzantiumUnawareOfAdditionalForksRemoteNeedsUpdate", Network.MAINNET_WITH_SHANGHAI, 20000000L, 1668000001L, empty(), empty(), - wantPeerCheck("0xa00bc324", 0L, false) - }, - { + wantPeerCheck("0xa00bc324", 0L, false)), + Arguments.of( "withdrawalsCheck12ShanghaiAndNotAwareOfAdditionalForksWithRemoteAnnouncingPetersburgAndUnknownFork", Network.MAINNET_WITH_SHANGHAI, 20000000L, 1668000001L, empty(), empty(), - wantPeerCheck("0x5cddc0e1", 0L, false) - }, - { + wantPeerCheck("0x5cddc0e1", 0L, false)), + Arguments.of( "withdrawalsCheck14ShanghaiWithRemoteAnnouncingUnknownFork", Network.MAINNET_WITH_SHANGHAI, 88888888L, 1668000001L, empty(), empty(), - wantPeerCheck("0xf0afd0e3", 88888888L, false) - }, - { + wantPeerCheck("0xf0afd0e3", 88888888L, false)), + Arguments.of( "withdrawalsCheck15ShanghaiWithRemoteInByzantiumAnnouncingUnknownFork", Network.MAINNET_WITH_SHANGHAI, 88888888L, 1668000001L, empty(), empty(), - wantPeerCheck("0xa00bc324", 7279999L, false) - } - }); + wantPeerCheck("0xa00bc324", 7279999L, false))); } - private final String name; - private final Network network; - private final long head; - private final long time; - private final Optional wantForkId; - private final Optional> wantForkIds; - private final Optional wantPeerCheckCase; - - @Test - public void test() { + @ParameterizedTest(name = "{index}: {0}") + @MethodSource("data") + public void test( + final String name, + final ForkIdTestUtil.Network network, + final long head, + final long time, + final Optional wantForkId, + final Optional> wantForkIds, + final Optional wantPeerCheckCase) { LOG.info("Running test case {}", name); final ForkIdManager forkIdManager = new ForkIdManager( @@ -673,21 +603,4 @@ public void test() { peerCheckCase.forkIdNext))) .isEqualTo(peerCheckCase.want)); } - - public ForkIdTest( - final String name, - final ForkIdTestUtil.Network network, - final long head, - final long time, - final Optional wantForkId, - final Optional> wantForkIds, - final Optional wantPeerCheckCase) { - this.name = name; - this.network = network; - this.head = head; - this.time = time; - this.wantForkId = wantForkId; - this.wantForkIds = wantForkIds; - this.wantPeerCheckCase = wantPeerCheckCase; - } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/BaseFeeBlockBodyValidatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/BaseFeeBlockBodyValidatorTest.java index a8ad3424f0f..9e5e48d3b47 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/BaseFeeBlockBodyValidatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/BaseFeeBlockBodyValidatorTest.java @@ -20,25 +20,25 @@ import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.Collections; import java.util.List; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class BaseFeeBlockBodyValidatorTest { private static final KeyPair keyPair = SignatureAlgorithmFactory.getInstance().generateKeyPair(); @@ -50,7 +50,7 @@ public class BaseFeeBlockBodyValidatorTest { BaseFeeBlockBodyValidator blockBodyValidator; - @Before + @BeforeEach public void setup() { when(protocolSpec.getFeeMarket()).thenReturn(FeeMarket.london(0L)); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/BlockHeaderValidatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/BlockHeaderValidatorTest.java index a04e5707142..bfa28c836d2 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/BlockHeaderValidatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/BlockHeaderValidatorTest.java @@ -31,8 +31,8 @@ import java.util.Optional; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.InOrder; public class BlockHeaderValidatorTest { @@ -43,7 +43,7 @@ public class BlockHeaderValidatorTest { private final MutableBlockchain blockchain = mock(MutableBlockchain.class); private final BlockDataGenerator generator = new BlockDataGenerator(); - @Before + @BeforeEach public void setUp() { when(protocolContext.getBlockchain()).thenReturn(blockchain); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/BodyValidationTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/BodyValidationTest.java index 9e2876e7fb7..cd5c5d89631 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/BodyValidationTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/BodyValidationTest.java @@ -23,7 +23,8 @@ import org.apache.tuweni.bytes.Bytes32; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; /** Tests for {@link BodyValidation}. */ public final class BodyValidationTest { @@ -34,7 +35,7 @@ public void calculateTransactionsRoot() throws IOException { final BlockHeader header = ValidationTestUtils.readHeader(block); final BlockBody body = ValidationTestUtils.readBody(block); final Bytes32 transactionRoot = BodyValidation.transactionsRoot(body.getTransactions()); - Assertions.assertThat(header.getTransactionsRoot()).isEqualTo(transactionRoot); + Assertions.assertThat(transactionRoot).isEqualTo(header.getTransactionsRoot()); } } @@ -58,6 +59,7 @@ public void calculateWithdrawalsRoot() throws IOException { } } + @Disabled // TODO: RLP encoding has changed, so testdata needs to be updated @Test public void calculateDepositsRoot() throws IOException { for (final int block : Arrays.asList(123, 124)) { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolScheduleTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolScheduleTest.java index 4d86f9070cf..784ba569b3d 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolScheduleTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolScheduleTest.java @@ -30,8 +30,8 @@ import java.util.function.Function; import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class DefaultProtocolScheduleTest { @@ -46,7 +46,7 @@ public class DefaultProtocolScheduleTest { private final long FIRST_TIMESTAMP_FORK = 9991L; - @Before + @BeforeEach public void setup() { config = new StubGenesisConfigOptions(); config.chainId(DEFAULT_CHAIN_ID); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/EtcHashTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/EtcHashTest.java index 0dbc9a312fe..a9c4f22b377 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/EtcHashTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/EtcHashTest.java @@ -15,7 +15,7 @@ package org.hyperledger.besu.ethereum.mainnet; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class EtcHashTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/EthHashTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/EthHashTest.java index 1eda369deb9..458bc741320 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/EthHashTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/EthHashTest.java @@ -26,7 +26,7 @@ import com.google.common.io.Resources; import org.apache.tuweni.bytes.Bytes; import org.bouncycastle.util.encoders.Hex; -import org.junit.Test; +import org.junit.jupiter.api.Test; public final class EthHashTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/IntrinsicGasTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/IntrinsicGasTest.java index d0e4217d8e7..a6ae23724e3 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/IntrinsicGasTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/IntrinsicGasTest.java @@ -20,96 +20,71 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator; import org.hyperledger.besu.evm.gascalculator.IstanbulGasCalculator; -import java.util.Arrays; -import java.util.Collection; +import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Assertions; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public class IntrinsicGasTest { - private final GasCalculator gasCalculator; - private final long expectedGas; - private final String txRlp; - - public IntrinsicGasTest( - final GasCalculator gasCalculator, final long expectedGas, final String txRlp) { - this.gasCalculator = gasCalculator; - this.expectedGas = expectedGas; - this.txRlp = txRlp; - } - - @Parameters - public static Collection data() { + public static Stream data() { final GasCalculator frontier = new FrontierGasCalculator(); final GasCalculator istanbul = new IstanbulGasCalculator(); - return Arrays.asList( - new Object[][] { - // EnoughGAS - { + return Stream.of( + // EnoughGAS + Arguments.of( frontier, 21952L, - "0xf86d80018259d894095e7baea6a6c7c4c2dfeb977efac326af552d870a8e0358ac39584bc98a7c979f984b031ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" - }, - { + "0xf86d80018259d894095e7baea6a6c7c4c2dfeb977efac326af552d870a8e0358ac39584bc98a7c979f984b031ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"), + Arguments.of( istanbul, 21224L, - "0xf86d80018259d894095e7baea6a6c7c4c2dfeb977efac326af552d870a8e0358ac39584bc98a7c979f984b031ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" - }, - // FirstZeroBytes - { + "0xf86d80018259d894095e7baea6a6c7c4c2dfeb977efac326af552d870a8e0358ac39584bc98a7c979f984b031ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"), + // FirstZeroBytes + Arguments.of( frontier, 21180L, - "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000010000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" - }, - { + "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000010000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"), + Arguments.of( istanbul, 21128L, - "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000010000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" - }, - // LastZeroBytes - { + "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000010000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"), + // LastZeroBytes + Arguments.of( frontier, 21180L, - "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d01000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" - }, - { + "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d01000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"), + Arguments.of( istanbul, 21128L, - "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d01000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" - }, - // NotEnoughGAS - { + "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d01000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"), + // NotEnoughGAS + Arguments.of( frontier, 21952L, - "0xf86d800182521c94095e7baea6a6c7c4c2dfeb977efac326af552d870a8e0358ac39584bc98a7c979f984b031ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" - }, - { + "0xf86d800182521c94095e7baea6a6c7c4c2dfeb977efac326af552d870a8e0358ac39584bc98a7c979f984b031ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"), + Arguments.of( istanbul, 21224L, - "0xf86d800182521c94095e7baea6a6c7c4c2dfeb977efac326af552d870a8e0358ac39584bc98a7c979f984b031ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" - }, - // ZeroBytes - { + "0xf86d800182521c94095e7baea6a6c7c4c2dfeb977efac326af552d870a8e0358ac39584bc98a7c979f984b031ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"), + // ZeroBytes + Arguments.of( frontier, 21116L, - "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" - }, - { + "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"), + Arguments.of( istanbul, 21116L, - "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" - }, - }); + "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804")); } - @Test - public void validateGasCost() { + @ParameterizedTest + @MethodSource("data") + public void validateGasCost( + final GasCalculator gasCalculator, final long expectedGas, final String txRlp) { Transaction t = Transaction.readFrom(RLP.input(Bytes.fromHexString(txRlp))); Assertions.assertThat( gasCalculator.transactionIntrinsicGasCost(t.getPayload(), t.isContractCreation())) diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidatorTest.java index cfca6830dbb..cbb5bed07eb 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidatorTest.java @@ -19,12 +19,12 @@ import org.hyperledger.besu.ethereum.ProtocolContext; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; /** Tests for {@link MainnetBlockHeaderValidator}. */ -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public final class MainnetBlockHeaderValidatorTest { @SuppressWarnings("unchecked") diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockImporterTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockImporterTest.java index 28221791224..2cde37ad1f3 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockImporterTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockImporterTest.java @@ -27,13 +27,13 @@ import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Block; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class MainnetBlockImporterTest { @Mock private BlockValidator blockValidator; @Mock private ProtocolContext context; @@ -42,7 +42,7 @@ public class MainnetBlockImporterTest { @Mock private Hash hash; private MainnetBlockImporter blockImporter; - @Before + @BeforeEach public void setup() { blockImporter = new MainnetBlockImporter(blockValidator); when(context.getBlockchain()).thenReturn(blockchain); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetPrecompiledContractRegistriesTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetPrecompiledContractRegistriesTest.java index 1b77fb3719d..0bee331d17b 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetPrecompiledContractRegistriesTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetPrecompiledContractRegistriesTest.java @@ -30,11 +30,11 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator; import org.hyperledger.besu.evm.precompile.PrecompileContractRegistry; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class MainnetPrecompiledContractRegistriesTest { private final PrivacyParameters privacyParameters = mock(PrivacyParameters.class); private final GasCalculator gasCalculator = mock(GasCalculator.class); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolScheduleTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolScheduleTest.java index 7c4b1bde529..93f4ab023ec 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolScheduleTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolScheduleTest.java @@ -24,7 +24,7 @@ import com.google.common.io.Resources; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class MainnetProtocolScheduleTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java index ce555391570..2fe864a5c90 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java @@ -41,19 +41,23 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class MainnetTransactionProcessorTest { private static final int MAX_STACK_SIZE = 1024; private final GasCalculator gasCalculator = new LondonGasCalculator(); - @Mock private MainnetTransactionValidator transactionValidator; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private TransactionValidatorFactory transactionValidatorFactory; + @Mock private AbstractMessageProcessor contractCreationProcessor; @Mock private AbstractMessageProcessor messageCallProcessor; @@ -69,7 +73,7 @@ public class MainnetTransactionProcessorTest { MainnetTransactionProcessor createTransactionProcessor(final boolean warmCoinbase) { return new MainnetTransactionProcessor( gasCalculator, - transactionValidator, + transactionValidatorFactory, contractCreationProcessor, messageCallProcessor, false, @@ -92,8 +96,9 @@ public void shouldWarmCoinbaseIfRequested() { when(transaction.getPayload()).thenReturn(Bytes.EMPTY); when(transaction.getSender()).thenReturn(senderAddress); when(transaction.getValue()).thenReturn(Wei.ZERO); - when(transactionValidator.validate(any(), any(), any())).thenReturn(ValidationResult.valid()); - when(transactionValidator.validateForSender(any(), any(), any())) + when(transactionValidatorFactory.get().validate(any(), any(), any())) + .thenReturn(ValidationResult.valid()); + when(transactionValidatorFactory.get().validateForSender(any(), any(), any())) .thenReturn(ValidationResult.valid()); when(worldState.getOrCreate(any())).thenReturn(senderAccount); when(worldState.getOrCreateSenderAccount(any())).thenReturn(senderAccount); @@ -168,9 +173,12 @@ public void shouldCallTransactionValidatorWithExpectedTransactionValidationParam private ArgumentCaptor transactionValidationParamCaptor() { final ArgumentCaptor txValidationParamCaptor = ArgumentCaptor.forClass(TransactionValidationParams.class); - when(transactionValidator.validate(any(), any(), any())).thenReturn(ValidationResult.valid()); + when(transactionValidatorFactory.get().validate(any(), any(), any())) + .thenReturn(ValidationResult.valid()); // returning invalid transaction to halt method execution - when(transactionValidator.validateForSender(any(), any(), txValidationParamCaptor.capture())) + when(transactionValidatorFactory + .get() + .validateForSender(any(), any(), txValidationParamCaptor.capture())) .thenReturn(ValidationResult.invalid(TransactionInvalidReason.NONCE_TOO_HIGH)); return txValidationParamCaptor; } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java index 868c39d5370..536a93957ae 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright ConsenSys AG. + * Copyright Hyperledger Besu contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -15,14 +15,16 @@ package org.hyperledger.besu.ethereum.mainnet; import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams.processingBlockParams; +import static org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams.transactionPoolParams; import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.GAS_PRICE_BELOW_CURRENT_BASE_FEE; import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.INVALID_TRANSACTION_FORMAT; import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.MAX_PRIORITY_FEE_PER_GAS_EXCEEDS_MAX_FEE_PER_GAS; import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; import org.hyperledger.besu.crypto.KeyPair; @@ -30,32 +32,40 @@ import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Blob; +import org.hyperledger.besu.datatypes.BlobsWithCommitments; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.KZGCommitment; +import org.hyperledger.besu.datatypes.KZGProof; +import org.hyperledger.besu.datatypes.TransactionType; +import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.GasLimitCalculator; +import org.hyperledger.besu.ethereum.core.BlobTestFixture; import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.ethereum.core.TransactionFilter; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.gascalculator.GasCalculator; -import org.hyperledger.besu.plugin.data.TransactionType; import java.math.BigInteger; +import java.util.List; import java.util.Optional; import java.util.Set; import java.util.function.Supplier; import com.google.common.base.Suppliers; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class MainnetTransactionValidatorTest { private static final Supplier SIGNATURE_ALGORITHM = @@ -63,7 +73,7 @@ public class MainnetTransactionValidatorTest { private static final KeyPair senderKeys = SIGNATURE_ALGORITHM.get().generateKeyPair(); private static final TransactionValidationParams transactionValidationParams = - TransactionValidationParams.processingBlockParams; + processingBlockParams; @Mock private GasCalculator gasCalculator; @@ -72,10 +82,43 @@ public class MainnetTransactionValidatorTest { .chainId(Optional.of(BigInteger.ONE)) .createTransaction(senderKeys); + protected TransactionValidator createTransactionValidator( + final GasCalculator gasCalculator, + final GasLimitCalculator gasLimitCalculator, + final FeeMarket feeMarket, + final boolean checkSignatureMalleability, + final Optional chainId, + final Set acceptedTransactionTypes, + final int maxInitcodeSize) { + return new MainnetTransactionValidator( + gasCalculator, + gasLimitCalculator, + feeMarket, + checkSignatureMalleability, + chainId, + acceptedTransactionTypes, + maxInitcodeSize); + } + + protected TransactionValidator createTransactionValidator( + final GasCalculator gasCalculator, + final GasLimitCalculator gasLimitCalculator, + final boolean checkSignatureMalleability, + final Optional chainId) { + return createTransactionValidator( + gasCalculator, + gasLimitCalculator, + FeeMarket.legacy(), + checkSignatureMalleability, + chainId, + Set.of(TransactionType.FRONTIER), + Integer.MAX_VALUE); + } + @Test public void shouldRejectTransactionIfIntrinsicGasExceedsGasLimit() { - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( + final TransactionValidator validator = + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); final Transaction transaction = new TransactionTestFixture() @@ -91,8 +134,8 @@ public void shouldRejectTransactionIfIntrinsicGasExceedsGasLimit() { @Test public void shouldRejectTransactionWhenTransactionHasChainIdAndValidatorDoesNot() { - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( + final TransactionValidator validator = + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); assertThat(validator.validate(basicTransaction, Optional.empty(), transactionValidationParams)) .isEqualTo( @@ -102,8 +145,8 @@ public void shouldRejectTransactionWhenTransactionHasChainIdAndValidatorDoesNot( @Test public void shouldRejectTransactionWhenTransactionHasIncorrectChainId() { - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( + final TransactionValidator validator = + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, @@ -114,66 +157,66 @@ public void shouldRejectTransactionWhenTransactionHasIncorrectChainId() { @Test public void shouldRejectTransactionWhenSenderAccountDoesNotExist() { - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( + final TransactionValidator validator = + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.of(BigInteger.ONE)); - assertThat(validator.validateForSender(basicTransaction, null, false)) + assertThat(validator.validateForSender(basicTransaction, null, processingBlockParams)) .isEqualTo(ValidationResult.invalid(TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE)); } @Test public void shouldRejectTransactionWhenTransactionNonceBelowAccountNonce() { - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( + final TransactionValidator validator = + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.of(BigInteger.ONE)); final Account account = accountWithNonce(basicTransaction.getNonce() + 1); - assertThat(validator.validateForSender(basicTransaction, account, false)) + assertThat(validator.validateForSender(basicTransaction, account, processingBlockParams)) .isEqualTo(ValidationResult.invalid(TransactionInvalidReason.NONCE_TOO_LOW)); } @Test public void shouldRejectTransactionWhenTransactionNonceAboveAccountNonceAndFutureNonceIsNotAllowed() { - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( + final TransactionValidator validator = + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.of(BigInteger.ONE)); final Account account = accountWithNonce(basicTransaction.getNonce() - 1); - assertThat(validator.validateForSender(basicTransaction, account, false)) + assertThat(validator.validateForSender(basicTransaction, account, processingBlockParams)) .isEqualTo(ValidationResult.invalid(TransactionInvalidReason.NONCE_TOO_HIGH)); } @Test public void shouldAcceptTransactionWhenTransactionNonceAboveAccountNonceAndFutureNonceIsAllowed() { - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( + final TransactionValidator validator = + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.of(BigInteger.ONE)); final Account account = accountWithNonce(basicTransaction.getNonce() - 1); - assertThat(validator.validateForSender(basicTransaction, account, true)) + assertThat(validator.validateForSender(basicTransaction, account, transactionPoolParams)) .isEqualTo(ValidationResult.valid()); } @Test public void shouldRejectTransactionWhenNonceExceedsMaximumAllowedNonce() { - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( + final TransactionValidator validator = + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.of(BigInteger.ONE)); final Transaction transaction = new TransactionTestFixture().nonce(11).createTransaction(senderKeys); final Account account = accountWithNonce(5); - assertThat(validator.validateForSender(transaction, account, false)) + assertThat(validator.validateForSender(transaction, account, processingBlockParams)) .isEqualTo(ValidationResult.invalid(TransactionInvalidReason.NONCE_TOO_HIGH)); } @Test public void transactionWithNullSenderCanBeValidIfGasPriceAndValueIsZero() { - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( + final TransactionValidator validator = + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.of(BigInteger.ONE)); final TransactionTestFixture builder = new TransactionTestFixture(); @@ -181,16 +224,17 @@ public void transactionWithNullSenderCanBeValidIfGasPriceAndValueIsZero() { final Address arbitrarySender = Address.fromHexString("1"); builder.gasPrice(Wei.ZERO).nonce(0).sender(arbitrarySender).value(Wei.ZERO); - assertThat(validator.validateForSender(builder.createTransaction(senderKeyPair), null, false)) + assertThat( + validator.validateForSender( + builder.createTransaction(senderKeyPair), null, processingBlockParams)) .isEqualTo(ValidationResult.valid()); } @Test public void shouldRejectTransactionIfAccountIsNotEOA() { - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( + final TransactionValidator validator = + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); - validator.setTransactionFilter(transactionFilter(false)); Account invalidEOA = when(account(basicTransaction.getUpfrontCost(0L), basicTransaction.getNonce()) @@ -198,38 +242,15 @@ public void shouldRejectTransactionIfAccountIsNotEOA() { .thenReturn(Hash.fromHexStringLenient("0xdeadbeef")) .getMock(); - assertThat(validator.validateForSender(basicTransaction, invalidEOA, true)) - .isEqualTo(ValidationResult.invalid(TransactionInvalidReason.TX_SENDER_NOT_AUTHORIZED)); - } - - @Test - public void shouldRejectTransactionIfAccountIsNotPermitted() { - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( - gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); - validator.setTransactionFilter(transactionFilter(false)); - - assertThat(validator.validateForSender(basicTransaction, accountWithNonce(0), true)) + assertThat(validator.validateForSender(basicTransaction, invalidEOA, processingBlockParams)) .isEqualTo(ValidationResult.invalid(TransactionInvalidReason.TX_SENDER_NOT_AUTHORIZED)); } - @Test - public void shouldAcceptValidTransactionIfAccountIsPermitted() { - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( - gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); - validator.setTransactionFilter(transactionFilter(true)); - - assertThat(validator.validateForSender(basicTransaction, accountWithNonce(0), true)) - .isEqualTo(ValidationResult.valid()); - } - @Test public void shouldRejectTransactionWithMaxFeeTimesGasLimitGreaterThanBalance() { - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( + final TransactionValidator validator = + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); - validator.setTransactionFilter(transactionFilter(true)); assertThat( validator.validateForSender( @@ -245,14 +266,14 @@ public void shouldRejectTransactionWithMaxFeeTimesGasLimitGreaterThanBalance() { .chainId(BigInteger.ONE) .signAndBuild(new SECP256K1().generateKeyPair()), account(Wei.of(100), 0), - true)) + transactionPoolParams)) .isEqualTo(ValidationResult.invalid(UPFRONT_COST_EXCEEDS_BALANCE)); } @Test public void shouldRejectTransactionWithMaxPriorityFeeGreaterThanMaxFee() { - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( + final TransactionValidator validator = + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), FeeMarket.london(0L), @@ -263,7 +284,6 @@ public void shouldRejectTransactionWithMaxPriorityFeeGreaterThanMaxFee() { TransactionType.FRONTIER, TransactionType.ACCESS_LIST, TransactionType.EIP1559 }), Integer.MAX_VALUE); - validator.setTransactionFilter(transactionFilter(true)); final Transaction transaction = Transaction.builder() @@ -286,60 +306,10 @@ public void shouldRejectTransactionWithMaxPriorityFeeGreaterThanMaxFee() { .isEqualTo("max priority fee per gas cannot be greater than max fee per gas"); } - @Test - public void shouldPropagateCorrectStateChangeParamToTransactionFilter() { - final ArgumentCaptor stateChangeLocalParamCaptor = - ArgumentCaptor.forClass(Boolean.class); - final ArgumentCaptor stateChangeOnchainParamCaptor = - ArgumentCaptor.forClass(Boolean.class); - final TransactionFilter transactionFilter = mock(TransactionFilter.class); - when(transactionFilter.permitted( - any(Transaction.class), - stateChangeLocalParamCaptor.capture(), - stateChangeOnchainParamCaptor.capture())) - .thenReturn(true); - - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( - gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); - validator.setTransactionFilter(transactionFilter); - - final TransactionValidationParams validationParams = - ImmutableTransactionValidationParams.builder().checkOnchainPermissions(true).build(); - - validator.validateForSender(basicTransaction, accountWithNonce(0), validationParams); - - assertThat(stateChangeLocalParamCaptor.getValue()).isTrue(); - assertThat(stateChangeOnchainParamCaptor.getValue()).isTrue(); - } - - @Test - public void shouldNotCheckAccountPermissionIfBothValidationParamsCheckPermissionsAreFalse() { - final TransactionFilter transactionFilter = mock(TransactionFilter.class); - - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( - gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); - validator.setTransactionFilter(transactionFilter); - - final TransactionValidationParams validationParams = - ImmutableTransactionValidationParams.builder() - .checkOnchainPermissions(false) - .checkLocalPermissions(false) - .build(); - - validator.validateForSender(basicTransaction, accountWithNonce(0), validationParams); - - assertThat(validator.validateForSender(basicTransaction, accountWithNonce(0), validationParams)) - .isEqualTo(ValidationResult.valid()); - - verifyNoInteractions(transactionFilter); - } - @Test public void shouldAcceptOnlyTransactionsInAcceptedTransactionTypes() { - final MainnetTransactionValidator frontierValidator = - new MainnetTransactionValidator( + final TransactionValidator frontierValidator = + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), FeeMarket.legacy(), @@ -348,7 +318,7 @@ public void shouldAcceptOnlyTransactionsInAcceptedTransactionTypes() { Set.of(TransactionType.FRONTIER), Integer.MAX_VALUE); - final MainnetTransactionValidator eip1559Validator = + final TransactionValidator eip1559Validator = new MainnetTransactionValidator( gasCalculator, GasLimitCalculator.constant(), @@ -381,8 +351,8 @@ public void shouldAcceptOnlyTransactionsInAcceptedTransactionTypes() { @Test public void shouldRejectTransactionIfEIP1559TransactionGasPriceLessBaseFee() { - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( + final TransactionValidator validator = + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), FeeMarket.london(0L), @@ -405,8 +375,8 @@ public void shouldRejectTransactionIfEIP1559TransactionGasPriceLessBaseFee() { @Test public void shouldAcceptZeroGasPriceTransactionIfBaseFeeIsZero() { final Optional zeroBaseFee = Optional.of(Wei.ZERO); - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( + final TransactionValidator validator = + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), FeeMarket.london(0L, zeroBaseFee), @@ -428,8 +398,8 @@ public void shouldAcceptZeroGasPriceTransactionIfBaseFeeIsZero() { @Test public void shouldAcceptValidEIP1559() { - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( + final TransactionValidator validator = + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), FeeMarket.london(0L), @@ -453,8 +423,8 @@ public void shouldAcceptValidEIP1559() { @Test public void shouldValidate1559TransactionWithPriceLowerThanBaseFeeForTransactionPool() { - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( + final TransactionValidator validator = + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), FeeMarket.london(0L), @@ -479,8 +449,8 @@ public void shouldValidate1559TransactionWithPriceLowerThanBaseFeeForTransaction @Test public void shouldRejectTooLargeInitcode() { - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( + final TransactionValidator validator = + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), FeeMarket.london(0L), @@ -504,25 +474,85 @@ public void shouldRejectTooLargeInitcode() { .isEqualTo("Initcode size of 49153 exceeds maximum size of 49152"); } + @Test + public void shouldRejectContractCreateWithBlob() { + /* + https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4844.md#blob-transaction + "The field to deviates slightly from the semantics with the exception that it + MUST NOT be nil and therefore must always represent a 20-byte address. + This means that blob transactions cannot have the form of a create transaction." + */ + final TransactionValidator validator = + createTransactionValidator( + gasCalculator, + GasLimitCalculator.constant(), + FeeMarket.cancun(0L, Optional.empty()), + false, + Optional.of(BigInteger.ONE), + Set.of(TransactionType.FRONTIER, TransactionType.EIP1559, TransactionType.BLOB), + 0xc000); + + var blobTx = + new TransactionTestFixture() + .to(Optional.empty()) + .type(TransactionType.BLOB) + .chainId(Optional.of(BigInteger.ONE)) + .maxFeePerGas(Optional.of(Wei.of(15))) + .maxFeePerBlobGas(Optional.of(Wei.of(128))) + .maxPriorityFeePerGas(Optional.of(Wei.of(1))) + .blobsWithCommitments( + Optional.of( + new BlobsWithCommitments( + List.of(new KZGCommitment(Bytes.EMPTY)), + List.of(new Blob(Bytes.EMPTY)), + List.of(new KZGProof(Bytes.EMPTY)), + List.of(VersionedHash.DEFAULT_VERSIONED_HASH)))) + .versionedHashes(Optional.of(List.of(VersionedHash.DEFAULT_VERSIONED_HASH))) + .createTransaction(senderKeys); + var validationResult = + validator.validate(blobTx, Optional.empty(), transactionValidationParams); + if (!validationResult.isValid()) { + System.out.println( + validationResult.getInvalidReason() + " " + validationResult.getErrorMessage()); + } + + assertThat(validationResult.isValid()).isFalse(); + assertThat(validationResult.getInvalidReason()) + .isEqualTo(TransactionInvalidReason.INVALID_TRANSACTION_FORMAT); + } + @Test public void shouldAcceptTransactionWithAtLeastOneBlob() { - final MainnetTransactionValidator validator = - new MainnetTransactionValidator( + when(gasCalculator.blobGasCost(anyInt())).thenReturn(2L); + final TransactionValidator validator = + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), - FeeMarket.london(0L), + FeeMarket.cancun(0L, Optional.empty()), false, Optional.of(BigInteger.ONE), Set.of(TransactionType.FRONTIER, TransactionType.EIP1559, TransactionType.BLOB), 0xc000); + BlobTestFixture blobTestFixture = new BlobTestFixture(); + BlobsWithCommitments bwc = blobTestFixture.createBlobsWithCommitments(1); var blobTx = new TransactionTestFixture() + .to(Optional.of(Address.fromHexString("0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"))) .type(TransactionType.BLOB) .chainId(Optional.of(BigInteger.ONE)) + .maxFeePerGas(Optional.of(Wei.of(15))) + .maxFeePerBlobGas(Optional.of(Wei.of(128))) + .maxPriorityFeePerGas(Optional.of(Wei.of(1))) + .blobsWithCommitments(Optional.of(bwc)) + .versionedHashes(Optional.of(bwc.getVersionedHashes())) .createTransaction(senderKeys); var validationResult = validator.validate(blobTx, Optional.empty(), transactionValidationParams); + if (!validationResult.isValid()) { + System.out.println( + validationResult.getInvalidReason() + " " + validationResult.getErrorMessage()); + } assertThat(validationResult.isValid()).isTrue(); } @@ -537,11 +567,4 @@ private Account account(final Wei balance, final long nonce) { when(account.getNonce()).thenReturn(nonce); return account; } - - private TransactionFilter transactionFilter(final boolean permitted) { - final TransactionFilter transactionFilter = mock(TransactionFilter.class); - when(transactionFilter.permitted(any(Transaction.class), anyBoolean(), anyBoolean())) - .thenReturn(permitted); - return transactionFilter; - } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PermissionTransactionValidatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PermissionTransactionValidatorTest.java new file mode 100644 index 00000000000..0b4c948f55e --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PermissionTransactionValidatorTest.java @@ -0,0 +1,161 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.mainnet; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams.transactionPoolParams; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.crypto.KeyPair; +import org.hyperledger.besu.crypto.SignatureAlgorithm; +import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.GasLimitCalculator; +import org.hyperledger.besu.ethereum.core.PermissionTransactionFilter; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.core.TransactionTestFixture; +import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; +import org.hyperledger.besu.evm.account.Account; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; + +import java.math.BigInteger; +import java.util.Optional; +import java.util.function.Supplier; + +import com.google.common.base.Suppliers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class PermissionTransactionValidatorTest extends MainnetTransactionValidatorTest { + + private static final Supplier SIGNATURE_ALGORITHM = + Suppliers.memoize(SignatureAlgorithmFactory::getInstance); + private static final KeyPair senderKeys = SIGNATURE_ALGORITHM.get().generateKeyPair(); + @Mock private GasCalculator gasCalculator; + + private final Transaction basicTransaction = + new TransactionTestFixture() + .chainId(Optional.of(BigInteger.ONE)) + .createTransaction(senderKeys); + + @Test + public void shouldRejectTransactionIfAccountIsNotPermitted() { + final TransactionValidator baseValidator = + createTransactionValidator( + gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); + final TransactionValidator validator = + new PermissionTransactionValidator(baseValidator, transactionFilter(false)); + + assertThat( + validator.validateForSender( + basicTransaction, accountWithNonce(0), transactionPoolParams)) + .isEqualTo(ValidationResult.invalid(TransactionInvalidReason.TX_SENDER_NOT_AUTHORIZED)); + } + + @Test + public void shouldAcceptValidTransactionIfAccountIsPermitted() { + final TransactionValidator baseValidator = + createTransactionValidator( + gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); + final TransactionValidator validator = + new PermissionTransactionValidator(baseValidator, transactionFilter(true)); + + assertThat( + validator.validateForSender( + basicTransaction, accountWithNonce(0), transactionPoolParams)) + .isEqualTo(ValidationResult.valid()); + } + + @Test + public void shouldPropagateCorrectStateChangeParamToTransactionFilter() { + final ArgumentCaptor stateChangeLocalParamCaptor = + ArgumentCaptor.forClass(Boolean.class); + final ArgumentCaptor stateChangeOnchainParamCaptor = + ArgumentCaptor.forClass(Boolean.class); + final PermissionTransactionFilter permissionTransactionFilter = + mock(PermissionTransactionFilter.class); + when(permissionTransactionFilter.permitted( + any(Transaction.class), + stateChangeLocalParamCaptor.capture(), + stateChangeOnchainParamCaptor.capture())) + .thenReturn(true); + + final TransactionValidator baseValidator = + createTransactionValidator( + gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); + final TransactionValidator validator = + new PermissionTransactionValidator(baseValidator, permissionTransactionFilter); + + final TransactionValidationParams validationParams = + ImmutableTransactionValidationParams.builder().checkOnchainPermissions(true).build(); + + validator.validateForSender(basicTransaction, accountWithNonce(0), validationParams); + + assertThat(stateChangeLocalParamCaptor.getValue()).isTrue(); + assertThat(stateChangeOnchainParamCaptor.getValue()).isTrue(); + } + + @Test + public void shouldNotCheckAccountPermissionIfBothValidationParamsCheckPermissionsAreFalse() { + final PermissionTransactionFilter permissionTransactionFilter = + mock(PermissionTransactionFilter.class); + + final TransactionValidator baseValidator = + createTransactionValidator( + gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); + final TransactionValidator validator = + new PermissionTransactionValidator(baseValidator, permissionTransactionFilter); + + final TransactionValidationParams validationParams = + ImmutableTransactionValidationParams.builder() + .checkOnchainPermissions(false) + .checkLocalPermissions(false) + .build(); + + validator.validateForSender(basicTransaction, accountWithNonce(0), validationParams); + + assertThat(validator.validateForSender(basicTransaction, accountWithNonce(0), validationParams)) + .isEqualTo(ValidationResult.valid()); + + verifyNoInteractions(permissionTransactionFilter); + } + + private Account accountWithNonce(final long nonce) { + return account(basicTransaction.getUpfrontCost(0L), nonce); + } + + private Account account(final Wei balance, final long nonce) { + final Account account = mock(Account.class); + when(account.getBalance()).thenReturn(balance); + when(account.getNonce()).thenReturn(nonce); + return account; + } + + private PermissionTransactionFilter transactionFilter(final boolean permitted) { + final PermissionTransactionFilter permissionTransactionFilter = + mock(PermissionTransactionFilter.class); + when(permissionTransactionFilter.permitted(any(Transaction.class), anyBoolean(), anyBoolean())) + .thenReturn(permitted); + return permissionTransactionFilter; + } +} diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PoWSolverTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PoWSolverTest.java index 510e78b8028..92cdce6eb0e 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PoWSolverTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PoWSolverTest.java @@ -36,11 +36,11 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PoWSolverTest { @Test diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PrivacyBlockProcessorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PrivacyBlockProcessorTest.java index 6f1796876e5..8835854ee05 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PrivacyBlockProcessorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PrivacyBlockProcessorTest.java @@ -53,12 +53,12 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PrivacyBlockProcessorTest { private PrivacyBlockProcessor privacyBlockProcessor; @@ -69,7 +69,7 @@ public class PrivacyBlockProcessorTest { private ProtocolSchedule protocolSchedule; private WorldStateArchive publicWorldStateArchive; - @Before + @BeforeEach public void setUp() { blockProcessor = mock(AbstractBlockProcessor.class); privateStateStorage = new PrivateStateKeyValueStorage(new InMemoryKeyValueStorage()); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilderTest.java index c573902726f..3d66d8df403 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilderTest.java @@ -33,14 +33,14 @@ import java.util.function.Function; import java.util.stream.Collectors; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.stubbing.Answer; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class ProtocolScheduleBuilderTest { private final long PRE_SHANGHAI_TIMESTAMP = 1680488620L; // Mon, 03 Apr 2023 02:23:40 UTC @Mock GenesisConfigOptions configOptions; @@ -48,7 +48,7 @@ public class ProtocolScheduleBuilderTest { private static final BigInteger CHAIN_ID = BigInteger.ONE; private ProtocolScheduleBuilder builder; - @Before + @BeforeEach public void setup() { builder = new ProtocolScheduleBuilder( diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecAdaptersTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecAdaptersTest.java index 7b01135148f..501288b7ab4 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecAdaptersTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecAdaptersTest.java @@ -19,12 +19,12 @@ import java.util.Map; import java.util.function.Function; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class ProtocolSpecAdaptersTest { @Mock private Function firstModifier; diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/RefundSstoreGasTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/RefundSstoreGasTest.java index 06594c21913..e98bbc528c1 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/RefundSstoreGasTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/RefundSstoreGasTest.java @@ -25,104 +25,69 @@ import org.hyperledger.besu.evm.gascalculator.PetersburgGasCalculator; import java.util.function.Supplier; +import java.util.stream.Stream; import org.apache.tuweni.units.bigints.UInt256; import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameter; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public class RefundSstoreGasTest { private static final UInt256 TWO = UInt256.valueOf(2); - @Parameters(name = "calculator: {0}, original: {2}, current: {3}, new: {4}") - public static Object[][] scenarios() { + public static Stream scenarios() { final GasCalculator constantinople = new ConstantinopleGasCalculator(); final GasCalculator petersburg = new PetersburgGasCalculator(); final GasCalculator istanbul = new IstanbulGasCalculator(); - return new Object[][] { - // Zero no-op - {"constantinople", constantinople, ZERO, ZERO, ZERO, 200L, 0L}, - {"petersburg", petersburg, ZERO, ZERO, ZERO, 5_000L, 0L}, - {"istanbul", istanbul, ZERO, ZERO, ZERO, 800L, 0L}, - - // Zero fresh change - {"constantinople", constantinople, ZERO, ZERO, ONE, 20_000L, 0L}, - {"petersburg", petersburg, ZERO, ZERO, ONE, 20_000L, 0L}, - {"istanbul", istanbul, ZERO, ZERO, ONE, 20_000L, 0L}, - - // Dirty, reset to zero - {"constantinople", constantinople, ZERO, ONE, ZERO, 200L, 19_800L}, - {"petersburg", petersburg, ZERO, ONE, ZERO, 5_000L, 15_000L}, - {"istanbul", istanbul, ZERO, ONE, ZERO, 800L, 19_200L}, - - // Dirty, changed but not reset - {"constantinople", constantinople, ZERO, ONE, TWO, 200L, 0L}, - {"petersburg", petersburg, ZERO, ONE, TWO, 5_000L, 0L}, - {"istanbul", istanbul, ZERO, ONE, TWO, 800L, 0L}, - - // Dirty no-op - {"constantinople", constantinople, ZERO, ONE, ONE, 200L, 0L}, - {"petersburg", petersburg, ZERO, ONE, ONE, 5_000L, 0L}, - {"istanbul", istanbul, ZERO, ONE, ONE, 800L, 0L}, - - // Dirty, zero no-op - {"constantinople", constantinople, ONE, ZERO, ZERO, 200L, 0L}, - {"petersburg", petersburg, ONE, ZERO, ZERO, 5_000L, 0L}, - {"istanbul", istanbul, ONE, ZERO, ZERO, 800L, 0L}, - - // Dirty, reset to non-zero - {"constantinople", constantinople, ONE, ZERO, ONE, 200L, -15_000L + 4_800L}, - {"petersburg", petersburg, ONE, ZERO, ONE, 20_000L, 0L}, - {"istanbul", istanbul, ONE, ZERO, ONE, 800L, -15_000L + 4_200L}, - - // Fresh change to zero - {"constantinople", constantinople, ONE, ONE, ZERO, 5_000L, 15_000L}, - {"petersburg", petersburg, ONE, ONE, ZERO, 5_000L, 15_000L}, - {"istanbul", istanbul, ONE, ONE, ZERO, 5_000L, 15_000L}, - - // Fresh change with all non-zero - {"constantinople", constantinople, ONE, ONE, TWO, 5_000L, 0L}, - {"petersburg", petersburg, ONE, ONE, TWO, 5_000L, 0L}, - {"istanbul", istanbul, ONE, ONE, TWO, 5_000L, 0L}, - - // Dirty, clear originally set value - {"constantinople", constantinople, ONE, TWO, ZERO, 200L, 15_000L}, - {"petersburg", petersburg, ONE, TWO, ZERO, 5_000L, 15_000L}, - {"istanbul", istanbul, ONE, TWO, ZERO, 800L, 15_000L}, - - // Non-zero no-op - {"constantinople", constantinople, ONE, ONE, ONE, 200L, 0L}, - {"petersburg", petersburg, ONE, ONE, ONE, 5_000L, 0L}, - {"istanbul", istanbul, ONE, ONE, ONE, 800L, 0L}, - }; + return Stream.of( + // Zero no-op + Arguments.of("constantinople", constantinople, ZERO, ZERO, ZERO, 200L, 0L), + Arguments.of("petersburg", petersburg, ZERO, ZERO, ZERO, 5_000L, 0L), + Arguments.of("istanbul", istanbul, ZERO, ZERO, ZERO, 800L, 0L), + // Zero fresh change + Arguments.of("constantinople", constantinople, ZERO, ZERO, ONE, 20_000L, 0L), + Arguments.of("petersburg", petersburg, ZERO, ZERO, ONE, 20_000L, 0L), + Arguments.of("istanbul", istanbul, ZERO, ZERO, ONE, 20_000L, 0L), + // Dirty, reset to zero + Arguments.of("constantinople", constantinople, ZERO, ONE, ZERO, 200L, 19_800L), + Arguments.of("petersburg", petersburg, ZERO, ONE, ZERO, 5_000L, 15_000L), + Arguments.of("istanbul", istanbul, ZERO, ONE, ZERO, 800L, 19_200L), + // Dirty, changed but not reset + Arguments.of("constantinople", constantinople, ZERO, ONE, TWO, 200L, 0L), + Arguments.of("petersburg", petersburg, ZERO, ONE, TWO, 5_000L, 0L), + Arguments.of("istanbul", istanbul, ZERO, ONE, TWO, 800L, 0L), + // Dirty no-op + Arguments.of("constantinople", constantinople, ZERO, ONE, ONE, 200L, 0L), + Arguments.of("petersburg", petersburg, ZERO, ONE, ONE, 5_000L, 0L), + Arguments.of("istanbul", istanbul, ZERO, ONE, ONE, 800L, 0L), + // Dirty, zero no-op + Arguments.of("constantinople", constantinople, ONE, ZERO, ZERO, 200L, 0L), + Arguments.of("petersburg", petersburg, ONE, ZERO, ZERO, 5_000L, 0L), + Arguments.of("istanbul", istanbul, ONE, ZERO, ZERO, 800L, 0L), + // Dirty, reset to non-zero + Arguments.of("constantinople", constantinople, ONE, ZERO, ONE, 200L, -15_000L + 4_800L), + Arguments.of("petersburg", petersburg, ONE, ZERO, ONE, 20_000L, 0L), + Arguments.of("istanbul", istanbul, ONE, ZERO, ONE, 800L, -15_000L + 4_200L), + // Fresh change to zero + Arguments.of("constantinople", constantinople, ONE, ONE, ZERO, 5_000L, 15_000L), + Arguments.of("petersburg", petersburg, ONE, ONE, ZERO, 5_000L, 15_000L), + Arguments.of("istanbul", istanbul, ONE, ONE, ZERO, 5_000L, 15_000L), + // Fresh change with all non-zero + Arguments.of("constantinople", constantinople, ONE, ONE, TWO, 5_000L, 0L), + Arguments.of("petersburg", petersburg, ONE, ONE, TWO, 5_000L, 0L), + Arguments.of("istanbul", istanbul, ONE, ONE, TWO, 5_000L, 0L), + // Dirty, clear originally set value + Arguments.of("constantinople", constantinople, ONE, TWO, ZERO, 200L, 15_000L), + Arguments.of("petersburg", petersburg, ONE, TWO, ZERO, 5_000L, 15_000L), + Arguments.of("istanbul", istanbul, ONE, TWO, ZERO, 800L, 15_000L), + // Non-zero no-op + Arguments.of("constantinople", constantinople, ONE, ONE, ONE, 200L, 0L), + Arguments.of("petersburg", petersburg, ONE, ONE, ONE, 5_000L, 0L), + Arguments.of("istanbul", istanbul, ONE, ONE, ONE, 800L, 0L)); } - @Parameter public String forkName; - - @Parameter(value = 1) - public GasCalculator gasCalculator = new ConstantinopleGasCalculator(); - - @Parameter(value = 2) - public UInt256 originalValue; - - @Parameter(value = 3) - public UInt256 currentValue; - - @Parameter(value = 4) - public UInt256 newValue; - - @Parameter(value = 5) - public long expectedGasCost; - - @Parameter(value = 6) - public long expectedGasRefund; - private final Supplier mockSupplierForOriginalValue = mockSupplier(); private final Supplier mockSupplierCurrentValue = mockSupplier(); @@ -131,22 +96,39 @@ private Supplier mockSupplier() { return mock(Supplier.class); } - @Before - public void setUp() { + public void setUp(final UInt256 originalValue, final UInt256 currentValue) { when(mockSupplierForOriginalValue.get()).thenReturn(originalValue); when(mockSupplierCurrentValue.get()).thenReturn(currentValue); } - @Test - public void shouldChargeCorrectGas() { + @ParameterizedTest(name = "calculator: {0}, original: {2}, current: {3}, new: {4}") + @MethodSource("scenarios") + public void shouldChargeCorrectGas( + final String forkName, + final GasCalculator gasCalculator, + final UInt256 originalValue, + final UInt256 currentValue, + final UInt256 newValue, + final long expectedGasCost, + final long expectedGasRefund) { + setUp(originalValue, currentValue); Assertions.assertThat( gasCalculator.calculateStorageCost( newValue, mockSupplierCurrentValue, mockSupplierForOriginalValue)) .isEqualTo(expectedGasCost); } - @Test - public void shouldRefundCorrectGas() { + @ParameterizedTest(name = "calculator: {0}, original: {2}, current: {3}, new: {4}") + @MethodSource("scenarios") + public void shouldRefundCorrectGas( + final String forkName, + final GasCalculator gasCalculator, + final UInt256 originalValue, + final UInt256 currentValue, + final UInt256 newValue, + final long expectedGasCost, + final long expectedGasRefund) { + setUp(originalValue, currentValue); Assertions.assertThat( gasCalculator.calculateStorageRefundAmount( newValue, mockSupplierCurrentValue, mockSupplierForOriginalValue)) diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/TargetingGasLimitCalculatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/TargetingGasLimitCalculatorTest.java index bec65b731ed..b19d2310c5c 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/TargetingGasLimitCalculatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/TargetingGasLimitCalculatorTest.java @@ -22,7 +22,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.GasLimitRangeAndDeltaValidationRule; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class TargetingGasLimitCalculatorTest { private static final long ADJUSTMENT_FACTOR = 1024L; diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidationFactoryTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidationFactoryTest.java new file mode 100644 index 00000000000..334439b0844 --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidationFactoryTest.java @@ -0,0 +1,52 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.mainnet; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.hyperledger.besu.ethereum.GasLimitCalculator; +import org.hyperledger.besu.ethereum.core.PermissionTransactionFilter; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; + +import java.math.BigInteger; +import java.util.Optional; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class TransactionValidationFactoryTest { + private static final Optional CHAIN_ID = Optional.of(BigInteger.ONE); + @Mock GasCalculator gasCalculator; + @Mock GasLimitCalculator gasLimitCalculator; + @Mock PermissionTransactionFilter permissionTransactionFilter; + + @Test + public void alwaysTheSameInstanceIsReturnedOnceCreated() { + final TransactionValidatorFactory transactionValidatorFactory = + new TransactionValidatorFactory(gasCalculator, gasLimitCalculator, false, CHAIN_ID); + assertThat(transactionValidatorFactory.get()).isSameAs(transactionValidatorFactory.get()); + } + + @Test + public void alwaysTheSameInstanceIsReturnedOnceCreatedWithPermissionFilter() { + final TransactionValidatorFactory transactionValidatorFactory = + new TransactionValidatorFactory(gasCalculator, gasLimitCalculator, false, CHAIN_ID); + transactionValidatorFactory.setPermissionTransactionFilter(permissionTransactionFilter); + assertThat(transactionValidatorFactory.get()).isSameAs(transactionValidatorFactory.get()); + } +} diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidationParamsTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidationParamsTest.java index 6e269b8a1bb..3b5ac890491 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidationParamsTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidationParamsTest.java @@ -16,7 +16,7 @@ import static org.assertj.core.api.Assertions.assertThat; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class TransactionValidationParamsTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ValidationResultTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ValidationResultTest.java index 22a27229f67..83511b1a246 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ValidationResultTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ValidationResultTest.java @@ -19,7 +19,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class ValidationResultTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarketTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarketTest.java new file mode 100644 index 00000000000..2394d66da51 --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarketTest.java @@ -0,0 +1,67 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hyperledger.besu.ethereum.mainnet.feemarket; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.hyperledger.besu.datatypes.BlobGas; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import org.junit.jupiter.api.Test; + +class CancunFeeMarketTest { + + private static final int BLOB_GAS_PER_BLOB = 131072; + + @Test + void dataPricePerGas() { + CancunFeeMarket cancunFeeMarket = new CancunFeeMarket(0, Optional.empty()); + // when no excess blob gas, data price per gas is 1 + assertEquals(1, cancunFeeMarket.blobGasPricePerGas(BlobGas.ZERO).getAsBigInteger().intValue()); + + record BlobGasPricing(long excess, long price) {} + List testVector = new ArrayList<>(); + + int numBlobs = 1; + long price = 1; + while (price <= 1000) { + price = blobGasPrice(BlobGas.of(numBlobs * BLOB_GAS_PER_BLOB)); + var testCase = new BlobGasPricing(numBlobs * BLOB_GAS_PER_BLOB, price); + testVector.add(testCase); + numBlobs++; + } + + testVector.stream() + .forEach( + blobGasPricing -> { + assertEquals( + blobGasPricing.price, + cancunFeeMarket + .blobGasPricePerGas(BlobGas.of(blobGasPricing.excess)) + .getAsBigInteger() + .intValue()); + }); + } + + private long blobGasPrice(final BlobGas excess) { + double dgufDenominator = 3338477; + double fakeExpo = excess.getValue().longValue() / dgufDenominator; + return (long) (1 * Math.exp(fakeExpo)); + } +} diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarketTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarketTest.java index 5c78e7f963f..1d0bdd53c97 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarketTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarketTest.java @@ -18,14 +18,14 @@ import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.Optional; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class LondonFeeMarketTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ZeroBaseFeeMarketTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ZeroBaseFeeMarketTest.java index dbe35d19890..4047c647aec 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ZeroBaseFeeMarketTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ZeroBaseFeeMarketTest.java @@ -18,16 +18,16 @@ import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; -import org.hyperledger.besu.datatypes.DataGas; +import org.hyperledger.besu.datatypes.BlobGas; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class ZeroBaseFeeMarketTest { @@ -36,7 +36,7 @@ public class ZeroBaseFeeMarketTest { private static final long FORK_BLOCK = 0; private ZeroBaseFeeMarket zeroBaseFeeMarket; - @Before + @BeforeEach public void setUp() throws Exception { zeroBaseFeeMarket = new ZeroBaseFeeMarket(FORK_BLOCK); } @@ -147,6 +147,6 @@ public void implementsDataFeedShouldReturnFalse() { @Test public void dataPriceShouldReturnsZero() { - assertThat(zeroBaseFeeMarket.dataPrice(DataGas.ONE)).isEqualTo(Wei.ZERO); + assertThat(zeroBaseFeeMarket.blobGasPricePerGas(BlobGas.ONE)).isEqualTo(Wei.ZERO); } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/AncestryValidationRuleTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/AncestryValidationRuleTest.java index eb893661849..cc6e1fa29e2 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/AncestryValidationRuleTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/AncestryValidationRuleTest.java @@ -20,7 +20,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class AncestryValidationRuleTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BaseFeeMarketBlockHeaderGasPriceValidationRuleTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BaseFeeMarketBlockHeaderGasPriceValidationRuleTest.java index 6dca61e5040..ca2cfe4d565 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BaseFeeMarketBlockHeaderGasPriceValidationRuleTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BaseFeeMarketBlockHeaderGasPriceValidationRuleTest.java @@ -24,8 +24,8 @@ import java.util.Optional; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class BaseFeeMarketBlockHeaderGasPriceValidationRuleTest { @@ -34,7 +34,7 @@ public class BaseFeeMarketBlockHeaderGasPriceValidationRuleTest { private BaseFeeMarketBlockHeaderGasPriceValidationRule validationRule; private final BaseFeeMarket feeMarket = FeeMarket.london(FORK_BLOCK); - @Before + @BeforeEach public void setUp() { validationRule = new BaseFeeMarketBlockHeaderGasPriceValidationRule(baseFeeMarket); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BlobGasValidationRuleTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BlobGasValidationRuleTest.java new file mode 100644 index 00000000000..34f7079be10 --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BlobGasValidationRuleTest.java @@ -0,0 +1,78 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hyperledger.besu.ethereum.mainnet.headervalidationrules; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.hyperledger.besu.datatypes.BlobGas; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; +import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** Tests for the {@link BlobGasValidationRule} class. */ +public class BlobGasValidationRuleTest { + + private CancunGasCalculator gasCalculator; + private BlobGasValidationRule blobGasValidationRule; + + @BeforeEach + public void setUp() { + gasCalculator = new CancunGasCalculator(); + blobGasValidationRule = new BlobGasValidationRule(gasCalculator); + } + + /** Tests that the header blob gas matches the calculated blob gas and passes validation. */ + @Test + public void validateHeader_BlobGasMatchesCalculated_SuccessValidation() { + long target = gasCalculator.getTargetBlobGasPerBlock(); + + // Create parent header + final BlockHeaderTestFixture parentBuilder = new BlockHeaderTestFixture(); + parentBuilder.excessBlobGas(BlobGas.of(1L)); + parentBuilder.blobGasUsed(target); + final BlockHeader parentHeader = parentBuilder.buildHeader(); + + // Create block header with matching excessBlobGas + final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); + headerBuilder.excessBlobGas(BlobGas.of(1L)); + final BlockHeader header = headerBuilder.buildHeader(); + + assertThat(blobGasValidationRule.validate(header, parentHeader)).isTrue(); + } + + /** + * Tests that the header blob gas is different from the calculated blob gas and fails validation. + */ + @Test + public void validateHeader_BlobGasDifferentFromCalculated_FailsValidation() { + long target = gasCalculator.getTargetBlobGasPerBlock(); + + // Create parent header + final BlockHeaderTestFixture parentBuilder = new BlockHeaderTestFixture(); + parentBuilder.excessBlobGas(BlobGas.of(1L)); + parentBuilder.blobGasUsed(target); + final BlockHeader parentHeader = parentBuilder.buildHeader(); + + // Create block header with different excessBlobGas + final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); + final BlockHeader header = headerBuilder.buildHeader(); + + assertThat(blobGasValidationRule.validate(header, parentHeader)).isFalse(); + } +} diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ConstantFieldValidationRuleTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ConstantFieldValidationRuleTest.java index 8ac7b158ea2..b7b0b6c2ead 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ConstantFieldValidationRuleTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ConstantFieldValidationRuleTest.java @@ -21,7 +21,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class ConstantFieldValidationRuleTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ExtraDataMaxLengthValidationRuleTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ExtraDataMaxLengthValidationRuleTest.java index f215445d509..e49f22950d6 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ExtraDataMaxLengthValidationRuleTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ExtraDataMaxLengthValidationRuleTest.java @@ -20,7 +20,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class ExtraDataMaxLengthValidationRuleTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/GasLimitElasticityValidationRuleTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/GasLimitElasticityValidationRuleTest.java index d707939fadd..bd69303a05c 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/GasLimitElasticityValidationRuleTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/GasLimitElasticityValidationRuleTest.java @@ -22,60 +22,41 @@ import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.LondonFeeMarket; -import java.util.Arrays; -import java.util.Collection; import java.util.Optional; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameter; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; -@RunWith(Parameterized.class) public class GasLimitElasticityValidationRuleTest { private static final Optional baseFeeMarket = Optional.of(new LondonFeeMarket(10)); - @Parameter public long headerGasLimit; - - @Parameter(1) - public long parentGasLimit; - - @Parameterized.Parameter(2) - public long headerNumber; - - @Parameter(3) - public boolean expectedResult; - public GasLimitRangeAndDeltaValidationRule uut = new GasLimitRangeAndDeltaValidationRule(5000, MAX_VALUE, baseFeeMarket); - @Parameters - public static Collection data() { - return Arrays.asList( - new Object[][] { - {20000000, 10000000, 10, true}, - {20019530, 10000000, 10, true}, - {20019531, 10000000, 10, false}, - {19980470, 10000000, 10, true}, - {19980469, 10000000, 10, false}, - {20000000, 20000000, 11, true}, - {20019530, 20000000, 11, true}, - {20019531, 20000000, 11, false}, - {19980470, 20000000, 11, true}, - {19980469, 20000000, 11, false}, - {40039061, 40000000, 11, true}, - {40039062, 40000000, 11, false}, - {39960939, 40000000, 11, true}, - {39960938, 40000000, 11, false}, - {4999, 40000000, 11, false} - }); - } - - @Test - public void test() { - + @ParameterizedTest + @CsvSource({ + "20000000, 10000000, 10, true", + "20019530, 10000000, 10, true", + "20019531, 10000000, 10, false", + "19980470, 10000000, 10, true", + "19980469, 10000000, 10, false", + "20000000, 20000000, 11, true", + "20019530, 20000000, 11, true", + "20019531, 20000000, 11, false", + "19980470, 20000000, 11, true", + "19980469, 20000000, 11, false", + "40039061, 40000000, 11, true", + "40039062, 40000000, 11, false", + "39960939, 40000000, 11, true", + "39960938, 40000000, 11, false", + "4999, 40000000, 11, false" + }) + public void testGasLimitElasticityValidationRule( + final long headerGasLimit, + final long parentGasLimit, + final long headerNumber, + final boolean expectedResult) { final BlockHeaderTestFixture blockHeaderBuilder = new BlockHeaderTestFixture(); blockHeaderBuilder.number(headerNumber); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/GasLimitElasticityValidationRuleZeroBaseFeeMarketTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/GasLimitElasticityValidationRuleZeroBaseFeeMarketTest.java index 0f0766623de..a25345994bc 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/GasLimitElasticityValidationRuleZeroBaseFeeMarketTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/GasLimitElasticityValidationRuleZeroBaseFeeMarketTest.java @@ -22,60 +22,42 @@ import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.ZeroBaseFeeMarket; -import java.util.Arrays; -import java.util.Collection; import java.util.Optional; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameter; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; -@RunWith(Parameterized.class) public class GasLimitElasticityValidationRuleZeroBaseFeeMarketTest { private static final Optional zeroBaseFeeMarket = Optional.of(new ZeroBaseFeeMarket(10)); - @Parameter public long headerGasLimit; - - @Parameter(1) - public long parentGasLimit; - - @Parameter(2) - public long headerNumber; - - @Parameter(3) - public boolean expectedResult; - public GasLimitRangeAndDeltaValidationRule uut = new GasLimitRangeAndDeltaValidationRule(5000, MAX_VALUE, zeroBaseFeeMarket); - @Parameters - public static Collection data() { - return Arrays.asList( - new Object[][] { - {20000000, 10000000, 10, true}, - {20019530, 10000000, 10, true}, - {20019531, 10000000, 10, false}, - {19980470, 10000000, 10, true}, - {19980469, 10000000, 10, false}, - {20000000, 20000000, 11, true}, - {20019530, 20000000, 11, true}, - {20019531, 20000000, 11, false}, - {19980470, 20000000, 11, true}, - {19980469, 20000000, 11, false}, - {40039061, 40000000, 11, true}, - {40039062, 40000000, 11, false}, - {39960939, 40000000, 11, true}, - {39960938, 40000000, 11, false}, - {4999, 40000000, 11, false} - }); - } - - @Test - public void test() { + @ParameterizedTest + @CsvSource({ + "20000000, 10000000, 10, true", + "20019530, 10000000, 10, true", + "20019531, 10000000, 10, false", + "19980470, 10000000, 10, true", + "19980469, 10000000, 10, false", + "20000000, 20000000, 11, true", + "20019530, 20000000, 11, true", + "20019531, 20000000, 11, false", + "19980470, 20000000, 11, true", + "19980469, 20000000, 11, false", + "40039061, 40000000, 11, true", + "40039062, 40000000, 11, false", + "39960939, 40000000, 11, true", + "39960938, 40000000, 11, false", + "4999, 40000000, 11, false" + }) + public void test( + final long headerGasLimit, + final long parentGasLimit, + final long headerNumber, + final boolean expectedResult) { final BlockHeaderTestFixture blockHeaderBuilder = new BlockHeaderTestFixture(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/GasLimitRangeAndDeltaValidationRuleTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/GasLimitRangeAndDeltaValidationRuleTest.java index bc17ace18e6..635f8e1c190 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/GasLimitRangeAndDeltaValidationRuleTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/GasLimitRangeAndDeltaValidationRuleTest.java @@ -20,68 +20,77 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; -import java.util.Arrays; -import java.util.Collection; import java.util.Optional; +import java.util.stream.Stream; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameter; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public class GasLimitRangeAndDeltaValidationRuleTest { - @Parameter public long headerGasLimit; - - @Parameter(1) - public long parentGasLimit; - - @Parameter(2) - public GasLimitRangeAndDeltaValidationRule uut; - - @Parameter(3) - public boolean expectedResult; - - @Parameter(4) - public Optional optionalBaseFee; - - @Parameters - public static Collection data() { - return Arrays.asList( - new Object[][] { - {4096, 4096, new GasLimitRangeAndDeltaValidationRule(4095, 4097), true, Optional.empty()}, - // In Range, no change = valid, - { - 4096, 4096, new GasLimitRangeAndDeltaValidationRule(4094, 4095), false, Optional.empty() - }, - // Out of Range, no change = invalid, - {4099, 4096, new GasLimitRangeAndDeltaValidationRule(4000, 4200), true, Optional.empty()}, - // In Range, <1/1024 change = valid, - {4093, 4096, new GasLimitRangeAndDeltaValidationRule(4000, 4200), true, Optional.empty()}, - // In Range, ,1/1024 change = valid, - { - 4092, 4096, new GasLimitRangeAndDeltaValidationRule(4000, 4200), false, Optional.empty() - }, - // In Range, == 1/1024 change = invalid, - { - 4100, 4096, new GasLimitRangeAndDeltaValidationRule(4000, 4200), false, Optional.empty() - }, - // In Range, == 1/1024 change = invalid, - { + public static Stream data() { + return Stream.of( + Arguments.of( + 4096, + 4096, + new GasLimitRangeAndDeltaValidationRule(4095, 4097), + true, + Optional.empty()), + // In Range, no change = valid, + Arguments.of( + 4096, + 4096, + new GasLimitRangeAndDeltaValidationRule(4094, 4095), + false, + Optional.empty()), + // Out of Range, no change = invalid, + Arguments.of( + 4099, + 4096, + new GasLimitRangeAndDeltaValidationRule(4000, 4200), + true, + Optional.empty()), + // In Range, <1/1024 change = valid, + Arguments.of( + 4093, + 4096, + new GasLimitRangeAndDeltaValidationRule(4000, 4200), + true, + Optional.empty()), + // In Range, ,1/1024 change = valid, + Arguments.of( + 4092, + 4096, + new GasLimitRangeAndDeltaValidationRule(4000, 4200), + false, + Optional.empty()), + // In Range, == 1/1024 change = invalid, + Arguments.of( + 4100, + 4096, + new GasLimitRangeAndDeltaValidationRule(4000, 4200), + false, + Optional.empty()), + // In Range, == 1/1024 change = invalid, + Arguments.of( 4099, 4096, new GasLimitRangeAndDeltaValidationRule(4000, 4200), false, - Optional.of(Wei.of(10L)) - } - // In Range, <1/1024 change, has basefee = invalid, - }); + Optional.of(Wei.of(10L))) + // In Range, <1/1024 change, has basefee = invalid, + ); } - @Test - public void test() { + @ParameterizedTest + @MethodSource("data") + public void test( + final long headerGasLimit, + final long parentGasLimit, + final GasLimitRangeAndDeltaValidationRule uut, + final boolean expectedResult, + final Optional optionalBaseFee) { final BlockHeaderTestFixture blockHeaderBuilder = new BlockHeaderTestFixture(); blockHeaderBuilder.gasLimit(headerGasLimit); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/GasUsageValidationRuleTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/GasUsageValidationRuleTest.java index 4157c2639b9..06dff080461 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/GasUsageValidationRuleTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/GasUsageValidationRuleTest.java @@ -19,38 +19,25 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; -import java.util.Arrays; -import java.util.Collection; +import java.util.stream.Stream; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameter; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public class GasUsageValidationRuleTest { - @Parameters - public static Collection data() { - return Arrays.asList( - new Object[][] { - {5, 6, true}, // gasUsed is less than gasLimit is valid - {5, 5, true}, // gasUsed is the same as gaslimit is valid - {5, 4, false}, // gasUsed is less than gasLimit - }); + public static Stream data() { + return Stream.of( + Arguments.of(5, 6, true), // gasUsed is less than gasLimit is valid + Arguments.of(5, 5, true), // gasUsed is the same as gaslimit is valid + Arguments.of(5, 4, false) // gasUsed is less than gasLimit + ); } - @Parameter public long gasUsed; - - @Parameter(1) - public long gasLimit; - - @Parameter(2) - public boolean expectedResult; - - @Test - public void test() { + @ParameterizedTest + @MethodSource("data") + public void test(final long gasUsed, final long gasLimit, final boolean expectedResult) { final GasUsageValidationRule uut = new GasUsageValidationRule(); final BlockHeaderTestFixture blockBuilder = new BlockHeaderTestFixture(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ProofOfWorkValidationRuleTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ProofOfWorkValidationRuleTest.java index 2622a362fa4..8d831ab7c4a 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ProofOfWorkValidationRuleTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ProofOfWorkValidationRuleTest.java @@ -33,25 +33,21 @@ import java.io.IOException; import java.math.BigInteger; -import java.util.Arrays; -import java.util.Collection; import java.util.Optional; +import java.util.stream.Stream; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public class ProofOfWorkValidationRuleTest { - private final BlockHeader blockHeader; - private final BlockHeader parentHeader; - private final ProofOfWorkValidationRule validationRule; + private BlockHeader blockHeader; + private BlockHeader parentHeader; + private ProofOfWorkValidationRule validationRule; - public ProofOfWorkValidationRuleTest(final long parentBlockNum, final long blockNum) - throws IOException { + public void setup(final long parentBlockNum, final long blockNum) throws IOException { blockHeader = ValidationTestUtils.readHeader(parentBlockNum); parentHeader = ValidationTestUtils.readHeader(blockNum); validationRule = @@ -59,25 +55,27 @@ public ProofOfWorkValidationRuleTest(final long parentBlockNum, final long block new EpochCalculator.DefaultEpochCalculator(), PoWHasher.ETHASH_LIGHT); } - @Parameters(name = "block {1}") - public static Collection data() { - - return Arrays.asList( - new Object[][] { - {300005, 300006}, - {1200000, 1200001}, - {4400000, 4400001}, - {4400001, 4400002} - }); + public static Stream data() { + return Stream.of( + Arguments.of(300005, 300006), + Arguments.of(1200000, 1200001), + Arguments.of(4400000, 4400001), + Arguments.of(4400001, 4400002)); } - @Test - public void validatesValidBlocks() { + @ParameterizedTest(name = "block {1}") + @MethodSource("data") + public void validatesValidBlocks(final long parentBlockNum, final long blockNum) + throws IOException { + setup(parentBlockNum, blockNum); assertThat(validationRule.validate(blockHeader, parentHeader)).isTrue(); } - @Test - public void failsBlockWithZeroValuedDifficulty() { + @ParameterizedTest(name = "block {1}") + @MethodSource("data") + public void failsBlockWithZeroValuedDifficulty(final long parentBlockNum, final long blockNum) + throws IOException { + setup(parentBlockNum, blockNum); final BlockHeader header = BlockHeaderBuilder.fromHeader(blockHeader) .difficulty(Difficulty.ZERO) @@ -86,8 +84,11 @@ public void failsBlockWithZeroValuedDifficulty() { assertThat(validationRule.validate(header, parentHeader)).isFalse(); } - @Test - public void passesBlockWithOneValuedDifficulty() { + @ParameterizedTest(name = "block {1}") + @MethodSource("data") + public void passesBlockWithOneValuedDifficulty(final long parentBlockNum, final long blockNum) + throws IOException { + setup(parentBlockNum, blockNum); final BlockHeaderBuilder headerBuilder = BlockHeaderBuilder.fromHeader(blockHeader) .difficulty(Difficulty.ONE) @@ -108,8 +109,11 @@ public void passesBlockWithOneValuedDifficulty() { assertThat(validationRule.validate(header, parentHeader)).isTrue(); } - @Test - public void failsWithVeryLargeDifficulty() { + @ParameterizedTest(name = "block {1}") + @MethodSource("data") + public void failsWithVeryLargeDifficulty(final long parentBlockNum, final long blockNum) + throws IOException { + setup(parentBlockNum, blockNum); final Difficulty largeDifficulty = Difficulty.of(BigInteger.valueOf(2).pow(255)); final BlockHeader header = BlockHeaderBuilder.fromHeader(blockHeader) @@ -119,8 +123,11 @@ public void failsWithVeryLargeDifficulty() { assertThat(validationRule.validate(header, parentHeader)).isFalse(); } - @Test - public void failsWithMisMatchedMixHash() { + @ParameterizedTest(name = "block {1}") + @MethodSource("data") + public void failsWithMisMatchedMixHash(final long parentBlockNum, final long blockNum) + throws IOException { + setup(parentBlockNum, blockNum); final Hash updateMixHash = Hash.wrap(UInt256.fromBytes(blockHeader.getMixHash()).subtract(1L)); final BlockHeader header = BlockHeaderBuilder.fromHeader(blockHeader) @@ -130,8 +137,11 @@ public void failsWithMisMatchedMixHash() { assertThat(validationRule.validate(header, parentHeader)).isFalse(); } - @Test - public void failsWithMisMatchedNonce() { + @ParameterizedTest(name = "block {1}") + @MethodSource("data") + public void failsWithMisMatchedNonce(final long parentBlockNum, final long blockNum) + throws IOException { + setup(parentBlockNum, blockNum); final long updatedNonce = blockHeader.getNonce() + 1; final BlockHeader header = BlockHeaderBuilder.fromHeader(blockHeader) @@ -141,8 +151,11 @@ public void failsWithMisMatchedNonce() { assertThat(validationRule.validate(header, parentHeader)).isFalse(); } - @Test - public void failsWithNonEip1559BlockAfterFork() { + @ParameterizedTest(name = "block {1}") + @MethodSource("data") + public void failsWithNonEip1559BlockAfterFork(final long parentBlockNum, final long blockNum) + throws IOException { + setup(parentBlockNum, blockNum); final ProofOfWorkValidationRule proofOfWorkValidationRule = new ProofOfWorkValidationRule( new EpochCalculator.DefaultEpochCalculator(), @@ -169,8 +182,11 @@ public void failsWithNonEip1559BlockAfterFork() { assertThat(proofOfWorkValidationRule.validate(header, parentHeader)).isFalse(); } - @Test - public void failsWithEip1559BlockBeforeFork() { + @ParameterizedTest(name = "block {1}") + @MethodSource("data") + public void failsWithEip1559BlockBeforeFork(final long parentBlockNum, final long blockNum) + throws IOException { + setup(parentBlockNum, blockNum); final ProofOfWorkValidationRule proofOfWorkValidationRule = new ProofOfWorkValidationRule( new EpochCalculator.DefaultEpochCalculator(), PoWHasher.ETHASH_LIGHT); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/TimestampValidationRuleTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/TimestampValidationRuleTest.java index 07380018b30..24dc4987afe 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/TimestampValidationRuleTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/TimestampValidationRuleTest.java @@ -22,7 +22,7 @@ import java.util.concurrent.TimeUnit; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class TimestampValidationRuleTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/FlexiblePrivacyPrecompiledContractTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/FlexiblePrivacyPrecompiledContractTest.java index 3f4e650c81a..83e1858f86c 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/FlexiblePrivacyPrecompiledContractTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/FlexiblePrivacyPrecompiledContractTest.java @@ -64,16 +64,12 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; public class FlexiblePrivacyPrecompiledContractTest { - @Rule public final TemporaryFolder temp = new TemporaryFolder(); - private final Bytes privateTransactionLookupId = Bytes.random(32); private final Bytes privateTransactionLookupId64 = Bytes.random(64); private MessageFrame messageFrame; @@ -106,7 +102,7 @@ private PrivateTransactionProcessor mockPrivateTxProcessor( return mockPrivateTransactionProcessor; } - @Before + @BeforeEach public void setUp() { final MutableWorldState mutableWorldState = mock(MutableWorldState.class); when(mutableWorldState.updater()).thenReturn(mock(WorldUpdater.class)); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPluginPrecompiledContractTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPluginPrecompiledContractTest.java index b8081492a58..d4816d6b015 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPluginPrecompiledContractTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPluginPrecompiledContractTest.java @@ -62,8 +62,8 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class PrivacyPluginPrecompiledContractTest { private final String DEFAULT_OUTPUT = "0x01"; @@ -72,7 +72,7 @@ public class PrivacyPluginPrecompiledContractTest { PrivacyPluginPrecompiledContract contract; - @Before + @BeforeEach public void setup() { messageFrame = mock(MessageFrame.class); @@ -121,7 +121,7 @@ public Bytes generateMarkerPayload( @Override public Optional getPrivateTransactionFromPayload( - final org.hyperledger.besu.plugin.data.Transaction transaction) { + final org.hyperledger.besu.datatypes.Transaction transaction) { final BytesValueRLPInput bytesValueRLPInput = new BytesValueRLPInput(transaction.getPayload(), false); return Optional.of(readFrom(bytesValueRLPInput)); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/ChainHeadPrivateNonceProviderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/ChainHeadPrivateNonceProviderTest.java index 870b0924e9d..c2916a94041 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/ChainHeadPrivateNonceProviderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/ChainHeadPrivateNonceProviderTest.java @@ -32,12 +32,12 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class ChainHeadPrivateNonceProviderTest { private static final Bytes32 PRIVACY_GROUP_ID = Bytes32.wrap(Bytes.fromBase64String("DyAOiF/ynpc+JXa2YAGB0bCitSlOMNm+ShmB/7M6C4w=")); @@ -49,7 +49,7 @@ public class ChainHeadPrivateNonceProviderTest { private WorldStateArchive privateWorldStateArchive; private PrivateStateRootResolver privateStateRootResolver; - @Before + @BeforeEach public void setUp() { final BlockDataGenerator gen = new BlockDataGenerator(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/FlexiblePrivacyControllerTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/FlexiblePrivacyControllerTest.java index 3e94052334c..b6811ffd891 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/FlexiblePrivacyControllerTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/FlexiblePrivacyControllerTest.java @@ -69,12 +69,15 @@ import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.io.Base64; import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class FlexiblePrivacyControllerTest { private static final String ADDRESS1 = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; @@ -118,7 +121,7 @@ public class FlexiblePrivacyControllerTest { new BigInteger( "8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", 16))); - @Before + @BeforeEach public void setUp() throws Exception { blockchain = mock(Blockchain.class); privateTransactionSimulator = mock(PrivateTransactionSimulator.class); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/FlexibleUtilTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/FlexibleUtilTest.java index 64d074c7e5d..f4247c7c6d2 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/FlexibleUtilTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/FlexibleUtilTest.java @@ -20,11 +20,11 @@ import java.util.List; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class FlexibleUtilTest { private static final String EXPECTED_EC_PARTICIPANT_1 = diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/MultiTenancyPrivacyControllerOnchainTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/MultiTenancyPrivacyControllerOnchainTest.java index 012da9c3508..76a0ed7e152 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/MultiTenancyPrivacyControllerOnchainTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/MultiTenancyPrivacyControllerOnchainTest.java @@ -32,12 +32,12 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class MultiTenancyPrivacyControllerOnchainTest { private static final String ENCLAVE_PUBLIC_KEY1 = "Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs="; @@ -49,7 +49,7 @@ public class MultiTenancyPrivacyControllerOnchainTest { private MultiTenancyPrivacyController multiTenancyPrivacyController; - @Before + @BeforeEach public void setup() { multiTenancyPrivacyController = new MultiTenancyPrivacyController(privacyController); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/MultiTenancyPrivacyControllerTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/MultiTenancyPrivacyControllerTest.java index 3909501556d..67bb95c2a3a 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/MultiTenancyPrivacyControllerTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/MultiTenancyPrivacyControllerTest.java @@ -37,13 +37,13 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class MultiTenancyPrivacyControllerTest { private static final String ENCLAVE_PUBLIC_KEY1 = "Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs="; @@ -58,7 +58,7 @@ public class MultiTenancyPrivacyControllerTest { private MultiTenancyPrivacyController multiTenancyPrivacyController; - @Before + @BeforeEach public void setup() { multiTenancyPrivacyController = new MultiTenancyPrivacyController(privacyController); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivacyGroupUtilTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivacyGroupUtilTest.java index f9085212569..8f8d306bce7 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivacyGroupUtilTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivacyGroupUtilTest.java @@ -20,7 +20,7 @@ import java.util.stream.Collectors; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PrivacyGroupUtilTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateMetadataUpdaterTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateMetadataUpdaterTest.java index 8f2d9340a1d..8c93bfd7f02 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateMetadataUpdaterTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateMetadataUpdaterTest.java @@ -30,12 +30,12 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PrivateMetadataUpdaterTest { private PrivateMetadataUpdater updater; @@ -46,7 +46,7 @@ public class PrivateMetadataUpdaterTest { private Hash stateRoot; private Hash pmtHash; - @Before + @BeforeEach public void before() { blockHeader = mock(BlockHeader.class); privateStateStorage = new InMemoryPrivacyStorageProvider().createPrivateStateStorage(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateStateGenesisAllocatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateStateGenesisAllocatorTest.java index d44be21cddf..e53244ef6d8 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateStateGenesisAllocatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateStateGenesisAllocatorTest.java @@ -39,7 +39,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PrivateStateGenesisAllocatorTest { public static final Hash EMPTY_ROOT_HASH = Hash.wrap(MerkleTrie.EMPTY_TRIE_NODE_HASH); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateStateRootResolverTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateStateRootResolverTest.java index 3428d74f04c..e3811ca9d0f 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateStateRootResolverTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateStateRootResolverTest.java @@ -33,9 +33,9 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class PrivateStateRootResolverTest { @@ -53,7 +53,7 @@ public class PrivateStateRootResolverTest { private PrivateStateStorage privateStateStorage; - @BeforeClass + @BeforeAll public static void setupClass() { BLOCKCHAIN = InMemoryKeyValueStorageProvider.createInMemoryBlockchain(BLOCK_GENERATOR.genesisBlock()); @@ -68,7 +68,7 @@ public static void setupClass() { } } - @Before + @BeforeEach public void setUp() { privateStateStorage = InMemoryKeyValueStorageProvider.createInMemoryPrivateStateStorage(); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionLocatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionLocatorTest.java index 246325806e8..31ca945549e 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionLocatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionLocatorTest.java @@ -43,13 +43,16 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class PrivateTransactionLocatorTest { private final String participantKey = "R24z0/bq4uTz0x1JxjdyRwfydh8Gi0L4oYYR0XpKdmc="; @@ -60,7 +63,7 @@ public class PrivateTransactionLocatorTest { private PrivateTransactionLocator locator; - @Before + @BeforeEach public void before() { locator = new PrivateTransactionLocator(blockchain, enclave, privateStateStorage); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionTest.java index 78b0dc8e935..7496311526c 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionTest.java @@ -34,7 +34,7 @@ import com.google.common.base.Suppliers; import com.google.common.collect.Lists; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PrivateTransactionTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionValidatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionValidatorTest.java index eefd11e5724..c7c52ae49a0 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionValidatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionValidatorTest.java @@ -33,13 +33,13 @@ import java.math.BigInteger; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PrivateTransactionValidatorTest { private static final KeyPair senderKeys = @@ -47,7 +47,7 @@ public class PrivateTransactionValidatorTest { private PrivateTransactionValidator validator; - @Before + @BeforeEach public void before() { validator = new PrivateTransactionValidator(Optional.empty()); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateWorldStateReaderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateWorldStateReaderTest.java index 475ddb33c9c..acc5313cd84 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateWorldStateReaderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateWorldStateReaderTest.java @@ -36,15 +36,18 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class PrivateWorldStateReaderTest { private final String PRIVACY_GROUP_ID = "B1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; @@ -63,14 +66,14 @@ public class PrivateWorldStateReaderTest { private PrivateWorldStateReader privateWorldStateReader; - @Before + @BeforeEach public void before() { privateWorldStateReader = new PrivateWorldStateReader( privateStateRootResolver, privateWorldStateArchive, privateStateStorage); } - @After + @AfterEach public void after() { Mockito.reset(privateStateStorage); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/RestrictedDefaultPrivacyControllerTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/RestrictedDefaultPrivacyControllerTest.java index a793d0b139f..6edb51cceca 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/RestrictedDefaultPrivacyControllerTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/RestrictedDefaultPrivacyControllerTest.java @@ -56,12 +56,15 @@ import com.google.common.base.Suppliers; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.io.Base64; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class RestrictedDefaultPrivacyControllerTest { private static final Supplier SIGNATURE_ALGORITHM = @@ -113,7 +116,7 @@ private PrivateTransactionValidator mockPrivateTransactionValidator() { return validator; } - @Before + @BeforeEach public void setUp() throws Exception { blockchain = mock(Blockchain.class); privateTransactionSimulator = mock(PrivateTransactionSimulator.class); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/markertransaction/FixedKeySigningPrivateMarkerTransactionFactoryTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/markertransaction/FixedKeySigningPrivateMarkerTransactionFactoryTest.java index 48c6e33bbb8..a056c3df14e 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/markertransaction/FixedKeySigningPrivateMarkerTransactionFactoryTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/markertransaction/FixedKeySigningPrivateMarkerTransactionFactoryTest.java @@ -20,20 +20,20 @@ import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Util; import org.hyperledger.besu.ethereum.privacy.PrivateTransaction; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class FixedKeySigningPrivateMarkerTransactionFactoryTest { @Test diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/markertransaction/RandomSigningPrivateMarkerTransactionFactoryTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/markertransaction/RandomSigningPrivateMarkerTransactionFactoryTest.java index 7eeea0ed6ea..83506e8d690 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/markertransaction/RandomSigningPrivateMarkerTransactionFactoryTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/markertransaction/RandomSigningPrivateMarkerTransactionFactoryTest.java @@ -18,19 +18,19 @@ import static org.mockito.Mockito.mock; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.privacy.PrivateTransaction; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class RandomSigningPrivateMarkerTransactionFactoryTest { @Test diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/storage/PrivateStateKeyValueStorageTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/storage/PrivateStateKeyValueStorageTest.java index ce7fdd12311..ff6e379d2c8 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/storage/PrivateStateKeyValueStorageTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/storage/PrivateStateKeyValueStorageTest.java @@ -20,14 +20,14 @@ import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class PrivateStateKeyValueStorageTest { private PrivateStateKeyValueStorage storage; - @Before + @BeforeEach public void before() { storage = new PrivateStateKeyValueStorage(new InMemoryKeyValueStorage()); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateStorageMigrationTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateStorageMigrationTest.java index b17bcddab72..5279a06de1d 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateStorageMigrationTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateStorageMigrationTest.java @@ -31,6 +31,7 @@ import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Block; @@ -51,7 +52,6 @@ import org.hyperledger.besu.ethereum.privacy.storage.PrivateStateStorage; import org.hyperledger.besu.ethereum.privacy.storage.PrivateTransactionMetadata; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; @@ -64,14 +64,17 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) @SuppressWarnings({"unchecked", "rawtypes"}) public class PrivateStorageMigrationTest { @@ -95,7 +98,7 @@ public class PrivateStorageMigrationTest { private PrivateStateRootResolver privateStateRootResolver; private PrivateStorageMigration migration; - @Before + @BeforeEach public void setUp() { final KeyValueStorage kvStorage = new InMemoryKeyValueStorage(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/proof/WorldStateProofProviderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/proof/WorldStateProofProviderTest.java index a6269f9bb24..b6357954f53 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/proof/WorldStateProofProviderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/proof/WorldStateProofProviderTest.java @@ -36,12 +36,12 @@ import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256; import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class WorldStateProofProviderTest { private static final Address address = @@ -52,7 +52,7 @@ public class WorldStateProofProviderTest { private WorldStateProofProvider worldStateProofProvider; - @Before + @BeforeEach public void setup() { worldStateProofProvider = new WorldStateProofProvider(worldStateStorage); } @@ -67,7 +67,7 @@ public void getProofWhenWorldStateNotAvailable() { @Test public void getProofWhenWorldStateAvailable() { - final Hash addressHash = Hash.hash(address); + final Hash addressHash = address.addressHash(); final MerkleTrie worldStateTrie = emptyWorldStateTrie(addressHash); final MerkleTrie storageTrie = emptyStorageTrie(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/proof/WorldStateRangeProofProviderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/proof/WorldStateRangeProofProviderTest.java index e09e041b354..bd4d95321a7 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/proof/WorldStateRangeProofProviderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/proof/WorldStateRangeProofProviderTest.java @@ -33,8 +33,8 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class WorldStateRangeProofProviderTest { @@ -46,7 +46,7 @@ public class WorldStateRangeProofProviderTest { private static WorldStateProofProvider worldStateProofProvider; - @Before + @BeforeEach public void setup() { worldStateProofProvider = new WorldStateProofProvider(worldStateStorage); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueStorageWorldStateStorageTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueStorageWorldStateStorageTest.java index 994964b2982..758866fd6ff 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueStorageWorldStateStorageTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueStorageWorldStateStorageTest.java @@ -23,7 +23,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class KeyValueStorageWorldStateStorageTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorResultTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorResultTest.java index 8bec27c06e1..a8f18a76831 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorResultTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorResultTest.java @@ -21,13 +21,13 @@ import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class TransactionSimulatorResultTest { private TransactionSimulatorResult transactionSimulatorResult; @@ -35,7 +35,7 @@ public class TransactionSimulatorResultTest { @Mock private Transaction transaction; @Mock private TransactionProcessingResult result; - @Before + @BeforeEach public void before() { this.transactionSimulatorResult = new TransactionSimulatorResult(transaction, result); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java index 5f955441d2b..2b523beacb6 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java @@ -27,6 +27,7 @@ import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -46,7 +47,6 @@ import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import org.hyperledger.besu.plugin.data.TransactionType; import java.math.BigInteger; import java.util.Optional; @@ -54,13 +54,16 @@ import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) @SuppressWarnings({"rawtypes", "unchecked"}) public class TransactionSimulatorTest { @@ -84,7 +87,7 @@ public class TransactionSimulatorTest { private final BlockHeaderTestFixture blockHeaderTestFixture = new BlockHeaderTestFixture(); - @Before + @BeforeEach public void setUp() { this.transactionSimulator = new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/util/BlockchainUtilParameterizedTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/util/BlockchainUtilParameterizedTest.java index 742469b0840..e4f57803092 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/util/BlockchainUtilParameterizedTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/util/BlockchainUtilParameterizedTest.java @@ -26,25 +26,22 @@ import org.hyperledger.besu.ethereum.core.TransactionReceipt; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.OptionalInt; import java.util.Random; +import java.util.stream.Stream; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public class BlockchainUtilParameterizedTest { private static final BlockDataGenerator blockDataGenerator = new BlockDataGenerator(); private static final Random random = new Random(1337); private static final int chainHeight = 89; - private final int commonAncestorHeight; private static Block genesisBlock; private static MutableBlockchain localBlockchain; @@ -53,11 +50,7 @@ public class BlockchainUtilParameterizedTest { private BlockHeader commonHeader; private List headers; - public BlockchainUtilParameterizedTest(final int commonAncestorHeight) { - this.commonAncestorHeight = commonAncestorHeight; - } - - @BeforeClass + @BeforeAll public static void setupClass() { genesisBlock = blockDataGenerator.genesisBlock(); localBlockchain = InMemoryKeyValueStorageProvider.createInMemoryBlockchain(genesisBlock); @@ -73,8 +66,7 @@ public static void setupClass() { } } - @Before - public void setup() { + public void setup(final int commonAncestorHeight) { remoteBlockchain = InMemoryKeyValueStorageProvider.createInMemoryBlockchain(genesisBlock); commonHeader = genesisBlock.getHeader(); @@ -110,26 +102,29 @@ public void setup() { } } - @Parameterized.Parameters(name = "commonAncestor={0}") - public static Collection parameters() { + public static Stream parameters() { final List params = new ArrayList<>(); params.add(new Object[] {0}); params.add(new Object[] {chainHeight}); params.add(new Object[] {random.nextInt(chainHeight - 1) + 1}); params.add(new Object[] {random.nextInt(chainHeight - 1) + 1}); params.add(new Object[] {random.nextInt(chainHeight - 1) + 1}); - return params; + return params.stream().map(Arguments::of); } - @Test - public void searchesAscending() { + @ParameterizedTest(name = "commonAncestor={0}") + @MethodSource("parameters") + public void searchesAscending(final int commonAncestorHeight) { + setup(commonAncestorHeight); final OptionalInt maybeAncestorNumber = BlockchainUtil.findHighestKnownBlockIndex(localBlockchain, headers, true); assertThat(maybeAncestorNumber.getAsInt()).isEqualTo(Math.toIntExact(commonHeader.getNumber())); } - @Test - public void searchesDescending() { + @ParameterizedTest(name = "commonAncestor={0}") + @MethodSource("parameters") + public void searchesDescending(final int commonAncestorHeight) { + setup(commonAncestorHeight); Collections.reverse(headers); final OptionalInt maybeAncestorNumber = BlockchainUtil.findHighestKnownBlockIndex(localBlockchain, headers, false); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/util/RawBlockIteratorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/util/RawBlockIteratorTest.java index 91b5d023c29..7581fe7f75e 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/util/RawBlockIteratorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/util/RawBlockIteratorTest.java @@ -28,20 +28,20 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.nio.file.Path; import java.util.List; import java.util.function.Function; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; public class RawBlockIteratorTest { - @Rule public final TemporaryFolder tmp = new TemporaryFolder(); + @TempDir private static Path tmp; private BlockDataGenerator gen; - @Before + @BeforeEach public void setup() { gen = new BlockDataGenerator(1); } @@ -68,7 +68,7 @@ public void readsBlocksWithInitialCapacity( // Write a few blocks to a tmp file byte[] firstSerializedBlock = null; - final File blocksFile = tmp.newFolder().toPath().resolve("blocks").toFile(); + final File blocksFile = tmp.resolve("blocks").toFile(); final DataOutputStream writer = new DataOutputStream(new FileOutputStream(blocksFile)); for (Block block : blocks) { final byte[] serializedBlock = serializeBlock(block); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/AbstractRetryingTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/AbstractRetryingTest.java index bbb7eb4c590..690cedfa6bb 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/AbstractRetryingTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/AbstractRetryingTest.java @@ -16,8 +16,8 @@ import org.hyperledger.besu.util.LogConfigurator; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * This class can be used to extend tests. It allows to rerun tests with trace tests enabled @@ -38,7 +38,7 @@ public abstract class AbstractRetryingTest { private static final String originalRootLogLevel = System.getProperty("root.log.level"); /** Sets the logging system back to the original parameters with which the tests were launched. */ - @Before + @BeforeEach public void resetLoggingToOriginalConfiguration() { if (originalRootLogLevel == null) { System.clearProperty("root.log.level"); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/AddressTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/AddressTest.java index b496bb5f6ce..cb2686ad94d 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/AddressTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/AddressTest.java @@ -20,7 +20,7 @@ import org.hyperledger.besu.datatypes.Address; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class AddressTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/CachingBlockHashLookupTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/CachingBlockHashLookupTest.java index 0be54cc6389..194009e7057 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/CachingBlockHashLookupTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/CachingBlockHashLookupTest.java @@ -30,13 +30,13 @@ import java.util.Optional; import org.assertj.core.api.Assertions; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class CachingBlockHashLookupTest { private static final int CURRENT_BLOCK_NUMBER = 256; @@ -44,7 +44,7 @@ public class CachingBlockHashLookupTest { private final BlockHeader[] headers = new BlockHeader[CURRENT_BLOCK_NUMBER]; private BlockHashLookup lookup; - @Before + @BeforeEach public void setUp() { BlockHeader parentHeader = null; for (int i = 0; i < headers.length; i++) { @@ -58,7 +58,7 @@ public void setUp() { createHeader(CURRENT_BLOCK_NUMBER, headers[headers.length - 1]), blockchain); } - @After + @AfterEach public void verifyBlocksNeverLookedUpByNumber() { // Looking up the block by number is incorrect because it always uses the canonical chain even // if the block being imported is on a fork. diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracerTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracerTest.java index 2a8516c3c9c..48fe26af187 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracerTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracerTest.java @@ -41,12 +41,12 @@ import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256; import org.assertj.core.api.Assertions; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class DebugOperationTracerTest { private static final int DEPTH = 4; @@ -83,6 +83,11 @@ public void shouldRecordOpcode() { @Test public void shouldRecordDepth() { final MessageFrame frame = validMessageFrame(); + // simulate 4 calls + frame.getMessageFrameStack().add(frame); + frame.getMessageFrameStack().add(frame); + frame.getMessageFrameStack().add(frame); + frame.getMessageFrameStack().add(frame); final TraceFrame traceFrame = traceFrame(frame); assertThat(traceFrame.getDepth()).isEqualTo(DEPTH); } @@ -201,8 +206,7 @@ private MessageFrameTestFixture validMessageFrameBuilder() { .worldUpdater(worldUpdater) .gasPrice(Wei.of(25)) .blockHeader(blockHeader) - .blockchain(blockchain) - .depth(DEPTH); + .blockchain(blockchain); } private Map setupStorageForCapture(final MessageFrame frame) { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/EstimateGasOperationTracerTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/EstimateGasOperationTracerTest.java index 5f87706c5cc..db931d9585c 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/EstimateGasOperationTracerTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/EstimateGasOperationTracerTest.java @@ -25,18 +25,18 @@ import org.hyperledger.besu.evm.operation.SStoreOperation; import org.hyperledger.besu.evm.tracing.EstimateGasOperationTracer; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class EstimateGasOperationTracerTest { private EstimateGasOperationTracer operationTracer; private MessageFrameTestFixture messageFrameTestFixture; - @Before + @BeforeEach public void setUp() { operationTracer = new EstimateGasOperationTracer(); messageFrameTestFixture = new MessageFrameTestFixture(); @@ -49,23 +49,26 @@ public void shouldDetectChangeInDepthDuringExecution() { assertThat(operationTracer.getMaxDepth()).isZero(); - final MessageFrame firstFrame = messageFrameTestFixture.depth(0).build(); + final MessageFrame firstFrame = messageFrameTestFixture.build(); operationTracer.tracePostExecution(firstFrame, testResult); assertThat(operationTracer.getMaxDepth()).isZero(); - final MessageFrame secondFrame = messageFrameTestFixture.depth(1).build(); + final MessageFrame secondFrame = messageFrameTestFixture.parentFrame(firstFrame).build(); operationTracer.tracePostExecution(secondFrame, testResult); assertThat(operationTracer.getMaxDepth()).isEqualTo(1); + firstFrame.getMessageFrameStack().removeFirst(); - final MessageFrame thirdFrame = messageFrameTestFixture.depth(1).build(); + final MessageFrame thirdFrame = messageFrameTestFixture.parentFrame(firstFrame).build(); operationTracer.tracePostExecution(thirdFrame, testResult); assertThat(operationTracer.getMaxDepth()).isEqualTo(1); - final MessageFrame fourthFrame = messageFrameTestFixture.depth(2).build(); + final MessageFrame fourthFrame = messageFrameTestFixture.parentFrame(thirdFrame).build(); operationTracer.tracePostExecution(fourthFrame, testResult); assertThat(operationTracer.getMaxDepth()).isEqualTo(2); + firstFrame.getMessageFrameStack().removeFirst(); + firstFrame.getMessageFrameStack().removeFirst(); - final MessageFrame fifthFrame = messageFrameTestFixture.depth(0).build(); + final MessageFrame fifthFrame = messageFrameTestFixture.build(); operationTracer.tracePostExecution(fifthFrame, testResult); assertThat(operationTracer.getMaxDepth()).isEqualTo(2); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/MemoryTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/MemoryTest.java index a8aeec62ab5..ab254a3b0c7 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/MemoryTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/MemoryTest.java @@ -20,7 +20,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class MemoryTest { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutableWorldStateTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutableWorldStateTest.java index d69beaa7951..7f910364511 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutableWorldStateTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutableWorldStateTest.java @@ -42,7 +42,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.Test; +import org.junit.jupiter.api.Test; // TODO: make that an abstract mutable world state test, and create sub-class for all world state // implementations. diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/MarkSweepPrunerTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/MarkSweepPrunerTest.java index 107a74be968..c91ea5dcb08 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/MarkSweepPrunerTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/MarkSweepPrunerTest.java @@ -49,12 +49,12 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InOrder; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class MarkSweepPrunerTest { private final BlockDataGenerator gen = new BlockDataGenerator(); @@ -146,8 +146,10 @@ public void sweepBefore_shouldSweepStateRootFirst() { // the full prune but without enforcing an ordering between the state root removals stateRoots.forEach( stateRoot -> { - final InOrder thisRootsOrdering = inOrder(hashValueStore, worldStateStorage); - thisRootsOrdering.verify(hashValueStore).remove(stateRoot); + final InOrder thisRootsOrdering = + inOrder(worldStateStorage, hashValueStore, worldStateStorage); + thisRootsOrdering.verify(worldStateStorage).isWorldStateAvailable(stateRoot, null); + thisRootsOrdering.verify(hashValueStore).keySet(); thisRootsOrdering.verify(worldStateStorage).prune(any()); }); } @@ -183,8 +185,10 @@ public void sweepBefore_shouldNotRemoveMarkedStateRoots() { // the full prune but without enforcing an ordering between the state root removals stateRoots.forEach( stateRoot -> { - final InOrder thisRootsOrdering = inOrder(hashValueStore, worldStateStorage); - thisRootsOrdering.verify(hashValueStore).remove(stateRoot); + final InOrder thisRootsOrdering = + inOrder(worldStateStorage, hashValueStore, worldStateStorage); + thisRootsOrdering.verify(worldStateStorage).isWorldStateAvailable(stateRoot, null); + thisRootsOrdering.verify(hashValueStore).keySet(); thisRootsOrdering.verify(worldStateStorage).prune(any()); }); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/PrunerTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/PrunerTest.java index fa90bf6a8e2..8f1b34bccac 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/PrunerTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/PrunerTest.java @@ -40,12 +40,12 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PrunerTest { private final NoOpMetricsSystem metricsSystem = new NoOpMetricsSystem(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/StateTrieAccountValueTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/StateTrieAccountValueTest.java index 4ffc499f0d3..5ce385570c3 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/StateTrieAccountValueTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/StateTrieAccountValueTest.java @@ -22,7 +22,7 @@ import org.hyperledger.besu.ethereum.rlp.RLPInput; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class StateTrieAccountValueTest { diff --git a/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/chain/genesis_cancun.json b/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/chain/genesis_cancun.json new file mode 100644 index 00000000000..61267b122c9 --- /dev/null +++ b/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/chain/genesis_cancun.json @@ -0,0 +1,4076 @@ +{ + "config": { + "ethash": {}, + "chainID": 7, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "constantinopleFixBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "parisBlock": 0, + "terminalTotalDifficulty": 0, + "shanghaiTime": 0, + "cancunTime": 4660 + }, + "nonce": "0x0", + "timestamp": "0x1234", + "extraData": "0x", + "gasLimit": "0x2fefd8", + "difficulty": "0x0", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "0000000000000000000000000000000000000100": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000101": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000102": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000103": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000104": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000105": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000106": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000107": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000108": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000109": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000010a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000010b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000010c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000010d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000010e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000010f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000110": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000111": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000112": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000113": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000114": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000115": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000116": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000117": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000118": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000119": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000011a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000011b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000011c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000011d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000011e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000011f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000120": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000121": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000122": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000123": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000124": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000125": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000126": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000127": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000128": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000129": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000012a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000012b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000012c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000012d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000012e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000012f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000130": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000131": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000132": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000133": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000134": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000135": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000136": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000137": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000138": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000139": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000013a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000013b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000013c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000013d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000013e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000013f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000140": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000141": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000142": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000143": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000144": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000145": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000146": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000147": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000148": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000149": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000014a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000014b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000014c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000014d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000014e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000014f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000150": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000151": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000152": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000153": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000154": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000155": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000156": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000157": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000158": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000159": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000015a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000015b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000015c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000015d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000015e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000015f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000160": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000161": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000162": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000163": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000164": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000165": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000166": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000167": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000168": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000169": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000016a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000016b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000016c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000016d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000016e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000016f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000170": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000171": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000172": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000173": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000174": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000175": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000176": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000177": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000178": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000179": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000017a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000017b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000017c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000017d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000017e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000017f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000180": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000181": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000182": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000183": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000184": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000185": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000186": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000187": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000188": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000189": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000018a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000018b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000018c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000018d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000018e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000018f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000190": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000191": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000192": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000193": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000194": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000195": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000196": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000197": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000198": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000199": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000019a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000019b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000019c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000019d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000019e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000019f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001aa": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ab": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ac": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ad": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ae": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001af": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ba": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001bb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001bc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001bd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001be": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001bf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ca": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001cb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001cc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001cd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ce": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001cf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001da": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001db": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001dc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001dd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001de": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001df": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ea": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001eb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ec": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ed": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ee": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ef": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001fa": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001fb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001fc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001fd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001fe": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ff": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000200": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000201": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000202": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000203": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000204": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000205": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000206": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000207": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000208": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000209": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000020a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000020b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000020c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000020d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000020e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000020f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000210": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000211": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000212": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000213": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000214": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000215": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000216": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000217": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000218": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000219": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000021a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000021b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000021c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000021d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000021e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000021f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000220": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000221": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000222": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000223": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000224": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000225": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000226": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000227": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000228": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000229": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000022a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000022b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000022c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000022d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000022e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000022f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000230": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000231": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000232": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000233": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000234": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000235": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000236": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000237": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000238": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000239": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000023a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000023b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000023c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000023d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000023e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000023f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000240": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000241": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000242": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000243": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000244": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000245": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000246": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000247": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000248": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000249": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000024a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000024b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000024c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000024d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000024e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000024f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000250": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000251": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000252": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000253": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000254": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000255": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000256": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000257": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000258": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000259": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000025a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000025b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000025c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000025d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000025e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000025f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000260": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000261": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000262": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000263": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000264": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000265": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000266": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000267": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000268": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000269": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000026a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000026b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000026c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000026d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000026e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000026f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000270": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000271": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000272": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000273": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000274": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000275": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000276": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000277": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000278": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000279": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000027a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000027b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000027c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000027d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000027e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000027f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000280": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000281": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000282": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000283": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000284": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000285": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000286": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000287": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000288": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000289": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000028a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000028b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000028c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000028d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000028e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000028f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000290": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000291": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000292": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000293": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000294": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000295": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000296": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000297": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000298": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000299": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000029a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000029b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000029c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000029d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000029e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000029f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002aa": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ab": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ac": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ad": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ae": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002af": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ba": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002bb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002bc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002bd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002be": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002bf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ca": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002cb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002cc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002cd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ce": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002cf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002da": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002db": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002dc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002dd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002de": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002df": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ea": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002eb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ec": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ed": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ee": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ef": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002fa": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002fb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002fc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002fd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002fe": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ff": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000300": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000301": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000302": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000303": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000304": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000305": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000306": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000307": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000308": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000309": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000030a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000030b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000030c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000030d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000030e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000030f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000310": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000311": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000312": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000313": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000314": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000315": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000316": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000317": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000318": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000319": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000031a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000031b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000031c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000031d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000031e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000031f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000320": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000321": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000322": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000323": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000324": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000325": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000326": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000327": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000328": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000329": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000032a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000032b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000032c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000032d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000032e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000032f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000330": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000331": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000332": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000333": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000334": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000335": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000336": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000337": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000338": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000339": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000033a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000033b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000033c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000033d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000033e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000033f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000340": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000341": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000342": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000343": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000344": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000345": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000346": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000347": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000348": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000349": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000034a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000034b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000034c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000034d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000034e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000034f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000350": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000351": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000352": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000353": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000354": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000355": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000356": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000357": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000358": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000359": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000035a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000035b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000035c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000035d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000035e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000035f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000360": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000361": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000362": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000363": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000364": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000365": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000366": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000367": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000368": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000369": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000036a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000036b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000036c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000036d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000036e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000036f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000370": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000371": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000372": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000373": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000374": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000375": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000376": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000377": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000378": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000379": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000037a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000037b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000037c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000037d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000037e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000037f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000380": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000381": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000382": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000383": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000384": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000385": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000386": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000387": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000388": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000389": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000038a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000038b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000038c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000038d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000038e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000038f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000390": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000391": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000392": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000393": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000394": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000395": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000396": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000397": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000398": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000399": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000039a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000039b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000039c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000039d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000039e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000039f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003aa": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ab": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ac": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ad": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ae": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003af": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ba": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003bb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003bc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003bd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003be": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003bf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ca": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003cb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003cc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003cd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ce": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003cf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003da": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003db": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003dc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003dd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003de": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003df": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ea": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003eb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ec": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ed": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ee": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ef": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003fa": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003fb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003fc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003fd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003fe": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ff": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000400": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000401": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000402": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000403": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000404": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000405": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000406": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000407": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000408": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000409": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000040a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000040b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000040c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000040d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000040e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000040f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000410": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000411": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000412": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000413": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000414": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000415": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000416": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000417": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000418": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000419": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000041a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000041b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000041c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000041d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000041e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000041f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000420": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000421": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000422": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000423": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000424": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000425": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000426": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000427": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000428": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000429": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000042a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000042b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000042c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000042d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000042e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000042f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000430": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000431": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000432": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000433": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000434": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000435": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000436": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000437": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000438": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000439": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000043a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000043b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000043c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000043d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000043e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000043f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000440": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000441": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000442": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000443": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000444": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000445": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000446": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000447": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000448": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000449": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000044a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000044b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000044c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000044d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000044e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000044f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000450": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000451": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000452": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000453": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000454": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000455": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000456": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000457": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000458": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000459": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000045a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000045b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000045c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000045d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000045e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000045f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000460": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000461": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000462": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000463": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000464": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000465": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000466": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000467": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000468": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000469": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000046a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000046b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000046c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000046d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000046e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000046f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000470": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000471": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000472": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000473": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000474": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000475": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000476": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000477": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000478": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000479": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000047a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000047b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000047c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000047d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000047e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000047f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000480": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000481": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000482": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000483": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000484": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000485": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000486": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000487": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000488": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000489": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000048a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000048b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000048c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000048d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000048e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000048f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000490": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000491": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000492": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000493": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000494": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000495": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000496": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000497": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000498": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000499": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000049a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000049b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000049c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000049d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000049e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000049f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004aa": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004ab": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004ac": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004ad": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004ae": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004af": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004ba": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004bb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004bc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004bd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004be": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004bf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004ca": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004cb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004cc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004cd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004ce": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004cf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004da": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004db": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004dc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004dd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004de": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004df": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0161e041aad467a890839d5b08b138c1e6373072": { + "balance": "0x123450000000000000000" + }, + "0f830fc93e76c8d26ed1f65045e70f5f986da383": { + "balance": "0x123450000000000000000" + }, + "2180290b54d5d9e38f85fdaf086bfe35b610f404": { + "balance": "0x123450000000000000000" + }, + "763fc7d39ab4cfa496c39077542589819aea5c54": { + "balance": "0x123450000000000000000" + }, + "87da6a8c6e9eff15d703fc2773e32f6af8dbe301": { + "balance": "0x123450000000000000000" + }, + "9c09de85a373dc3486115cab94c72549029f1103": { + "balance": "0x123450000000000000000" + }, + "9d2f18c852eb5b37292dfc9f68ac5ecbf0d22dd2": { + "balance": "0x123450000000000000000" + }, + "a995b3ebccfb2b8e8b1db15b7ca8cf2f11ed0310": { + "balance": "0x123450000000000000000" + }, + "aa82d35d5eaec5cf87c311a3af844ed682d5a247": { + "balance": "0x123450000000000000000" + }, + "b76ae96839fe445670262bce61144e6cda9099b8": { + "balance": "0x123450000000000000000" + }, + "b97de4b8c857e4f6bc354f226dc3249aaee49209": { + "balance": "0x123450000000000000000" + }, + "c5065c9eeebe6df2c2284d046bfc906501846c51": { + "balance": "0x123450000000000000000" + }, + "cf49fda3be353c69b41ed96333cd24302da4556f": { + "balance": "0x123450000000000000000" + }, + "fb289e2b2b65fb63299a682d000744671c50417b": { + "balance": "0x123450000000000000000" + } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas": "0x3b9aca00" +} diff --git a/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/chain/genesis_shanghai.json b/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/chain/genesis_shanghai.json new file mode 100644 index 00000000000..77792d88df9 --- /dev/null +++ b/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/chain/genesis_shanghai.json @@ -0,0 +1,4076 @@ +{ + "config": { + "ethash": {}, + "chainID": 7, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "constantinopleFixBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "parisBlock": 0, + "terminalTotalDifficulty": 0, + "shanghaiTime": 0, + "cancunTime": 4661 + }, + "nonce": "0x0", + "timestamp": "0x1234", + "extraData": "0x", + "gasLimit": "0x2fefd8", + "difficulty": "0x0", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "0000000000000000000000000000000000000100": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000101": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000102": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000103": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000104": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000105": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000106": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000107": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000108": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000109": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000010a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000010b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000010c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000010d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000010e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000010f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000110": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000111": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000112": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000113": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000114": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000115": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000116": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000117": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000118": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000119": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000011a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000011b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000011c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000011d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000011e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000011f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000120": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000121": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000122": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000123": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000124": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000125": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000126": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000127": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000128": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000129": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000012a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000012b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000012c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000012d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000012e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000012f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000130": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000131": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000132": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000133": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000134": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000135": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000136": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000137": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000138": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000139": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000013a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000013b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000013c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000013d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000013e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000013f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000140": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000141": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000142": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000143": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000144": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000145": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000146": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000147": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000148": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000149": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000014a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000014b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000014c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000014d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000014e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000014f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000150": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000151": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000152": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000153": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000154": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000155": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000156": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000157": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000158": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000159": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000015a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000015b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000015c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000015d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000015e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000015f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000160": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000161": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000162": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000163": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000164": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000165": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000166": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000167": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000168": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000169": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000016a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000016b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000016c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000016d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000016e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000016f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000170": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000171": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000172": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000173": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000174": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000175": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000176": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000177": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000178": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000179": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000017a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000017b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000017c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000017d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000017e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000017f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000180": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000181": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000182": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000183": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000184": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000185": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000186": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000187": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000188": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000189": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000018a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000018b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000018c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000018d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000018e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000018f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000190": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000191": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000192": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000193": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000194": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000195": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000196": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000197": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000198": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000199": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000019a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000019b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000019c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000019d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000019e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000019f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001a9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001aa": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ab": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ac": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ad": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ae": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001af": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001b9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ba": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001bb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001bc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001bd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001be": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001bf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001c9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ca": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001cb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001cc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001cd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ce": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001cf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001d9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001da": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001db": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001dc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001dd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001de": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001df": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001e9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ea": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001eb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ec": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ed": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ee": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ef": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001f9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001fa": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001fb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001fc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001fd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001fe": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000001ff": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000200": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000201": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000202": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000203": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000204": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000205": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000206": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000207": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000208": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000209": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000020a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000020b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000020c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000020d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000020e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000020f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000210": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000211": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000212": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000213": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000214": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000215": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000216": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000217": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000218": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000219": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000021a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000021b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000021c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000021d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000021e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000021f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000220": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000221": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000222": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000223": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000224": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000225": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000226": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000227": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000228": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000229": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000022a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000022b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000022c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000022d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000022e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000022f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000230": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000231": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000232": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000233": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000234": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000235": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000236": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000237": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000238": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000239": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000023a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000023b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000023c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000023d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000023e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000023f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000240": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000241": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000242": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000243": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000244": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000245": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000246": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000247": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000248": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000249": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000024a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000024b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000024c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000024d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000024e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000024f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000250": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000251": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000252": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000253": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000254": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000255": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000256": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000257": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000258": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000259": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000025a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000025b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000025c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000025d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000025e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000025f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000260": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000261": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000262": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000263": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000264": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000265": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000266": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000267": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000268": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000269": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000026a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000026b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000026c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000026d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000026e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000026f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000270": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000271": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000272": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000273": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000274": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000275": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000276": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000277": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000278": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000279": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000027a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000027b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000027c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000027d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000027e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000027f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000280": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000281": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000282": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000283": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000284": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000285": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000286": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000287": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000288": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000289": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000028a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000028b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000028c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000028d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000028e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000028f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000290": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000291": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000292": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000293": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000294": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000295": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000296": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000297": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000298": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000299": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000029a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000029b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000029c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000029d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000029e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000029f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002a9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002aa": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ab": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ac": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ad": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ae": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002af": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002b9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ba": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002bb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002bc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002bd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002be": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002bf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002c9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ca": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002cb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002cc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002cd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ce": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002cf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002d9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002da": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002db": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002dc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002dd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002de": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002df": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002e9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ea": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002eb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ec": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ed": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ee": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ef": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002f9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002fa": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002fb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002fc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002fd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002fe": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000002ff": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000300": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000301": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000302": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000303": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000304": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000305": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000306": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000307": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000308": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000309": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000030a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000030b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000030c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000030d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000030e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000030f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000310": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000311": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000312": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000313": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000314": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000315": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000316": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000317": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000318": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000319": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000031a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000031b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000031c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000031d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000031e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000031f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000320": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000321": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000322": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000323": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000324": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000325": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000326": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000327": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000328": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000329": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000032a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000032b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000032c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000032d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000032e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000032f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000330": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000331": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000332": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000333": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000334": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000335": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000336": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000337": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000338": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000339": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000033a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000033b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000033c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000033d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000033e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000033f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000340": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000341": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000342": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000343": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000344": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000345": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000346": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000347": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000348": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000349": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000034a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000034b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000034c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000034d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000034e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000034f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000350": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000351": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000352": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000353": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000354": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000355": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000356": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000357": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000358": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000359": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000035a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000035b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000035c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000035d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000035e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000035f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000360": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000361": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000362": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000363": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000364": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000365": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000366": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000367": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000368": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000369": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000036a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000036b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000036c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000036d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000036e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000036f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000370": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000371": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000372": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000373": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000374": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000375": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000376": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000377": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000378": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000379": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000037a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000037b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000037c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000037d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000037e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000037f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000380": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000381": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000382": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000383": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000384": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000385": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000386": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000387": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000388": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000389": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000038a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000038b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000038c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000038d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000038e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000038f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000390": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000391": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000392": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000393": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000394": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000395": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000396": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000397": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000398": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000399": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000039a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000039b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000039c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000039d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000039e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000039f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003a9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003aa": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ab": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ac": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ad": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ae": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003af": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003b9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ba": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003bb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003bc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003bd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003be": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003bf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003c9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ca": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003cb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003cc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003cd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ce": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003cf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003d9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003da": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003db": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003dc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003dd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003de": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003df": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003e9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ea": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003eb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ec": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ed": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ee": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ef": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003f9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003fa": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003fb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003fc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003fd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003fe": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000003ff": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000400": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000401": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000402": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000403": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000404": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000405": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000406": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000407": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000408": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000409": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000040a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000040b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000040c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000040d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000040e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000040f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000410": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000411": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000412": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000413": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000414": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000415": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000416": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000417": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000418": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000419": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000041a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000041b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000041c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000041d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000041e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000041f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000420": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000421": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000422": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000423": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000424": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000425": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000426": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000427": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000428": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000429": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000042a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000042b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000042c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000042d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000042e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000042f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000430": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000431": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000432": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000433": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000434": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000435": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000436": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000437": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000438": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000439": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000043a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000043b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000043c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000043d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000043e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000043f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000440": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000441": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000442": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000443": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000444": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000445": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000446": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000447": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000448": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000449": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000044a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000044b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000044c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000044d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000044e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000044f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000450": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000451": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000452": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000453": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000454": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000455": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000456": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000457": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000458": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000459": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000045a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000045b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000045c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000045d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000045e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000045f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000460": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000461": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000462": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000463": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000464": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000465": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000466": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000467": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000468": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000469": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000046a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000046b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000046c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000046d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000046e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000046f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000470": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000471": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000472": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000473": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000474": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000475": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000476": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000477": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000478": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000479": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000047a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000047b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000047c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000047d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000047e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000047f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000480": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000481": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000482": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000483": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000484": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000485": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000486": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000487": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000488": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000489": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000048a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000048b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000048c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000048d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000048e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000048f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000490": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000491": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000492": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000493": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000494": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000495": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000496": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000497": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000498": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0000000000000000000000000000000000000499": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000049a": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000049b": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000049c": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000049d": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000049e": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "000000000000000000000000000000000000049f": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004a9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004aa": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004ab": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004ac": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004ad": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004ae": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004af": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004b9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004ba": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004bb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004bc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004bd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004be": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004bf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004c9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004ca": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004cb": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004cc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004cd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004ce": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004cf": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d8": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004d9": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004da": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004db": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004dc": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004dd": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004de": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004df": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e0": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e1": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e2": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e3": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e4": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e5": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e6": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "00000000000000000000000000000000000004e7": { + "code": "0x5f804955600180495560028049556003804955", + "balance": "0x0" + }, + "0161e041aad467a890839d5b08b138c1e6373072": { + "balance": "0x123450000000000000000" + }, + "0f830fc93e76c8d26ed1f65045e70f5f986da383": { + "balance": "0x123450000000000000000" + }, + "2180290b54d5d9e38f85fdaf086bfe35b610f404": { + "balance": "0x123450000000000000000" + }, + "763fc7d39ab4cfa496c39077542589819aea5c54": { + "balance": "0x123450000000000000000" + }, + "87da6a8c6e9eff15d703fc2773e32f6af8dbe301": { + "balance": "0x123450000000000000000" + }, + "9c09de85a373dc3486115cab94c72549029f1103": { + "balance": "0x123450000000000000000" + }, + "9d2f18c852eb5b37292dfc9f68ac5ecbf0d22dd2": { + "balance": "0x123450000000000000000" + }, + "a995b3ebccfb2b8e8b1db15b7ca8cf2f11ed0310": { + "balance": "0x123450000000000000000" + }, + "aa82d35d5eaec5cf87c311a3af844ed682d5a247": { + "balance": "0x123450000000000000000" + }, + "b76ae96839fe445670262bce61144e6cda9099b8": { + "balance": "0x123450000000000000000" + }, + "b97de4b8c857e4f6bc354f226dc3249aaee49209": { + "balance": "0x123450000000000000000" + }, + "c5065c9eeebe6df2c2284d046bfc906501846c51": { + "balance": "0x123450000000000000000" + }, + "cf49fda3be353c69b41ed96333cd24302da4556f": { + "balance": "0x123450000000000000000" + }, + "fb289e2b2b65fb63299a682d000744671c50417b": { + "balance": "0x123450000000000000000" + } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas": "0x3b9aca00" +} diff --git a/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/core/encoding/BlobDataFixture.bin b/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/core/encoding/BlobDataFixture.bin new file mode 100644 index 00000000000..924a4338a2d --- /dev/null +++ b/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/core/encoding/BlobDataFixture.bin @@ -0,0 +1,3911 @@ +We're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say i t) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play i t +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let yo u down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt youWe're no strangers to love +You know the rules and so do I (do I) +A full commitmen t's what I'm thinking of +You wo uldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h urt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it (to say it) +Inside, we both know what's been going on (going on) +We know the game and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna le t you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodb ye +Never gonna tell a lie and h \ No newline at end of file diff --git a/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/core/encoding/blob1.txt b/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/core/encoding/blob1.txt new file mode 100644 index 00000000000..c20766e5314 --- /dev/null +++ b/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/core/encoding/blob1.txt @@ -0,0 +1 @@ +0x03fa0200fdf88f0780843b9aca008506fc23ac00830186a09400000000000000000000000000000000000001008080c001e1a0010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c44401401a0840650aa8f74d2b07f40067dc33b715078d73422f01da17abdbd11e02bbdfda9a04b2260f6022bf53eadb337b3e59514936f7317d872defb891a708ee279bdca90fa020004ba0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f1b0c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f1b0c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/core/encoding/blob_transactions_test_vectors.json b/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/core/encoding/blob_transactions_test_vectors.json new file mode 100644 index 00000000000..452c23fa2b9 --- /dev/null +++ b/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/core/encoding/blob_transactions_test_vectors.json @@ -0,0 +1,58 @@ +[ + { + "Input": { + "PrivateKey": "aa3a09289747a62b7b8190af3a75544cbe8c3b4a58f7b11d8d3b12ad17300a59", + "To": "0x45Ae5777c9b35Eb16280e423b0d7c91C06C66B58", + "Nonce": 1, + "Value": "1", + "GasLimit": 100000, + "GasPrice": "1000", + "PriorityGasPrice": "50", + "MaxFeePerBlobGas": "100", + "Data": "0x77918d0c4153776b" + }, + "RawEncodedTransaction": "0x033c00000076010000a6010000b0b4fa487696b3e1ab9de18f8e1d295e46b1048a68e18787145f5bc1e34faa6178b4018747674c3849fa7c1d38f2f07b4500000000935bdf0c90c47aaaf38ae7eed1380cfecea8c0a2cc5c93a4cbbba10976e306256a2f48215abc90b8edf7cdcfe226eb5841d86fa19cd4b5446dc075376fd59b0c330500000000000000000000000000000000000000000000000000000000000001000000000000003200000000000000000000000000000000000000000000000000000000000000e803000000000000000000000000000000000000000000000000000000000000a086010000000000c00000000100000000000000000000000000000000000000000000000000000000000000d5000000d50000006400000000000000000000000000000000000000000000000000000000000000d50000000145ae5777c9b35eb16280e423b0d7c91c06c66b5801f4af1847885b145b1a91f61c6c4dc13be1239debecf751101ee69c16f58904b8f1de4f6734fbcb617df946d87d8dd210440bb33ff8d84e86aa08660ee7beec27127438f5882f5f9b74fecef38c437c77918d0c4153776b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + { + "Input": { + "PrivateKey": "67f45650acc5dc426fc424348f8d9f07032c439f03797c4beba096a6e23e666b", + "To": "0x549A51956bd364D8bB2Efb1F1eA4436e8D7764Ff", + "Nonce": 2, + "Value": "1", + "GasLimit": 50000, + "GasPrice": "1234", + "PriorityGasPrice": "100", + "MaxFeePerBlobGas": "200", + "Data": "0x61f1628061be533586f64f50678a793e64a207a5df408217ed91c94f3c6f61bf6e2f6ff982b7ac3f300face1b52ae3fc68ee030fdc3150d73a056bd4df661059c6d1cb08ea2b39d0d49b0efaa75b8b61fb7f2b9caca6896aea156ed0304701796c517e2b010e387fefc702dabc6b4d2c732a173d33e0c272701e4f8668bad602" + }, + "RawEncodedTransaction": "0x033c00000076010000a6010000b6fabe6947368cfe7c5ac38eab67c0a3d5013848cb3b6600e0a0e205c1719577f5cd89b9e6c256ef9bc131d7550b9a2945000000002548c5fb3971907ef5a3ec7e092ff4abc602dfa5859805cba9ec3a725784f864954c50ef43cc745af6631688c6b819881eb3dab130cef3aee2bcb529f07de919330500000000000000000000000000000000000000000000000000000000000002000000000000006400000000000000000000000000000000000000000000000000000000000000d20400000000000000000000000000000000000000000000000000000000000050c3000000000000c00000000100000000000000000000000000000000000000000000000000000000000000d5000000d5000000c800000000000000000000000000000000000000000000000000000000000000d500000001549a51956bd364d8bb2efb1f1ea4436e8d7764ff015a6aa788d53d27bf35bafc1c45ff8734767eeeea3c334eacd3b759090f7937813e3a0cbc3a233eee92ccba94c8d76aa68c8a23257a81fa9aac7d0eabf89bb6ea484955196fc9a0ab07522ca3d50ab361f1628061be533586f64f50678a793e64a207a5df408217ed91c94f3c6f6100bf6e2f6ff982b7ac3f300face1b52ae3fc68ee030fdc3150d73a056bd4df66001059c6d1cb08ea2b39d0d49b0efaa75b8b61fb7f2b9caca6896aea156ed030004701796c517e2b010e387fefc702dabc6b4d2c732a173d33e0c272701e4f860068bad6020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + { + "Input": { + "PrivateKey": "2e2b5c749eab38b8eca6b788c70429580ffa8eb79ab9635b95af00c6f6cba661", + "To": "0xa39c4e1B259473fbcC5213a0613eB53a8C50bf76", + "Nonce": 3, + "Value": "1", + "GasLimit": 70000, + "GasPrice": "999", + "PriorityGasPrice": "10", + "MaxFeePerBlobGas": "20", + "Data": "0xa9fc4e91a83d0307d0aa69047208b24e15bd81098f9f580176ddf17604604b9259ddb3477cd87b6fd26d00615d65bb7e09597c1ea058e700a3da71696887edc6c0383f63e6a51b313afcf46f7159649cd4da51903c820aa577e93adc54cb62bd05a5d1bc8f9b4bcbf8de9670040106859f3c78b5f4d0e69804e743b905506f23503f720744f6a7e5ade176064fdc43803dcd6a12eda8d523fea35c4fe7e9537fa48f87c7b23f9f01e7ba0aa4f6688dbdb2646ec62d0156a1529121c702d00c73f27add8d238d04248a2c5b76e4b108116b2f9699523521586464b86dd4d6048c35719131dc4828ab8c95cb2aeb29fde8163f10994bfcffaf041250da0f2525a8" + }, + "RawEncodedTransaction": "0x033c00000076010000a6010000b9f0f8d300dd1026eaae3514ec7c5256da8d5cab3c2dad5de17b1d313d090d4a8e3c16a5a18958689c5bfc8d796469b2450000000022914d549bf0a6e1768dd8bd194398b90d3ff9e106e2eaf49ea4b6c3393bdc4e3095de1696ff03c6411f4253caaf8a67ddc6960621c62427c5175cbc4b54ba62330500000000000000000000000000000000000000000000000000000000000003000000000000000a00000000000000000000000000000000000000000000000000000000000000e7030000000000000000000000000000000000000000000000000000000000007011010000000000c00000000100000000000000000000000000000000000000000000000000000000000000d5000000d50000001400000000000000000000000000000000000000000000000000000000000000d500000001a39c4e1b259473fbcc5213a0613eb53a8c50bf7601993d186e446474c02a7128f7664b21f84cf71bf23c094891c7a0eb50d60aac82fe74ca635e5232c171eb8389f4b572b5da6e6b0f1f352a6e3baa9730f255991994a6df1604fcb4a6b08b125e6de7c4a9fc4e91a83d0307d0aa69047208b24e15bd81098f9f580176ddf17604604b009259ddb3477cd87b6fd26d00615d65bb7e09597c1ea058e700a3da7169688700edc6c0383f63e6a51b313afcf46f7159649cd4da51903c820aa577e93adc5400cb62bd05a5d1bc8f9b4bcbf8de9670040106859f3c78b5f4d0e69804e743b90005506f23503f720744f6a7e5ade176064fdc43803dcd6a12eda8d523fea35c004fe7e9537fa48f87c7b23f9f01e7ba0aa4f6688dbdb2646ec62d0156a152910021c702d00c73f27add8d238d04248a2c5b76e4b108116b2f969952352158640064b86dd4d6048c35719131dc4828ab8c95cb2aeb29fde8163f10994bfcffaf00041250da0f2525a80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + { + "Input": { + "PrivateKey": "ee15ba623c2a495eefc9b8dc7447ff70bee325cc1f75f5170a71dc4dd3227f13", + "To": "0xd59399657A78bb69dEE83C416C13Be711e02fA23", + "Nonce": 4, + "Value": "1", + "GasLimit": 21000, + "GasPrice": "1001", + "PriorityGasPrice": "35", + "MaxFeePerBlobGas": "70", + "Data": "0xab7df14deb748629d5977f83d8536dc5c24561b1cea925451174062650693e3a0a4e9b888a2b0851c37b9ba08d4ed87ec3f877b9e61579a406b5254151b5dc19367820e899c7044be963af47e6f48d3dd2c6641176a1a6f2c29de718ad4d5ef81d8dea813f6570525d1eb9b41f2c4a957fb2af932fbdd8b46fc8086a705b8ce89b319000d5820a8e03e009f0068901762602836f8275208df4061ec3af8c890dcee5b75606084179b671e58e7664ccb115f5986291bdae081600ca52c4d68b81998ed228a7eed85bdcf421f779495ee4a5ceb8f640ba736f2528a4c59dac9d7772088681ecdcf80127d983cfe504281f4c13a2ff04e33dd279b91240ea54804110f59977d0fcf70a0a9b22bbd0d450e90ca09ef09f4400066486a2c87440b378970d888303a25afe22968c07cfa1184a7b9a12143a1953715fe0f939c5d206452ddddeb5f202f4b23a0a372328cb9f508e70c2c6c988d81dd6f7dd811feb6d56baaaf2682e9de965ab0eb31f729b59550f0d01a9f0d89a8df5de74a816ef184d7889fe7447596e4084afa4d6a927d268c1cc4a6b5fa60df8410c8df357e989f724f0d1b8fa4376a7dc701e6dd9426d558f7451d4d3bbba18558fd9ed1354143fe40f47cc5c00c3bf1e9e566afe04d2f6e68811a889888bea0b9c09ea3cf3d869f973faabc894d4b217ba9421eafcdd6d554021a5ef3b471d3d343c7e9096113d32c44f7c164d5399afface623210089d580a6a00050c08b99af5005aad43332661ff482d75777813f922f642132836ba9477477cabff285e65c26ec7ce7d93ef048861e0eeff856a5239c36e574a0436e0c02c79747137e94dacdde8a3d182590110c1666d09b189fadb211bc3bff278bbbab9017cc38a67d9fc3161ed509309a9117e28b36dfc0fc947f12698204c3a461173849f247172d30a344e8f60c875bed85b40f7f48dd1eea5be4e23982097b980eb59349155fe5428f1e09c87052b0d19e2032ba3207b5ae082eb4c9073cd320a65dbde9eb1bc036bc9f8bd2fb98cc3d484f51ffffda4262506548ab031a8b096c7407297c17705b82b99d337777e19002cec4e6eb3a1f59c3cfe34e3c33463c2720580a3ce8837cae469a14855b1cd22998720ac59453ee2f1710e1393c0a373b53e55e4cf662873b98a4665b8a34c2766eb6aebf9d1f66913e661b826382c855d6bcae2604d01d61647084bf72c114ced593104bafc8e79e341b5d79eca3b962422fdc81069e5bc4e1b2278719e4994f449afc12280841a617e6dedcb7ed13392738417c7991a12984abf2af764ca8a5a2e06ed2082c7523d1a00ffbb8722e2792dacc3b8810f85ccd7bcee288ed42be6a9e13a14c0accc9dc3bb7f984612d7a16397ba12e046f4e8e39914aa83de3da1a32cd6df36a290074de4cf67165c9055454b320146023400c3f5bc2946" + }, + "RawEncodedTransaction": "0x033c00000076010000a60100008688d5a22dfcbac7ba4554a408e4cd987e899ac34ac328647894b90715efd9691b48177f9f18d8296286e675197af3ef4500000001dc17eaa54e29b2def5c88ec0cd9c223e1983abee1f9f3a6da927e5aa59a8a9fb082b03a9b38cfae8007625d9ae04da8945359ecc8ab6b9b175041b1c7abbc34c330500000000000000000000000000000000000000000000000000000000000004000000000000002300000000000000000000000000000000000000000000000000000000000000e9030000000000000000000000000000000000000000000000000000000000000852000000000000c00000000100000000000000000000000000000000000000000000000000000000000000d5000000d50000004600000000000000000000000000000000000000000000000000000000000000d500000001d59399657a78bb69dee83c416c13be711e02fa2301bac1ab118201c78f5372db0b0d587a9b4f198c83b5a7c52cc8f76bb0081892b8034bc918ce25dfe12bc4109e7576a01bb5e0f1bc9503d647d750a9451ff02007fbe7533e95d02cdc495361e7e0a25eab7df14deb748629d5977f83d8536dc5c24561b1cea925451174062650693e003a0a4e9b888a2b0851c37b9ba08d4ed87ec3f877b9e61579a406b5254151b500dc19367820e899c7044be963af47e6f48d3dd2c6641176a1a6f2c29de718ad004d5ef81d8dea813f6570525d1eb9b41f2c4a957fb2af932fbdd8b46fc8086a00705b8ce89b319000d5820a8e03e009f0068901762602836f8275208df4061e00c3af8c890dcee5b75606084179b671e58e7664ccb115f5986291bdae08160000ca52c4d68b81998ed228a7eed85bdcf421f779495ee4a5ceb8f640ba736f250028a4c59dac9d7772088681ecdcf80127d983cfe504281f4c13a2ff04e33dd20079b91240ea54804110f59977d0fcf70a0a9b22bbd0d450e90ca09ef09f440000066486a2c87440b378970d888303a25afe22968c07cfa1184a7b9a12143a190053715fe0f939c5d206452ddddeb5f202f4b23a0a372328cb9f508e70c2c6c90088d81dd6f7dd811feb6d56baaaf2682e9de965ab0eb31f729b59550f0d01a900f0d89a8df5de74a816ef184d7889fe7447596e4084afa4d6a927d268c1cc4a006b5fa60df8410c8df357e989f724f0d1b8fa4376a7dc701e6dd9426d558f740051d4d3bbba18558fd9ed1354143fe40f47cc5c00c3bf1e9e566afe04d2f6e6008811a889888bea0b9c09ea3cf3d869f973faabc894d4b217ba9421eafcdd6d00554021a5ef3b471d3d343c7e9096113d32c44f7c164d5399afface62321008009d580a6a00050c08b99af5005aad43332661ff482d75777813f922f64213280036ba9477477cabff285e65c26ec7ce7d93ef048861e0eeff856a5239c36e57004a0436e0c02c79747137e94dacdde8a3d182590110c1666d09b189fadb211b00c3bff278bbbab9017cc38a67d9fc3161ed509309a9117e28b36dfc0fc947f1002698204c3a461173849f247172d30a344e8f60c875bed85b40f7f48dd1eea500be4e23982097b980eb59349155fe5428f1e09c87052b0d19e2032ba3207b5a00e082eb4c9073cd320a65dbde9eb1bc036bc9f8bd2fb98cc3d484f51ffffda400262506548ab031a8b096c7407297c17705b82b99d337777e19002cec4e6eb300a1f59c3cfe34e3c33463c2720580a3ce8837cae469a14855b1cd22998720ac0059453ee2f1710e1393c0a373b53e55e4cf662873b98a4665b8a34c2766eb6a00ebf9d1f66913e661b826382c855d6bcae2604d01d61647084bf72c114ced59003104bafc8e79e341b5d79eca3b962422fdc81069e5bc4e1b2278719e4994f40049afc12280841a617e6dedcb7ed13392738417c7991a12984abf2af764ca8a005a2e06ed2082c7523d1a00ffbb8722e2792dacc3b8810f85ccd7bcee288ed4002be6a9e13a14c0accc9dc3bb7f984612d7a16397ba12e046f4e8e39914aa8300de3da1a32cd6df36a290074de4cf67165c9055454b320146023400c3f5bc29004600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } +] \ No newline at end of file diff --git a/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/mainnet/block_62717.blocks b/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/mainnet/block_62717.blocks new file mode 100644 index 00000000000..908adb571ca Binary files /dev/null and b/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/mainnet/block_62717.blocks differ diff --git a/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/mainnet/block_62718.blocks b/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/mainnet/block_62718.blocks new file mode 100644 index 00000000000..908adb571ca Binary files /dev/null and b/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/mainnet/block_62718.blocks differ diff --git a/ethereum/eth/build.gradle b/ethereum/eth/build.gradle index 0f68fc521d3..a40b49afffb 100644 --- a/ethereum/eth/build.gradle +++ b/ethereum/eth/build.gradle @@ -55,9 +55,9 @@ dependencies { implementation 'com.google.guava:guava' implementation 'io.vertx:vertx-core' implementation 'org.apache.commons:commons-lang3' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-units' - implementation 'org.apache.tuweni:tuweni-rlp' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-units' + implementation 'io.tmio:tuweni-rlp' annotationProcessor "org.immutables:value" implementation "org.immutables:value-annotations" @@ -74,7 +74,6 @@ dependencies { testImplementation project(':testutil') testImplementation 'com.fasterxml.jackson.core:jackson-databind' - testImplementation 'junit:junit' testImplementation 'org.assertj:assertj-core' testImplementation 'org.awaitility:awaitility' testImplementation 'org.junit.jupiter:junit-jupiter' @@ -82,9 +81,6 @@ dependencies { testImplementation 'org.mockito:mockito-junit-jupiter' testImplementation 'org.openjdk.jol:jol-core' - testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' - - testSupportImplementation 'junit:junit' testSupportImplementation 'org.mockito:mockito-core' testSupportImplementation project(':testutil') testSupportImplementation project(path: ':ethereum:core', configuration: 'testArtifacts') diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/encoding/TransactionAnnouncementDecoder.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/encoding/TransactionAnnouncementDecoder.java index 3d8df28f57f..8fb89158b72 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/encoding/TransactionAnnouncementDecoder.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/encoding/TransactionAnnouncementDecoder.java @@ -15,12 +15,12 @@ package org.hyperledger.besu.ethereum.eth.encoding; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.ethereum.eth.EthProtocolVersion; import org.hyperledger.besu.ethereum.eth.transactions.TransactionAnnouncement; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability; import org.hyperledger.besu.ethereum.rlp.RLPException; import org.hyperledger.besu.ethereum.rlp.RLPInput; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.ArrayList; import java.util.List; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/encoding/TransactionAnnouncementEncoder.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/encoding/TransactionAnnouncementEncoder.java index 93ff06c9351..dd7f14db928 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/encoding/TransactionAnnouncementEncoder.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/encoding/TransactionAnnouncementEncoder.java @@ -17,11 +17,11 @@ import static org.hyperledger.besu.ethereum.core.Transaction.toHashList; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.EthProtocolVersion; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.ArrayList; import java.util.List; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/messages/PooledTransactionsMessage.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/messages/PooledTransactionsMessage.java index ae06cd30a16..8f4717bb5c1 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/messages/PooledTransactionsMessage.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/messages/PooledTransactionsMessage.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.eth.messages; import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.core.encoding.BlobTransactionEncoder; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.AbstractMessageData; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; @@ -39,9 +40,16 @@ public int getCode() { } public static PooledTransactionsMessage create(final List transactions) { - List tx = transactions; final BytesValueRLPOutput out = new BytesValueRLPOutput(); - out.writeList(tx, Transaction::writeTo); + out.writeList( + transactions, + (transaction, rlpOutput) -> { + if (transaction.getType().supportsBlob()) { + BlobTransactionEncoder.encodeForWireNetwork(transaction, rlpOutput); + } else { + transaction.writeTo(rlpOutput); + } + }); return new PooledTransactionsMessage(out.encoded()); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloaderFactory.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloaderFactory.java index 5be64317e29..441dcfeb9d5 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloaderFactory.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloaderFactory.java @@ -14,7 +14,6 @@ */ package org.hyperledger.besu.ethereum.eth.sync.checkpointsync; -import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.eth.manager.EthContext; @@ -90,7 +89,7 @@ public static Optional> createCheckpointDownloader( .ifPresent( address -> snapContext.addAccountsToBeRepaired( - CompactEncoding.bytesToPath(Hash.hash(address)))); + CompactEncoding.bytesToPath(address.addressHash()))); } else if (fastSyncState.getPivotBlockHeader().isEmpty() && protocolContext.getBlockchain().getChainHeadBlockNumber() != BlockHeader.GENESIS_BLOCK_NUMBER) { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapDownloaderFactory.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapDownloaderFactory.java index ffea38d3950..3f6596cf0b8 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapDownloaderFactory.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapDownloaderFactory.java @@ -14,7 +14,6 @@ */ package org.hyperledger.besu.ethereum.eth.sync.snapsync; -import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.eth.manager.EthContext; @@ -85,7 +84,7 @@ public static Optional> createSnapDownloader( .ifPresent( address -> snapContext.addAccountsToBeRepaired( - CompactEncoding.bytesToPath(Hash.hash(address)))); + CompactEncoding.bytesToPath(address.addressHash()))); } else if (fastSyncState.getPivotBlockHeader().isEmpty() && protocolContext.getBlockchain().getChainHeadBlockNumber() != BlockHeader.GENESIS_BLOCK_NUMBER) { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequest.java index 092925b955d..779a5a72c8a 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequest.java @@ -22,6 +22,7 @@ import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; import org.hyperledger.besu.ethereum.trie.CompactEncoding; import org.hyperledger.besu.ethereum.trie.MerkleTrie; +import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage.Updater; @@ -59,13 +60,17 @@ protected int doPersist( @Override public Optional getExistingData( final SnapWorldDownloadState downloadState, final WorldStateStorage worldStateStorage) { - Optional accountStorageTrieNode = - worldStateStorage.getAccountStorageTrieNode( - getAccountHash(), - getLocation(), - null); // push null to not check the hash in the getAccountStorageTrieNode method - if (accountStorageTrieNode.isPresent()) { - return accountStorageTrieNode + + final Optional storageTrieNode; + if (worldStateStorage.getDataStorageFormat().equals(DataStorageFormat.FOREST)) { + storageTrieNode = worldStateStorage.getTrieNodeUnsafe(getNodeHash()); + } else { + storageTrieNode = + worldStateStorage.getTrieNodeUnsafe(Bytes.concatenate(getAccountHash(), getLocation())); + } + + if (storageTrieNode.isPresent()) { + return storageTrieNode .filter(node -> Hash.hash(node).equals(getNodeHash())) .or( () -> { // if we have a storage in database but not the good one we will need to fix diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionAnnouncement.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionAnnouncement.java index 1533a6bdbe4..4f623f80686 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionAnnouncement.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionAnnouncement.java @@ -17,8 +17,8 @@ import static com.google.common.base.Preconditions.checkNotNull; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.ArrayList; import java.util.List; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionBroadcaster.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionBroadcaster.java index 583f90f9dc6..f64f4e7973c 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionBroadcaster.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionBroadcaster.java @@ -14,15 +14,15 @@ */ package org.hyperledger.besu.ethereum.eth.transactions; +import static org.hyperledger.besu.datatypes.TransactionType.BLOB; import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.toTransactionList; -import static org.hyperledger.besu.plugin.data.TransactionType.BLOB; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthPeer; import org.hyperledger.besu.ethereum.eth.messages.EthPV65; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool.TransactionBatchAddedListener; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.ArrayList; import java.util.Collection; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java index 7b16d8717d6..41978bcb932 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java @@ -19,7 +19,9 @@ import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.INTERNAL_ERROR; import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.TRANSACTION_ALREADY_KNOWN; +import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; @@ -30,9 +32,9 @@ import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthPeer; -import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionValidator; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams; +import org.hyperledger.besu.ethereum.mainnet.TransactionValidator; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; @@ -40,7 +42,6 @@ import org.hyperledger.besu.ethereum.trie.MerkleTrieException; import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.fluent.SimpleAccount; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.util.Subscribers; import java.io.BufferedReader; @@ -56,6 +57,7 @@ import java.util.Comparator; import java.util.IntSummaryStatistics; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.OptionalLong; import java.util.concurrent.CompletableFuture; @@ -198,20 +200,25 @@ private Stream sortedBySenderAndNonce(final Collection .sorted(Comparator.comparing(Transaction::getSender).thenComparing(Transaction::getNonce)); } - public void addRemoteTransactions(final Collection transactions) { + public Map> addRemoteTransactions( + final Collection transactions) { final long started = System.currentTimeMillis(); final int initialCount = transactions.size(); final List addedTransactions = new ArrayList<>(initialCount); LOG.debug("Adding {} remote transactions", initialCount); - sortedBySenderAndNonce(transactions) - .forEach( - transaction -> { - final var result = addRemoteTransaction(transaction); - if (result.isValid()) { - addedTransactions.add(transaction); - } - }); + final var validationResults = + sortedBySenderAndNonce(transactions) + .collect( + Collectors.toMap( + Transaction::getHash, + transaction -> { + final var result = addRemoteTransaction(transaction); + if (result.isValid()) { + addedTransactions.add(transaction); + } + return result; + })); LOG_FOR_REPLAY .atTrace() @@ -231,6 +238,7 @@ public void addRemoteTransactions(final Collection transactions) { if (!addedTransactions.isEmpty()) { transactionBroadcaster.onTransactionsAdded(addedTransactions); } + return validationResults; } private ValidationResult addRemoteTransaction( @@ -353,14 +361,11 @@ private static void logReAddedTransactions( .log(); } - private MainnetTransactionValidator getTransactionValidator() { + private TransactionValidator getTransactionValidator() { return protocolSchedule .getByBlockHeader(protocolContext.getBlockchain().getChainHeadHeader()) - .getTransactionValidator(); - } - - public PendingTransactions getPendingTransactions() { - return pendingTransactions; + .getTransactionValidatorFactory() + .get(); } private ValidationResultAndAccount validateLocalTransaction(final Transaction transaction) { @@ -491,6 +496,44 @@ private Optional getChainHeadBlockHeader() { return blockchain.getBlockHeader(blockchain.getChainHeadHash()); } + public boolean isLocalSender(final Address sender) { + return pendingTransactions.isLocalSender(sender); + } + + public int count() { + return pendingTransactions.size(); + } + + public Collection getPendingTransactions() { + return pendingTransactions.getPendingTransactions(); + } + + public OptionalLong getNextNonceForSender(final Address address) { + return pendingTransactions.getNextNonceForSender(address); + } + + public long maxSize() { + return pendingTransactions.maxSize(); + } + + public void evictOldTransactions() { + pendingTransactions.evictOldTransactions(); + } + + public void selectTransactions( + final PendingTransactions.TransactionSelector transactionSelector) { + pendingTransactions.selectTransactions(transactionSelector); + } + + public String logStats() { + return pendingTransactions.logStats(); + } + + @VisibleForTesting + Class pendingTransactionsImplementation() { + return pendingTransactions.getClass(); + } + public interface TransactionBatchAddedListener { void onTransactionsAdded(Collection transactions); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolEvictionService.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolEvictionService.java index 58d575f326f..c572f5847a1 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolEvictionService.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolEvictionService.java @@ -37,7 +37,7 @@ public void start() { TimeUnit.MINUTES.toMillis(1), id -> { if (transactionPool.isEnabled()) { - transactionPool.getPendingTransactions().evictOldTransactions(); + transactionPool.evictOldTransactions(); } })); } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/EthProtocolTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/EthProtocolTest.java index 4555ad3d9d1..c89a9152c79 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/EthProtocolTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/EthProtocolTest.java @@ -18,7 +18,7 @@ import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class EthProtocolTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ChainStateTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ChainStateTest.java index 7b9c209f140..f4a2f608444 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ChainStateTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ChainStateTest.java @@ -27,7 +27,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class ChainStateTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeerTest.java index 0b7c850cbf7..99de00e6003 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeerTest.java @@ -52,7 +52,7 @@ import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class EthPeerTest { private static final BlockDataGenerator gen = new BlockDataGenerator(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeersTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeersTest.java index 375cfbd387b..06499fb8b8f 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeersTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeersTest.java @@ -39,8 +39,8 @@ import java.util.concurrent.CancellationException; import java.util.function.Consumer; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.stubbing.Answer; public class EthPeersTest { @@ -51,7 +51,7 @@ public class EthPeersTest { private final RequestManager.ResponseStream responseStream = mock(RequestManager.ResponseStream.class); - @Before + @BeforeEach public void setup() throws Exception { when(peerRequest.sendRequest(any())).thenReturn(responseStream); ethProtocolManager = EthProtocolManagerTestUtil.create(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java index 6fc31a33961..d47581d2c88 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java @@ -99,8 +99,8 @@ import org.awaitility.Awaitility; import org.awaitility.core.ConditionFactory; import org.awaitility.core.ConditionTimeoutException; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; // NullPointerExceptions on optional.get() will result in test failures anyway @@ -114,7 +114,7 @@ public final class EthProtocolManagerTest { private static ProtocolContext protocolContext; private static final MetricsSystem metricsSystem = new NoOpMetricsSystem(); - @BeforeClass + @BeforeAll public static void setup() { gen = new BlockDataGenerator(0); final BlockchainSetupUtil blockchainSetupUtil = diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthSchedulerShutdownTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthSchedulerShutdownTest.java index 1cf97c9a622..714021b17fb 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthSchedulerShutdownTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthSchedulerShutdownTest.java @@ -21,8 +21,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class EthSchedulerShutdownTest { @@ -33,7 +33,7 @@ public class EthSchedulerShutdownTest { private ExecutorService servicesExecutor; private ExecutorService computationExecutor; - @Before + @BeforeEach public void setup() { scheduledExecutor = Executors.newSingleThreadScheduledExecutor(); syncWorkerExecutor = Executors.newSingleThreadExecutor(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthSchedulerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthSchedulerTest.java index dcc4d3dbaab..7ce43a0c5f8 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthSchedulerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthSchedulerTest.java @@ -29,8 +29,8 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class EthSchedulerTest { @@ -39,7 +39,7 @@ public class EthSchedulerTest { private MockScheduledExecutor scheduledExecutor; private AtomicBoolean shouldTimeout; - @Before + @BeforeEach public void setup() { shouldTimeout = new AtomicBoolean(false); ethScheduler = new DeterministicEthScheduler(shouldTimeout::get); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthServerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthServerTest.java index 4a4aeac2eb3..7c75c6ddad3 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthServerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthServerTest.java @@ -55,7 +55,7 @@ import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class EthServerTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputationTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputationTest.java index 1fa5b47b96f..9706369a069 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputationTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputationTest.java @@ -20,7 +20,8 @@ import org.hyperledger.besu.ethereum.eth.messages.EthPV62; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class PeerReputationTest { @@ -28,9 +29,9 @@ public class PeerReputationTest { private static final int MAX_SCORE = 50; private final PeerReputation reputation = new PeerReputation(INITIAL_SCORE, MAX_SCORE); - @Test(expected = java.lang.IllegalArgumentException.class) + @Test public void shouldThrowOnInvalidInitialScore() { - new PeerReputation(2, 1); + Assertions.assertThrows(IllegalArgumentException.class, () -> new PeerReputation(2, 1)); } @Test diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/RequestManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/RequestManagerTest.java index 7ab55f8e088..a00a08a7378 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/RequestManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/RequestManagerTest.java @@ -36,7 +36,7 @@ import java.util.function.Consumer; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class RequestManagerTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/bounded/BoundedQueueTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/bounded/BoundedQueueTest.java index 7c42386bf98..9188b148eac 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/bounded/BoundedQueueTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/bounded/BoundedQueueTest.java @@ -18,7 +18,7 @@ import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class BoundedQueueTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java index ab4a87bc738..aeb60471403 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java @@ -17,6 +17,11 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.spy; +import org.hyperledger.besu.crypto.KeyPair; +import org.hyperledger.besu.crypto.SECPPrivateKey; +import org.hyperledger.besu.crypto.SECPPublicKey; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -52,9 +57,10 @@ import java.util.concurrent.atomic.AtomicReference; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; +import org.apache.tuweni.bytes.Bytes32; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * @param The type of data being requested from the network @@ -62,6 +68,19 @@ */ public abstract class AbstractMessageTaskTest { protected static final int MAX_PEERS = 5; + protected static final KeyPair genesisAccountKeyPair = + new KeyPair( + SECPPrivateKey.create( + Bytes32.fromHexString( + "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8"), + "ECDSA"), + SECPPublicKey.create( + Bytes.fromHexString( + "0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3"), + "ECDSA")); + protected static final Address genesisAccountSender = + Address.extract(Hash.hash(genesisAccountKeyPair.getPublicKey().getEncodedBytes())); + protected static final long genesisAccountNonce = 32; protected static Blockchain blockchain; protected static ProtocolSchedule protocolSchedule; protected static ProtocolContext protocolContext; @@ -73,7 +92,7 @@ public abstract class AbstractMessageTaskTest { protected AtomicBoolean peersDoTimeout; protected AtomicInteger peerCountToTimeout; - @BeforeClass + @BeforeAll public static void setup() { final BlockchainSetupUtil blockchainSetupUtil = BlockchainSetupUtil.forTesting(DataStorageFormat.FOREST); @@ -84,7 +103,7 @@ public static void setup() { assertThat(blockchainSetupUtil.getMaxBlockNumber()).isGreaterThanOrEqualTo(20L); } - @Before + @BeforeEach public void setupTest() { peersDoTimeout = new AtomicBoolean(false); peerCountToTimeout = new AtomicInteger(0); @@ -119,6 +138,8 @@ public void setupTest() { syncState, new MiningParameters.Builder().minTransactionGasPrice(Wei.ONE).build(), TransactionPoolConfiguration.DEFAULT); + transactionPool.setEnabled(); + ethProtocolManager = EthProtocolManagerTestUtil.create( blockchain, diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/PeerMessageTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/PeerMessageTaskTest.java index dceb4d623b5..1405fbc24ac 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/PeerMessageTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/PeerMessageTaskTest.java @@ -38,7 +38,7 @@ import java.util.function.Consumer; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * Tests ethTasks that interact with a single peer to retrieve data from the network. diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/RetryingMessageTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/RetryingMessageTaskTest.java index b69e316398e..85f29cf35b0 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/RetryingMessageTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/RetryingMessageTaskTest.java @@ -26,8 +26,8 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * Tests ethTasks that request data from the network, and retry until all of the data is received. @@ -38,7 +38,7 @@ public abstract class RetryingMessageTaskTest extends AbstractMessageTaskTest protected static final int DEFAULT_MAX_RETRIES = 4; protected int maxRetries; - @Before + @BeforeEach public void resetMaxRetries() { this.maxRetries = DEFAULT_MAX_RETRIES; } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/RetryingSwitchingPeerMessageTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/RetryingSwitchingPeerMessageTaskTest.java index e7c953f0935..084c730a6e3 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/RetryingSwitchingPeerMessageTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/RetryingSwitchingPeerMessageTaskTest.java @@ -29,7 +29,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * Tests ethTasks that request data from the network, and retry until all of the data is received. diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractEthTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractEthTaskTest.java index e0c17248a51..f1ca69d6701 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractEthTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractEthTaskTest.java @@ -32,12 +32,12 @@ import java.util.concurrent.atomic.AtomicInteger; import com.google.common.collect.Lists; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class AbstractEthTaskTest { @Mock private OperationTimer mockOperationTimer; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTaskTest.java index 90b407f2fce..e180420a4f5 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTaskTest.java @@ -28,12 +28,12 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class AbstractRetryingPeerTaskTest { @Mock EthContext ethContext; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/BufferedGetPooledTransactionsFromPeerFetcherTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/BufferedGetPooledTransactionsFromPeerFetcherTest.java index 2f4049aa7e1..17b834cedf1 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/BufferedGetPooledTransactionsFromPeerFetcherTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/BufferedGetPooledTransactionsFromPeerFetcherTest.java @@ -41,13 +41,16 @@ import java.util.stream.IntStream; import io.netty.util.concurrent.ScheduledFuture; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class BufferedGetPooledTransactionsFromPeerFetcherTest { @Mock EthPeer ethPeer; @@ -61,7 +64,7 @@ public class BufferedGetPooledTransactionsFromPeerFetcherTest { private StubMetricsSystem metricsSystem; private PeerTransactionTracker transactionTracker; - @Before + @BeforeEach public void setup() { metricsSystem = new StubMetricsSystem(); transactionTracker = new PeerTransactionTracker(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetBlockFromPeerTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetBlockFromPeerTaskTest.java index 7cdcd3c7071..99ea4ad06cb 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetBlockFromPeerTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetBlockFromPeerTaskTest.java @@ -31,7 +31,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicReference; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class GetBlockFromPeerTaskTest extends AbstractMessageTaskTest> { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetBodiesFromPeerTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetBodiesFromPeerTaskTest.java index 09e4f972e4e..dbe1ba9bc86 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetBodiesFromPeerTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetBodiesFromPeerTaskTest.java @@ -35,7 +35,7 @@ import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt64; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class GetBodiesFromPeerTaskTest extends PeerMessageTaskTest> { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByHashTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByHashTaskTest.java index 6d6881c01ff..aecb7191afe 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByHashTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByHashTaskTest.java @@ -37,11 +37,11 @@ import java.util.concurrent.atomic.AtomicReference; import org.hamcrest.MatcherAssert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class GetHeadersFromPeerByHashTaskTest extends PeerMessageTaskTest> { @Override diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByNumberTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByNumberTaskTest.java index ea6c290bdb9..5f2479ef458 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByNumberTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByNumberTaskTest.java @@ -37,11 +37,11 @@ import java.util.concurrent.atomic.AtomicReference; import org.hamcrest.MatcherAssert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class GetHeadersFromPeerByNumberTaskTest extends PeerMessageTaskTest> { @Override protected void assertPartialResultMatchesExpectation( diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetPooledTransactionsFromPeerTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetPooledTransactionsFromPeerTaskTest.java index 760e481bc6b..f50237515e4 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetPooledTransactionsFromPeerTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetPooledTransactionsFromPeerTaskTest.java @@ -16,14 +16,12 @@ import static org.assertj.core.api.Assertions.assertThat; -import org.hyperledger.besu.crypto.KeyPair; -import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.eth.manager.EthPeer; import org.hyperledger.besu.ethereum.eth.manager.ethtaskutils.PeerMessageTaskTest; -import org.hyperledger.besu.ethereum.eth.transactions.TransactionAddedResult; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; @@ -40,18 +38,16 @@ public class GetPooledTransactionsFromPeerTaskTest extends PeerMessageTaskTest generateDataToBeRequested() { - - final List requestedData = new ArrayList<>(); - KeyPair keyPair = SignatureAlgorithmFactory.getInstance().generateKeyPair(); + final List requestedData = new ArrayList<>(3); for (int i = 0; i < 3; i++) { Transaction tx = new TransactionTestFixture() - .nonce(i) + .nonce(genesisAccountNonce + i) + .gasPrice(Wei.ONE) .gasLimit(100000) .chainId(Optional.empty()) - .createTransaction(keyPair); - assertThat(transactionPool.getPendingTransactions().addLocalTransaction(tx, Optional.empty())) - .isEqualTo(TransactionAddedResult.ADDED); + .createTransaction(genesisAccountKeyPair); + assertThat(transactionPool.addTransactionViaApi(tx).isValid()).isTrue(); requestedData.add(tx); } return requestedData; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetBlockFromPeersTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetBlockFromPeersTaskTest.java index 9e900287b1f..9996842bd2d 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetBlockFromPeersTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetBlockFromPeersTaskTest.java @@ -26,8 +26,8 @@ import java.util.Optional; import java.util.concurrent.ExecutionException; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; public class RetryingGetBlockFromPeersTaskTest extends RetryingSwitchingPeerMessageTaskTest> { @@ -59,12 +59,12 @@ protected RetryingGetBlockFromPeersTask createTask(final PeerTaskResult r @Test @Override - @Ignore("GetBlock could not return partial response") + @Disabled("GetBlock could not return partial response") public void failsWhenPeerReturnsPartialResultThenStops() {} @Override @Test - @Ignore("GetBlock could not return partial response") + @Disabled("GetBlock could not return partial response") public void completesWhenPeerReturnsPartialResult() throws ExecutionException, InterruptedException { super.completesWhenPeerReturnsPartialResult(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetNodeDataFromPeerTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetNodeDataFromPeerTaskTest.java index 586bf2aa22d..5ed94b143a5 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetNodeDataFromPeerTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetNodeDataFromPeerTaskTest.java @@ -31,8 +31,8 @@ import com.google.common.collect.Lists; import org.apache.tuweni.bytes.Bytes; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; public class RetryingGetNodeDataFromPeerTaskTest extends RetryingMessageTaskTest> { @@ -88,11 +88,11 @@ public void completesWhenPeerReturnsPartialResult() @Test @Override - @Ignore("Partial responses are enough to complete the request so this test doesn't apply") + @Disabled("Partial responses are enough to complete the request so this test doesn't apply") public void failsWhenPeerReturnsPartialResultThenStops() {} @Test @Override - @Ignore("Empty responses count as valid when requesting node data") + @Disabled("Empty responses count as valid when requesting node data") public void failsWhenPeersSendEmptyResponses() {} } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/WaitForPeerTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/WaitForPeerTaskTest.java index 3690723f24c..906b0ca7aaa 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/WaitForPeerTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/WaitForPeerTaskTest.java @@ -26,15 +26,15 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicBoolean; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class WaitForPeerTaskTest { private EthProtocolManager ethProtocolManager; private EthContext ethContext; private final MetricsSystem metricsSystem = new NoOpMetricsSystem(); - @Before + @BeforeEach public void setupTest() { ethProtocolManager = EthProtocolManagerTestUtil.create(); ethContext = ethProtocolManager.ethContext(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/WaitForPeersTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/WaitForPeersTaskTest.java index 275026473a5..283a1b5894c 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/WaitForPeersTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/WaitForPeersTaskTest.java @@ -26,15 +26,15 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicBoolean; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class WaitForPeersTaskTest { private EthProtocolManager ethProtocolManager; private EthContext ethContext; private final MetricsSystem metricsSystem = new NoOpMetricsSystem(); - @Before + @BeforeEach public void setupTest() { ethProtocolManager = EthProtocolManagerTestUtil.create(); ethContext = ethProtocolManager.ethContext(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockBodiesMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockBodiesMessageTest.java index c305d5fcbb1..665384f1f66 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockBodiesMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockBodiesMessageTest.java @@ -42,15 +42,15 @@ import com.google.common.io.Resources; import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** Tests for {@link BlockBodiesMessage}. */ public final class BlockBodiesMessageTest { private ProtocolSchedule protocolSchedule; - @Before + @BeforeEach public void setup() { protocolSchedule = FixedDifficultyProtocolSchedule.create( diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockHeadersMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockHeadersMessageTest.java index 697313c26d3..6dc6b08fd21 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockHeadersMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockHeadersMessageTest.java @@ -33,7 +33,7 @@ import com.google.common.io.Resources; import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** Tests for {@link BlockHeadersMessage}. */ public final class BlockHeadersMessageTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/GetBlockBodiesMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/GetBlockBodiesMessageTest.java index d9a27cf22ed..43d2371b87a 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/GetBlockBodiesMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/GetBlockBodiesMessageTest.java @@ -32,7 +32,7 @@ import com.google.common.io.Resources; import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** Tests for {@link GetBlockBodiesMessage}. */ public final class GetBlockBodiesMessageTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/GetBlockHeadersMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/GetBlockHeadersMessageTest.java index 0e0aaf71dd8..8585204057f 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/GetBlockHeadersMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/GetBlockHeadersMessageTest.java @@ -22,7 +22,7 @@ import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public final class GetBlockHeadersMessageTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/GetNodeDataMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/GetNodeDataMessageTest.java index 8e335acbfa0..b8d0aa9fc2b 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/GetNodeDataMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/GetNodeDataMessageTest.java @@ -24,7 +24,7 @@ import java.util.List; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public final class GetNodeDataMessageTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/GetPooledTransactionsMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/GetPooledTransactionsMessageTest.java index 32d0443a7bb..0c0d84bfa30 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/GetPooledTransactionsMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/GetPooledTransactionsMessageTest.java @@ -25,7 +25,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class GetPooledTransactionsMessageTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/GetReceiptsMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/GetReceiptsMessageTest.java index c6f41c27dfa..e6f7110f03a 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/GetReceiptsMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/GetReceiptsMessageTest.java @@ -24,7 +24,7 @@ import java.util.List; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public final class GetReceiptsMessageTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/LimitedTransactionsMessagesTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/LimitedTransactionsMessagesTest.java index e6ee599596d..b5530d46790 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/LimitedTransactionsMessagesTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/LimitedTransactionsMessagesTest.java @@ -27,7 +27,7 @@ import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class LimitedTransactionsMessagesTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/MessageWrapperTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/MessageWrapperTest.java index 9fef76a8eb7..921802b5cc3 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/MessageWrapperTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/MessageWrapperTest.java @@ -27,6 +27,7 @@ import org.hyperledger.besu.crypto.SECP256K1; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -39,7 +40,6 @@ import org.hyperledger.besu.ethereum.rlp.RLPException; import org.hyperledger.besu.evm.log.LogTopic; import org.hyperledger.besu.evm.log.LogsBloomFilter; -import org.hyperledger.besu.plugin.data.TransactionType; import java.io.IOException; import java.math.BigInteger; @@ -55,7 +55,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class MessageWrapperTest { @@ -319,6 +319,7 @@ public TestTransaction( recIdAndChainId(Byte.decode(v)).getKey()), Bytes.fromHexString(data), recIdAndChainId(Byte.decode(v)).getValue(), + Optional.empty(), Optional.empty()); } } @@ -390,6 +391,7 @@ public TestBlockHeader( null, null, null, + null, new MainnetBlockHeaderFunctions()); } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/NewBlockHashesMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/NewBlockHashesMessageTest.java index 4f49dc2cb1c..45e2fa58712 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/NewBlockHashesMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/NewBlockHashesMessageTest.java @@ -31,7 +31,7 @@ import com.google.common.io.Resources; import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** Tests for {@link NewBlockHashesMessage}. */ public final class NewBlockHashesMessageTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/NewBlockMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/NewBlockMessageTest.java index 93e053ff583..2d7427bc2a5 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/NewBlockMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/NewBlockMessageTest.java @@ -26,7 +26,7 @@ import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class NewBlockMessageTest { private static final ProtocolSchedule protocolSchedule = ProtocolScheduleFixture.MAINNET; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/NewPooledTransactionHashesMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/NewPooledTransactionHashesMessageTest.java index 44af7d869b6..f8d5f666478 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/NewPooledTransactionHashesMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/NewPooledTransactionHashesMessageTest.java @@ -27,7 +27,7 @@ import java.util.List; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class NewPooledTransactionHashesMessageTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/NodeDataMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/NodeDataMessageTest.java index 1ec5a955bb3..ef4f7e0c3e9 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/NodeDataMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/NodeDataMessageTest.java @@ -24,7 +24,7 @@ import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public final class NodeDataMessageTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/PooledTransactionsMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/PooledTransactionsMessageTest.java index 46ebf147172..fbbdd3eae4a 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/PooledTransactionsMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/PooledTransactionsMessageTest.java @@ -18,16 +18,16 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.RawMessage; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.Arrays; import java.util.List; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PooledTransactionsMessageTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/ReceiptsMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/ReceiptsMessageTest.java index c0d253797d4..16f1ed5b8c5 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/ReceiptsMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/ReceiptsMessageTest.java @@ -24,7 +24,7 @@ import java.util.List; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public final class ReceiptsMessageTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/StatusMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/StatusMessageTest.java index 8458c990768..e4f80a4d647 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/StatusMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/StatusMessageTest.java @@ -27,7 +27,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class StatusMessageTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/TransactionsMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/TransactionsMessageTest.java index f59710ec2ae..49dca42b891 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/TransactionsMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/TransactionsMessageTest.java @@ -24,7 +24,7 @@ import java.util.ArrayList; import java.util.List; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class TransactionsMessageTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/AccountRangeMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/AccountRangeMessageTest.java index bfb76576fed..11d16a61e0b 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/AccountRangeMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/AccountRangeMessageTest.java @@ -29,7 +29,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public final class AccountRangeMessageTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/BytecodeMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/BytecodeMessageTest.java index 28b8b6883c8..05c63f71f2d 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/BytecodeMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/BytecodeMessageTest.java @@ -23,7 +23,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public final class BytecodeMessageTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/GetAccountRangeMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/GetAccountRangeMessageTest.java index c56629149db..c8ef62a6d51 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/GetAccountRangeMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/GetAccountRangeMessageTest.java @@ -22,7 +22,7 @@ import org.apache.tuweni.bytes.Bytes32; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public final class GetAccountRangeMessageTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/GetBytecodeMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/GetBytecodeMessageTest.java index 39f16882094..8091015d68d 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/GetBytecodeMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/GetBytecodeMessageTest.java @@ -23,7 +23,7 @@ import org.apache.tuweni.bytes.Bytes32; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public final class GetBytecodeMessageTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/GetStorageRangeMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/GetStorageRangeMessageTest.java index 49a43f94124..4ff1b09b9a0 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/GetStorageRangeMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/GetStorageRangeMessageTest.java @@ -24,7 +24,7 @@ import org.apache.tuweni.bytes.Bytes32; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public final class GetStorageRangeMessageTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/GetTrieNodeMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/GetTrieNodeMessageTest.java index 67447005c87..625c96931bb 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/GetTrieNodeMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/GetTrieNodeMessageTest.java @@ -25,7 +25,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public final class GetTrieNodeMessageTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/StorageRangeMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/StorageRangeMessageTest.java index c3272d1139f..c9179329b02 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/StorageRangeMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/StorageRangeMessageTest.java @@ -26,7 +26,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public final class StorageRangeMessageTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/TrieNodeMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/TrieNodeMessageTest.java index 02481e7e1b2..6223102bf9b 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/TrieNodeMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/snap/TrieNodeMessageTest.java @@ -24,7 +24,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public final class TrieNodeMessageTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/AbstractPeerBlockValidatorTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/AbstractPeerBlockValidatorTest.java index 178723546a0..34bb284c164 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/AbstractPeerBlockValidatorTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/AbstractPeerBlockValidatorTest.java @@ -37,7 +37,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import org.junit.Test; +import org.junit.jupiter.api.Test; public abstract class AbstractPeerBlockValidatorTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/DaoForkPeerValidatorTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/DaoForkPeerValidatorTest.java index 2ea01b53753..8586874c434 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/DaoForkPeerValidatorTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/DaoForkPeerValidatorTest.java @@ -30,7 +30,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class DaoForkPeerValidatorTest extends AbstractPeerBlockValidatorTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/PeerValidatorRunnerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/PeerValidatorRunnerTest.java index 780c9fc8234..4663ac3ee92 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/PeerValidatorRunnerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/PeerValidatorRunnerTest.java @@ -31,7 +31,7 @@ import java.time.Duration; import java.util.concurrent.CompletableFuture; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PeerValidatorRunnerTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/RequiredBlocksPeerValidatorTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/RequiredBlocksPeerValidatorTest.java index eab13c3df22..67c80345880 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/RequiredBlocksPeerValidatorTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/RequiredBlocksPeerValidatorTest.java @@ -31,7 +31,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class RequiredBlocksPeerValidatorTest extends AbstractPeerBlockValidatorTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/RangeHeadersFetcherTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/RangeHeadersFetcherTest.java index d0ffe91db98..0b18a0f64c6 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/RangeHeadersFetcherTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/RangeHeadersFetcherTest.java @@ -40,9 +40,9 @@ import java.util.List; import java.util.concurrent.CompletableFuture; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; @@ -59,7 +59,7 @@ public class RangeHeadersFetcherTest { private Responder responder; private RespondingEthPeer respondingPeer; - @BeforeClass + @BeforeAll public static void setUpClass() { final BlockchainSetupUtil blockchainSetupUtil = BlockchainSetupUtil.forTesting(DataStorageFormat.FOREST); @@ -70,7 +70,7 @@ public static void setUpClass() { protocolContext = blockchainSetupUtil.getProtocolContext(); } - @Before + @BeforeEach public void setUpTest() { ethProtocolManager = EthProtocolManagerTestUtil.create( diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncAlgSpec.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncAlgSpec.java index f53b32cd54f..8a1a0a226e8 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncAlgSpec.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncAlgSpec.java @@ -41,18 +41,21 @@ import javax.annotation.Nonnull; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class BackwardSyncAlgSpec { public static final int REMOTE_HEIGHT = 50; @@ -72,7 +75,7 @@ public class BackwardSyncAlgSpec { private static final BlockDataGenerator blockDataGenerator = new BlockDataGenerator(); private Block genesisBlock; - @Before + @BeforeEach public void setUp() throws Exception { BlockDataGenerator blockDataGenerator = new BlockDataGenerator(); genesisBlock = blockDataGenerator.genesisBlock(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java index 7c744c6b520..3ed28e66f4d 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java @@ -28,6 +28,7 @@ import org.hyperledger.besu.config.StubGenesisConfigOptions; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.ethereum.BlockProcessingOutputs; import org.hyperledger.besu.ethereum.BlockProcessingResult; import org.hyperledger.besu.ethereum.BlockValidator; @@ -47,7 +48,6 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.referencetests.ReferenceTestWorldState; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; @@ -60,16 +60,19 @@ import javax.annotation.Nonnull; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Answers; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.Spy; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class BackwardSyncContextTest { public static final int REMOTE_HEIGHT = 50; @@ -105,7 +108,7 @@ public class BackwardSyncContextTest { private Block uncle; private Block genesisBlock; - @Before + @BeforeEach public void setup() { when(protocolSpec.getBlockValidator()).thenReturn(blockValidator); doReturn(protocolSpec).when(protocolSchedule).getByBlockHeader(any()); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncStepTest.java index 9ddcaf7b8cb..8b77d1ac2a4 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncStepTest.java @@ -45,15 +45,18 @@ import java.util.concurrent.CompletableFuture; import javax.annotation.Nonnull; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Answers; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class BackwardSyncStepTest { public static final int REMOTE_HEIGHT = 50; @@ -76,7 +79,7 @@ public class BackwardSyncStepTest { GenericKeyValueStorageFacade chainStorage; GenericKeyValueStorageFacade sessionDataStorage; - @Before + @BeforeEach public void setup() { headersStorage = new GenericKeyValueStorageFacade<>( diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ChainForTestCreator.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ChainForTestCreator.java index 0d0b50858be..b986b7c2d95 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ChainForTestCreator.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ChainForTestCreator.java @@ -59,6 +59,7 @@ public static BlockHeader prepareHeader(final long number, final Optional chainStorage; GenericKeyValueStorageFacade sessionDataStorage; - @Before + @BeforeEach public void setup() { headersStorage = new GenericKeyValueStorageFacade<>( diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/InMemoryBackwardChainTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/InMemoryBackwardChainTest.java index 405e06d1d35..c8bffb95793 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/InMemoryBackwardChainTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/InMemoryBackwardChainTest.java @@ -31,12 +31,12 @@ import java.util.Optional; import javax.annotation.Nonnull; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class InMemoryBackwardChainTest { public static final int HEIGHT = 20_000; @@ -48,7 +48,7 @@ public class InMemoryBackwardChainTest { GenericKeyValueStorageFacade chainStorage; GenericKeyValueStorageFacade sessionDataStorage; - @Before + @BeforeEach public void prepareData() { headersStorage = new GenericKeyValueStorageFacade<>( diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointBlockImportStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointBlockImportStepTest.java index 1520edb0679..13b4718794a 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointBlockImportStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointBlockImportStepTest.java @@ -35,8 +35,8 @@ import java.util.Collections; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class CheckPointBlockImportStepTest { @@ -46,7 +46,7 @@ public class CheckPointBlockImportStepTest { private CheckpointBlockImportStep checkPointHeaderImportStep; private KeyValueStoragePrefixedKeyBlockchainStorage blockchainStorage; - @Before + @BeforeEach public void setup() { blockchainStorage = new KeyValueStoragePrefixedKeyBlockchainStorage( diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSourceTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSourceTest.java index a7d86388219..1fde5dfee16 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSourceTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSourceTest.java @@ -24,15 +24,15 @@ import java.util.Optional; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class CheckPointSourceTest { private final SyncState syncState = mock(SyncState.class); private CheckpointSource checkPointSource; - @Before + @BeforeEach public void setup() { checkPointSource = new CheckpointSource(syncState, header(12), 1); } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java index ddb15422559..62ef446503b 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java @@ -40,19 +40,17 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; -import java.util.Arrays; -import java.util.Collection; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; -@RunWith(Parameterized.class) public class CheckPointSyncChainDownloaderTest { private final WorldStateStorage worldStateStorage = mock(WorldStateStorage.class); @@ -68,19 +66,15 @@ public class CheckPointSyncChainDownloaderTest { protected Blockchain otherBlockchain; private Checkpoint checkpoint; - @Parameters - public static Collection data() { - return Arrays.asList(new Object[][] {{DataStorageFormat.BONSAI}, {DataStorageFormat.FOREST}}); + static class CheckPointSyncChainDownloaderTestArguments implements ArgumentsProvider { + @Override + public Stream provideArguments(final ExtensionContext context) { + return Stream.of( + Arguments.of(DataStorageFormat.BONSAI), Arguments.of(DataStorageFormat.FOREST)); + } } - private final DataStorageFormat storageFormat; - - public CheckPointSyncChainDownloaderTest(final DataStorageFormat storageFormat) { - this.storageFormat = storageFormat; - } - - @Before - public void setup() { + public void setup(final DataStorageFormat storageFormat) { when(worldStateStorage.isWorldStateAvailable(any(), any())).thenReturn(true); final BlockchainSetupUtil localBlockchainSetup = BlockchainSetupUtil.forTesting(storageFormat); localBlockchain = localBlockchainSetup.getBlockchain(); @@ -111,7 +105,7 @@ public void setup() { Optional.of(checkpoint)); } - @After + @AfterEach public void tearDown() { ethProtocolManager.stop(); } @@ -129,8 +123,10 @@ private ChainDownloader downloader( new FastSyncState(otherBlockchain.getBlockHeader(pivotBlockNumber).get())); } - @Test - public void shouldSyncToPivotBlockInMultipleSegments() { + @ParameterizedTest + @ArgumentsSource(CheckPointSyncChainDownloaderTestArguments.class) + public void shouldSyncToPivotBlockInMultipleSegments(final DataStorageFormat storageFormat) { + setup(storageFormat); otherBlockchainSetup.importFirstBlocks(30); final RespondingEthPeer peer = @@ -163,8 +159,10 @@ public void shouldSyncToPivotBlockInMultipleSegments() { .isEqualTo(otherBlockchain.getBlockHeader(pivotBlockNumber).get()); } - @Test - public void shouldSyncToPivotBlockInSingleSegment() { + @ParameterizedTest + @ArgumentsSource(CheckPointSyncChainDownloaderTestArguments.class) + public void shouldSyncToPivotBlockInSingleSegment(final DataStorageFormat storageFormat) { + setup(storageFormat); otherBlockchainSetup.importFirstBlocks(30); final RespondingEthPeer peer = diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java index ec9313ed907..0a775b130fa 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java @@ -37,9 +37,9 @@ import java.util.List; import java.util.concurrent.CompletableFuture; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class DownloadReceiptsStepTest { @@ -49,7 +49,7 @@ public class DownloadReceiptsStepTest { private EthProtocolManager ethProtocolManager; private DownloadReceiptsStep downloadReceiptsStep; - @BeforeClass + @BeforeAll public static void setUpClass() { final BlockchainSetupUtil setupUtil = BlockchainSetupUtil.forTesting(DataStorageFormat.FOREST); setupUtil.importFirstBlocks(20); @@ -57,7 +57,7 @@ public static void setUpClass() { blockchain = setupUtil.getBlockchain(); } - @Before + @BeforeEach public void setUp() { TransactionPool transactionPool = mock(TransactionPool.class); ethProtocolManager = diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastDownloaderFactoryTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastDownloaderFactoryTest.java index 7cdcd8d3dc4..1cb6521e00e 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastDownloaderFactoryTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastDownloaderFactoryTest.java @@ -42,13 +42,16 @@ import java.util.Optional; import org.assertj.core.api.Assertions; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; @SuppressWarnings("rawtypes") -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class FastDownloaderFactoryTest { @Mock private SynchronizerConfiguration syncConfig; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java index 7fdab1e0d3c..a707228e92d 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java @@ -46,20 +46,19 @@ import org.hyperledger.besu.plugin.services.MetricsSystem; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.OptionalLong; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; -@RunWith(Parameterized.class) public class FastSyncActionsTest { private final SynchronizerConfiguration.Builder syncConfigBuilder = @@ -77,19 +76,15 @@ public class FastSyncActionsTest { private SyncState syncState; private MetricsSystem metricsSystem; - @Parameterized.Parameters - public static Collection data() { - return Arrays.asList(new Object[][] {{DataStorageFormat.BONSAI}, {DataStorageFormat.FOREST}}); - } - - private final DataStorageFormat storageFormat; - - public FastSyncActionsTest(final DataStorageFormat storageFormat) { - this.storageFormat = storageFormat; + static class FastSyncActionsTestArguments implements ArgumentsProvider { + @Override + public Stream provideArguments(final ExtensionContext context) { + return Stream.of( + Arguments.of(DataStorageFormat.BONSAI), Arguments.of(DataStorageFormat.FOREST)); + } } - @Before - public void setUp() { + public void setUp(final DataStorageFormat storageFormat) { blockchainSetupUtil = BlockchainSetupUtil.forTesting(storageFormat); blockchainSetupUtil.importAllBlocks(); blockchain = blockchainSetupUtil.getBlockchain(); @@ -111,8 +106,11 @@ public void setUp() { new PivotSelectorFromPeers(ethContext, syncConfig, syncState, metricsSystem)); } - @Test - public void waitForPeersShouldSucceedIfEnoughPeersAreFound() { + @ParameterizedTest + @ArgumentsSource(FastSyncActionsTest.FastSyncActionsTestArguments.class) + public void waitForPeersShouldSucceedIfEnoughPeersAreFound( + final DataStorageFormat storageFormat) { + setUp(storageFormat); for (int i = 0; i < syncConfig.getFastSyncMinimumPeerCount(); i++) { EthProtocolManagerTestUtil.createPeer( ethProtocolManager, syncConfig.getFastSyncPivotDistance() + i + 1); @@ -122,8 +120,10 @@ public void waitForPeersShouldSucceedIfEnoughPeersAreFound() { assertThat(result).isCompletedWithValue(new FastSyncState(5)); } - @Test - public void returnTheSamePivotBlockIfAlreadySelected() { + @ParameterizedTest + @ArgumentsSource(FastSyncActionsTest.FastSyncActionsTestArguments.class) + public void returnTheSamePivotBlockIfAlreadySelected(final DataStorageFormat storageFormat) { + setUp(storageFormat); final BlockHeader pivotHeader = new BlockHeaderTestFixture().number(1024).buildHeader(); final FastSyncState fastSyncState = new FastSyncState(pivotHeader); final CompletableFuture result = fastSyncActions.selectPivotBlock(fastSyncState); @@ -131,8 +131,11 @@ public void returnTheSamePivotBlockIfAlreadySelected() { assertThat(result).isCompletedWithValue(fastSyncState); } - @Test - public void selectPivotBlockShouldUseExistingPivotBlockIfAvailable() { + @ParameterizedTest + @ArgumentsSource(FastSyncActionsTest.FastSyncActionsTestArguments.class) + public void selectPivotBlockShouldUseExistingPivotBlockIfAvailable( + final DataStorageFormat storageFormat) { + setUp(storageFormat); final BlockHeader pivotHeader = new BlockHeaderTestFixture().number(1024).buildHeader(); EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 5000); @@ -142,8 +145,11 @@ public void selectPivotBlockShouldUseExistingPivotBlockIfAvailable() { assertThat(result).isCompletedWithValue(expected); } - @Test - public void selectPivotBlockShouldSelectBlockPivotDistanceFromBestPeer() { + @ParameterizedTest + @ArgumentsSource(FastSyncActionsTest.FastSyncActionsTestArguments.class) + public void selectPivotBlockShouldSelectBlockPivotDistanceFromBestPeer( + final DataStorageFormat storageFormat) { + setUp(storageFormat); final int minPeers = 1; syncConfigBuilder.fastSyncMinimumPeerCount(minPeers); syncConfig = syncConfigBuilder.build(); @@ -160,8 +166,11 @@ public void selectPivotBlockShouldSelectBlockPivotDistanceFromBestPeer() { assertThat(result).isCompletedWithValue(expected); } - @Test - public void selectPivotBlockShouldConsiderTotalDifficultyWhenSelectingBestPeer() { + @ParameterizedTest + @ArgumentsSource(FastSyncActionsTest.FastSyncActionsTestArguments.class) + public void selectPivotBlockShouldConsiderTotalDifficultyWhenSelectingBestPeer( + final DataStorageFormat storageFormat) { + setUp(storageFormat); final int minPeers = 1; syncConfigBuilder.fastSyncMinimumPeerCount(minPeers); syncConfig = syncConfigBuilder.build(); @@ -179,8 +188,11 @@ public void selectPivotBlockShouldConsiderTotalDifficultyWhenSelectingBestPeer() assertThat(result).isCompletedWithValue(expected); } - @Test - public void selectPivotBlockShouldWaitAndRetryUntilMinHeightEstimatesAreAvailable() { + @ParameterizedTest + @ArgumentsSource(FastSyncActionsTest.FastSyncActionsTestArguments.class) + public void selectPivotBlockShouldWaitAndRetryUntilMinHeightEstimatesAreAvailable( + final DataStorageFormat storageFormat) { + setUp(storageFormat); EthProtocolManagerTestUtil.disableEthSchedulerAutoRun(ethProtocolManager); final int minPeers = 2; syncConfigBuilder.fastSyncMinimumPeerCount(minPeers); @@ -208,8 +220,11 @@ public void selectPivotBlockShouldWaitAndRetryUntilMinHeightEstimatesAreAvailabl assertThat(result).isCompletedWithValue(expected); } - @Test - public void selectPivotBlockShouldWaitAndRetryIfSufficientChainHeightEstimatesAreUnavailable() { + @ParameterizedTest + @ArgumentsSource(FastSyncActionsTest.FastSyncActionsTestArguments.class) + public void selectPivotBlockShouldWaitAndRetryIfSufficientChainHeightEstimatesAreUnavailable( + final DataStorageFormat storageFormat) { + setUp(storageFormat); final int minPeers = 3; syncConfigBuilder.fastSyncMinimumPeerCount(minPeers); syncConfig = syncConfigBuilder.build(); @@ -255,8 +270,11 @@ public void selectPivotBlockShouldWaitAndRetryIfSufficientChainHeightEstimatesAr assertThat(result).isCompletedWithValue(expected); } - @Test - public void selectPivotBlockShouldWaitAndRetryIfSufficientValidatedPeersUnavailable() { + @ParameterizedTest + @ArgumentsSource(FastSyncActionsTest.FastSyncActionsTestArguments.class) + public void selectPivotBlockShouldWaitAndRetryIfSufficientValidatedPeersUnavailable( + final DataStorageFormat storageFormat) { + setUp(storageFormat); final int minPeers = 3; final PeerValidator validator = mock(PeerValidator.class); syncConfigBuilder.fastSyncMinimumPeerCount(minPeers); @@ -304,18 +322,26 @@ public void selectPivotBlockShouldWaitAndRetryIfSufficientValidatedPeersUnavaila assertThat(result).isCompletedWithValue(expected); } - @Test - public void selectPivotBlockUsesBestPeerWithHeightEstimate() { + @ParameterizedTest + @ArgumentsSource(FastSyncActionsTest.FastSyncActionsTestArguments.class) + public void selectPivotBlockUsesBestPeerWithHeightEstimate( + final DataStorageFormat storageFormat) { + setUp(storageFormat); selectPivotBlockUsesBestPeerMatchingRequiredCriteria(true, false); } - @Test - public void selectPivotBlockUsesBestPeerThatIsValidated() { + @ParameterizedTest + @ArgumentsSource(FastSyncActionsTest.FastSyncActionsTestArguments.class) + public void selectPivotBlockUsesBestPeerThatIsValidated(final DataStorageFormat storageFormat) { + setUp(storageFormat); selectPivotBlockUsesBestPeerMatchingRequiredCriteria(false, true); } - @Test - public void selectPivotBlockUsesBestPeerThatIsValidatedAndHasHeightEstimate() { + @ParameterizedTest + @ArgumentsSource(FastSyncActionsTest.FastSyncActionsTestArguments.class) + public void selectPivotBlockUsesBestPeerThatIsValidatedAndHasHeightEstimate( + final DataStorageFormat storageFormat) { + setUp(storageFormat); selectPivotBlockUsesBestPeerMatchingRequiredCriteria(true, true); } @@ -369,8 +395,11 @@ private void selectPivotBlockUsesBestPeerMatchingRequiredCriteria( assertThat(result).isCompletedWithValue(expected); } - @Test - public void selectPivotBlockShouldWaitAndRetryIfBestPeerChainIsShorterThanPivotDistance() { + @ParameterizedTest + @ArgumentsSource(FastSyncActionsTest.FastSyncActionsTestArguments.class) + public void selectPivotBlockShouldWaitAndRetryIfBestPeerChainIsShorterThanPivotDistance( + final DataStorageFormat storageFormat) { + setUp(storageFormat); final int minPeers = 1; syncConfigBuilder.fastSyncMinimumPeerCount(minPeers); syncConfig = syncConfigBuilder.build(); @@ -396,8 +425,11 @@ public void selectPivotBlockShouldWaitAndRetryIfBestPeerChainIsShorterThanPivotD assertThat(result).isCompletedWithValue(expected); } - @Test - public void selectPivotBlockShouldRetryIfBestPeerChainIsEqualToPivotDistance() { + @ParameterizedTest + @ArgumentsSource(FastSyncActionsTest.FastSyncActionsTestArguments.class) + public void selectPivotBlockShouldRetryIfBestPeerChainIsEqualToPivotDistance( + final DataStorageFormat storageFormat) { + setUp(storageFormat); final long pivotDistance = syncConfig.getFastSyncPivotDistance(); EthProtocolManagerTestUtil.disableEthSchedulerAutoRun(ethProtocolManager); // Create peers with chains that are too short @@ -418,15 +450,21 @@ public void selectPivotBlockShouldRetryIfBestPeerChainIsEqualToPivotDistance() { assertThat(result).isCompletedWithValue(expected); } - @Test - public void downloadPivotBlockHeaderShouldUseExistingPivotBlockHeaderIfPresent() { + @ParameterizedTest + @ArgumentsSource(FastSyncActionsTest.FastSyncActionsTestArguments.class) + public void downloadPivotBlockHeaderShouldUseExistingPivotBlockHeaderIfPresent( + final DataStorageFormat storageFormat) { + setUp(storageFormat); final BlockHeader pivotHeader = new BlockHeaderTestFixture().number(1024).buildHeader(); final FastSyncState expected = new FastSyncState(pivotHeader); assertThat(fastSyncActions.downloadPivotBlockHeader(expected)).isCompletedWithValue(expected); } - @Test - public void downloadPivotBlockHeaderShouldRetrievePivotBlockHeader() { + @ParameterizedTest + @ArgumentsSource(FastSyncActionsTest.FastSyncActionsTestArguments.class) + public void downloadPivotBlockHeaderShouldRetrievePivotBlockHeader( + final DataStorageFormat storageFormat) { + setUp(storageFormat); syncConfig = SynchronizerConfiguration.builder().fastSyncMinimumPeerCount(1).build(); fastSyncActions = createFastSyncActions( @@ -444,8 +482,11 @@ public void downloadPivotBlockHeaderShouldRetrievePivotBlockHeader() { assertThat(result).isCompletedWithValue(new FastSyncState(blockchain.getBlockHeader(1).get())); } - @Test - public void downloadPivotBlockHeaderShouldRetrievePivotBlockHash() { + @ParameterizedTest + @ArgumentsSource(FastSyncActionsTest.FastSyncActionsTestArguments.class) + public void downloadPivotBlockHeaderShouldRetrievePivotBlockHash( + final DataStorageFormat storageFormat) { + setUp(storageFormat); syncConfig = SynchronizerConfiguration.builder().fastSyncMinimumPeerCount(1).build(); GenesisConfigOptions genesisConfig = mock(GenesisConfigOptions.class); when(genesisConfig.getTerminalBlockNumber()).thenReturn(OptionalLong.of(10L)); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java index 9f3031ab65d..d2c63a18a15 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java @@ -39,19 +39,17 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; -import java.util.Arrays; -import java.util.Collection; import java.util.concurrent.CompletableFuture; import java.util.concurrent.locks.LockSupport; +import java.util.stream.Stream; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; -@RunWith(Parameterized.class) public class FastSyncChainDownloaderTest { private final WorldStateStorage worldStateStorage = mock(WorldStateStorage.class); @@ -66,19 +64,15 @@ public class FastSyncChainDownloaderTest { private BlockchainSetupUtil otherBlockchainSetup; protected Blockchain otherBlockchain; - @Parameters - public static Collection data() { - return Arrays.asList(new Object[][] {{DataStorageFormat.BONSAI}, {DataStorageFormat.FOREST}}); - } - - private final DataStorageFormat storageFormat; - - public FastSyncChainDownloaderTest(final DataStorageFormat storageFormat) { - this.storageFormat = storageFormat; + static class FastSyncChainDownloaderTestArguments implements ArgumentsProvider { + @Override + public Stream provideArguments(final ExtensionContext context) { + return Stream.of( + Arguments.of(DataStorageFormat.BONSAI), Arguments.of(DataStorageFormat.FOREST)); + } } - @Before - public void setup() { + public void setup(final DataStorageFormat storageFormat) { when(worldStateStorage.isWorldStateAvailable(any(), any())).thenReturn(true); final BlockchainSetupUtil localBlockchainSetup = BlockchainSetupUtil.forTesting(storageFormat); localBlockchain = localBlockchainSetup.getBlockchain(); @@ -97,7 +91,7 @@ public void setup() { syncState = new SyncState(protocolContext.getBlockchain(), ethContext.getEthPeers()); } - @After + @AfterEach public void tearDown() { ethProtocolManager.stop(); } @@ -115,8 +109,10 @@ private ChainDownloader downloader( new FastSyncState(otherBlockchain.getBlockHeader(pivotBlockNumber).get())); } - @Test - public void shouldSyncToPivotBlockInMultipleSegments() { + @ParameterizedTest + @ArgumentsSource(FastSyncChainDownloaderTestArguments.class) + public void shouldSyncToPivotBlockInMultipleSegments(final DataStorageFormat storageFormat) { + setup(storageFormat); otherBlockchainSetup.importFirstBlocks(30); final RespondingEthPeer peer = @@ -141,8 +137,10 @@ public void shouldSyncToPivotBlockInMultipleSegments() { .isEqualTo(otherBlockchain.getBlockHeader(pivotBlockNumber).get()); } - @Test - public void shouldSyncToPivotBlockInSingleSegment() { + @ParameterizedTest + @ArgumentsSource(FastSyncChainDownloaderTestArguments.class) + public void shouldSyncToPivotBlockInSingleSegment(final DataStorageFormat storageFormat) { + setup(storageFormat); otherBlockchainSetup.importFirstBlocks(30); final RespondingEthPeer peer = @@ -163,8 +161,10 @@ public void shouldSyncToPivotBlockInSingleSegment() { .isEqualTo(otherBlockchain.getBlockHeader(pivotBlockNumber).get()); } - @Test - public void recoversFromSyncTargetDisconnect() { + @ParameterizedTest + @ArgumentsSource(FastSyncChainDownloaderTestArguments.class) + public void recoversFromSyncTargetDisconnect(final DataStorageFormat storageFormat) { + setup(storageFormat); final BlockchainSetupUtil shorterChainUtil = BlockchainSetupUtil.forTesting(storageFormat); final MutableBlockchain shorterChain = shorterChainUtil.getBlockchain(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloaderTest.java index 4dc88df2ad1..632fed6ede1 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloaderTest.java @@ -46,8 +46,8 @@ import java.util.function.Supplier; import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class FastSyncDownloaderTest { @@ -76,7 +76,7 @@ public class FastSyncDownloaderTest { fastSyncDataDirectory, FastSyncState.EMPTY_SYNC_STATE); - @Before + @BeforeEach public void setup() { when(worldStateStorage.getDataStorageFormat()).thenReturn(DataStorageFormat.FOREST); when(worldStateStorage.isWorldStateAvailable(any(), any())).thenReturn(true); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncStateStorageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncStateStorageTest.java index c8b7262a0ce..3b22b4a5649 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncStateStorageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncStateStorageTest.java @@ -20,25 +20,22 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; -import java.io.File; +import java.nio.file.Path; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; public class FastSyncStateStorageTest { - @Rule public final TemporaryFolder tempDirRule = new TemporaryFolder(); + @TempDir private Path tempDir; private FastSyncStateStorage storage; private final BlockHeader pivotBlockHeader = new BlockHeaderTestFixture().buildHeader(); private final FastSyncState syncStateWithHeader = new FastSyncState(pivotBlockHeader); - private File tempDir; - @Before + @BeforeEach public void setUp() throws Exception { - tempDir = tempDirRule.newFolder(); - storage = new FastSyncStateStorage(tempDir.toPath()); + storage = new FastSyncStateStorage(tempDir); } @Test @@ -51,7 +48,7 @@ public void shouldConsiderFastSyncInProgressWhenFileExists() { storage.storeState(syncStateWithHeader); assertThat(storage.isFastSyncInProgress()).isTrue(); - final FastSyncStateStorage newStorage = new FastSyncStateStorage(tempDir.toPath()); + final FastSyncStateStorage newStorage = new FastSyncStateStorage(tempDir); assertThat(newStorage.isFastSyncInProgress()).isTrue(); } @@ -60,7 +57,7 @@ public void shouldRoundTripHeader() { storage.storeState(syncStateWithHeader); assertThat(storage.loadState(new MainnetBlockHeaderFunctions())).isEqualTo(syncStateWithHeader); - final FastSyncStateStorage newStorage = new FastSyncStateStorage(tempDir.toPath()); + final FastSyncStateStorage newStorage = new FastSyncStateStorage(tempDir); assertThat(newStorage.loadState(new MainnetBlockHeaderFunctions())) .isEqualTo(syncStateWithHeader); } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncValidationPolicyTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncValidationPolicyTest.java index 98fa7dfbf02..d0d3e91c3ff 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncValidationPolicyTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncValidationPolicyTest.java @@ -22,7 +22,7 @@ import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class FastSyncValidationPolicyTest { @Test diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockConfirmerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockConfirmerTest.java index 741334643cb..08ce7e9d37f 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockConfirmerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockConfirmerTest.java @@ -36,20 +36,18 @@ import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; -import java.util.Arrays; -import java.util.Collection; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; -@RunWith(Parameterized.class) public class PivotBlockConfirmerTest { private static final long PIVOT_BLOCK_NUMBER = 10; @@ -64,19 +62,15 @@ public class PivotBlockConfirmerTest { private PivotBlockConfirmer pivotBlockConfirmer; private ProtocolSchedule protocolSchedule; - @Parameters - public static Collection data() { - return Arrays.asList(new Object[][] {{DataStorageFormat.BONSAI}, {DataStorageFormat.FOREST}}); - } - - private final DataStorageFormat storageFormat; - - public PivotBlockConfirmerTest(final DataStorageFormat storageFormat) { - this.storageFormat = storageFormat; + static class PivotBlockConfirmerTestArguments implements ArgumentsProvider { + @Override + public Stream provideArguments(final ExtensionContext context) { + return Stream.of( + Arguments.of(DataStorageFormat.BONSAI), Arguments.of(DataStorageFormat.FOREST)); + } } - @Before - public void setUp() { + public void setUp(final DataStorageFormat storageFormat) { final BlockchainSetupUtil blockchainSetupUtil = BlockchainSetupUtil.forTesting(storageFormat); blockchainSetupUtil.importAllBlocks(); blockchain = blockchainSetupUtil.getBlockchain(); @@ -107,8 +101,10 @@ private PivotBlockConfirmer createPivotBlockConfirmer( maxRetries)); } - @Test - public void completeSuccessfully() { + @ParameterizedTest + @ArgumentsSource(PivotBlockConfirmerTestArguments.class) + public void completeSuccessfully(final DataStorageFormat storageFormat) { + setUp(storageFormat); pivotBlockConfirmer = createPivotBlockConfirmer(2, 2); final Responder responder = @@ -136,8 +132,10 @@ public void completeSuccessfully() { new FastSyncState(blockchain.getBlockHeader(PIVOT_BLOCK_NUMBER).get())); } - @Test - public void delayedResponse() { + @ParameterizedTest + @ArgumentsSource(PivotBlockConfirmerTestArguments.class) + public void delayedResponse(final DataStorageFormat storageFormat) { + setUp(storageFormat); pivotBlockConfirmer = createPivotBlockConfirmer(2, 2); final Responder responder = @@ -169,8 +167,10 @@ public void delayedResponse() { new FastSyncState(blockchain.getBlockHeader(PIVOT_BLOCK_NUMBER).get())); } - @Test - public void peerTimesOutThenIsUnresponsive() { + @ParameterizedTest + @ArgumentsSource(PivotBlockConfirmerTestArguments.class) + public void peerTimesOutThenIsUnresponsive(final DataStorageFormat storageFormat) { + setUp(storageFormat); pivotBlockConfirmer = createPivotBlockConfirmer(2, 2); final Responder responder = @@ -209,8 +209,10 @@ public void peerTimesOutThenIsUnresponsive() { new FastSyncState(blockchain.getBlockHeader(PIVOT_BLOCK_NUMBER).get())); } - @Test - public void peerTimesOut() { + @ParameterizedTest + @ArgumentsSource(PivotBlockConfirmerTestArguments.class) + public void peerTimesOut(final DataStorageFormat storageFormat) { + setUp(storageFormat); pivotBlockConfirmer = createPivotBlockConfirmer(2, 2); final Responder responder = @@ -249,8 +251,10 @@ public void peerTimesOut() { new FastSyncState(blockchain.getBlockHeader(PIVOT_BLOCK_NUMBER).get())); } - @Test - public void peerUnresponsive() { + @ParameterizedTest + @ArgumentsSource(PivotBlockConfirmerTestArguments.class) + public void peerUnresponsive(final DataStorageFormat storageFormat) { + setUp(storageFormat); pivotBlockConfirmer = createPivotBlockConfirmer(2, 2); final Responder responder = @@ -291,8 +295,10 @@ public void peerUnresponsive() { new FastSyncState(blockchain.getBlockHeader(PIVOT_BLOCK_NUMBER).get())); } - @Test - public void headerMismatch() { + @ParameterizedTest + @ArgumentsSource(PivotBlockConfirmerTestArguments.class) + public void headerMismatch(final DataStorageFormat storageFormat) { + setUp(storageFormat); pivotBlockConfirmer = createPivotBlockConfirmer(3, 2); final Responder responderA = diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockRetrieverTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockRetrieverTest.java index 80bc2b9d2a4..7e539c8a596 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockRetrieverTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockRetrieverTest.java @@ -39,20 +39,18 @@ import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.util.ExceptionUtils; -import java.util.Arrays; -import java.util.Collection; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; -@RunWith(Parameterized.class) public class PivotBlockRetrieverTest { private static final long PIVOT_BLOCK_NUMBER = 10; @@ -67,19 +65,15 @@ public class PivotBlockRetrieverTest { private PivotBlockRetriever pivotBlockRetriever; private ProtocolSchedule protocolSchedule; - @Parameters - public static Collection data() { - return Arrays.asList(new Object[][] {{DataStorageFormat.BONSAI}, {DataStorageFormat.FOREST}}); - } - - private final DataStorageFormat storageFormat; - - public PivotBlockRetrieverTest(final DataStorageFormat storageFormat) { - this.storageFormat = storageFormat; + static class PivotBlockRetrieverTestArguments implements ArgumentsProvider { + @Override + public Stream provideArguments(final ExtensionContext context) { + return Stream.of( + Arguments.of(DataStorageFormat.BONSAI), Arguments.of(DataStorageFormat.FOREST)); + } } - @Before - public void setUp() { + public void setUp(final DataStorageFormat storageFormat) { final BlockchainSetupUtil blockchainSetupUtil = BlockchainSetupUtil.forTesting(storageFormat); blockchainSetupUtil.importAllBlocks(); blockchain = blockchainSetupUtil.getBlockchain(); @@ -112,8 +106,10 @@ private PivotBlockRetriever createPivotBlockRetriever( maxRetries)); } - @Test - public void shouldSucceedWhenAllPeersAgree() { + @ParameterizedTest + @ArgumentsSource(PivotBlockRetrieverTestArguments.class) + public void shouldSucceedWhenAllPeersAgree(final DataStorageFormat storageFormat) { + setUp(storageFormat); final RespondingEthPeer.Responder responder = RespondingEthPeer.blockchainResponder( blockchain, protocolContext.getWorldStateArchive(), transactionPool); @@ -134,8 +130,10 @@ public void shouldSucceedWhenAllPeersAgree() { new FastSyncState(blockchain.getBlockHeader(PIVOT_BLOCK_NUMBER).get())); } - @Test - public void shouldIgnorePeersThatDoNotHaveThePivotBlock() { + @ParameterizedTest + @ArgumentsSource(PivotBlockRetrieverTestArguments.class) + public void shouldIgnorePeersThatDoNotHaveThePivotBlock(final DataStorageFormat storageFormat) { + setUp(storageFormat); pivotBlockRetriever = createPivotBlockRetriever(3, 1, 1); EthProtocolManagerTestUtil.disableEthSchedulerAutoRun(ethProtocolManager); @@ -179,8 +177,10 @@ public void shouldIgnorePeersThatDoNotHaveThePivotBlock() { new FastSyncState(blockchain.getBlockHeader(PIVOT_BLOCK_NUMBER).get())); } - @Test - public void shouldIgnorePeersThatAreNotFullyValidated() { + @ParameterizedTest + @ArgumentsSource(PivotBlockRetrieverTestArguments.class) + public void shouldIgnorePeersThatAreNotFullyValidated(final DataStorageFormat storageFormat) { + setUp(storageFormat); final PeerValidator peerValidator = mock(PeerValidator.class); final RespondingEthPeer.Responder responder = RespondingEthPeer.blockchainResponder( @@ -237,8 +237,10 @@ public void shouldIgnorePeersThatAreNotFullyValidated() { new FastSyncState(blockchain.getBlockHeader(PIVOT_BLOCK_NUMBER).get())); } - @Test - public void shouldQueryBestPeersFirst() { + @ParameterizedTest + @ArgumentsSource(PivotBlockRetrieverTestArguments.class) + public void shouldQueryBestPeersFirst(final DataStorageFormat storageFormat) { + setUp(storageFormat); pivotBlockRetriever = createPivotBlockRetriever(2, 1, 1); EthProtocolManagerTestUtil.disableEthSchedulerAutoRun(ethProtocolManager); @@ -265,8 +267,10 @@ public void shouldQueryBestPeersFirst() { new FastSyncState(blockchain.getBlockHeader(PIVOT_BLOCK_NUMBER).get())); } - @Test - public void shouldRecoverFromUnresponsivePeer() { + @ParameterizedTest + @ArgumentsSource(PivotBlockRetrieverTestArguments.class) + public void shouldRecoverFromUnresponsivePeer(final DataStorageFormat storageFormat) { + setUp(storageFormat); pivotBlockRetriever = createPivotBlockRetriever(2, 1, 1); EthProtocolManagerTestUtil.disableEthSchedulerAutoRun(ethProtocolManager); @@ -300,8 +304,11 @@ public void shouldRecoverFromUnresponsivePeer() { new FastSyncState(blockchain.getBlockHeader(PIVOT_BLOCK_NUMBER).get())); } - @Test - public void shouldRetryWhenPeersDisagreeOnPivot_successfulRetry() { + @ParameterizedTest + @ArgumentsSource(PivotBlockRetrieverTestArguments.class) + public void shouldRetryWhenPeersDisagreeOnPivot_successfulRetry( + final DataStorageFormat storageFormat) { + setUp(storageFormat); final long pivotBlockDelta = 1; pivotBlockRetriever = createPivotBlockRetriever(2, pivotBlockDelta, 1); @@ -334,8 +341,11 @@ public void shouldRetryWhenPeersDisagreeOnPivot_successfulRetry() { .isCompletedWithValue(new FastSyncState(blockchain.getBlockHeader(newPivotBlock).get())); } - @Test - public void shouldRetryWhenPeersDisagreeOnPivot_exceedMaxRetries() { + @ParameterizedTest + @ArgumentsSource(PivotBlockRetrieverTestArguments.class) + public void shouldRetryWhenPeersDisagreeOnPivot_exceedMaxRetries( + final DataStorageFormat storageFormat) { + setUp(storageFormat); final long pivotBlockDelta = 1; pivotBlockRetriever = createPivotBlockRetriever(2, pivotBlockDelta, 1); @@ -371,8 +381,11 @@ public void shouldRetryWhenPeersDisagreeOnPivot_exceedMaxRetries() { .isEqualTo(FastSyncError.PIVOT_BLOCK_HEADER_MISMATCH); } - @Test - public void shouldRetryWhenPeersDisagreeOnPivot_pivotInvalidOnRetry() { + @ParameterizedTest + @ArgumentsSource(PivotBlockRetrieverTestArguments.class) + public void shouldRetryWhenPeersDisagreeOnPivot_pivotInvalidOnRetry( + final DataStorageFormat storageFormat) { + setUp(storageFormat); final long pivotBlockDelta = PIVOT_BLOCK_NUMBER + 1; pivotBlockRetriever = createPivotBlockRetriever(2, pivotBlockDelta, 1); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/CompleteTaskStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/CompleteTaskStepTest.java index e24a3420269..c984f0575d9 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/CompleteTaskStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/CompleteTaskStepTest.java @@ -27,7 +27,7 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class CompleteTaskStepTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldDownloadStateTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldDownloadStateTest.java index 0a774292fd7..b8531288276 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldDownloadStateTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldDownloadStateTest.java @@ -35,20 +35,18 @@ import org.hyperledger.besu.services.tasks.InMemoryTasksPriorityQueues; import org.hyperledger.besu.testutil.TestClock; -import java.util.Arrays; -import java.util.Collection; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; -@RunWith(Parameterized.class) public class FastWorldDownloadStateTest { private static final Bytes ROOT_NODE_DATA = Bytes.of(1, 2, 3, 4); @@ -70,19 +68,15 @@ public class FastWorldDownloadStateTest { private CompletableFuture future; - @Parameterized.Parameters - public static Collection data() { - return Arrays.asList(new Object[][] {{DataStorageFormat.BONSAI}, {DataStorageFormat.FOREST}}); - } - - private final DataStorageFormat storageFormat; - - public FastWorldDownloadStateTest(final DataStorageFormat storageFormat) { - this.storageFormat = storageFormat; + static class FastWorldDownloadStateTestArguments implements ArgumentsProvider { + @Override + public Stream provideArguments(final ExtensionContext context) { + return Stream.of( + Arguments.of(DataStorageFormat.BONSAI), Arguments.of(DataStorageFormat.FOREST)); + } } - @Before - public void setUp() { + public void setUp(final DataStorageFormat storageFormat) { if (storageFormat == DataStorageFormat.BONSAI) { worldStateStorage = new BonsaiWorldStateKeyValueStorage( @@ -102,16 +96,22 @@ public void setUp() { future = downloadState.getDownloadFuture(); } - @Test - public void shouldCompleteReturnedFutureWhenNoPendingTasksRemain() { + @ParameterizedTest + @ArgumentsSource(FastWorldDownloadStateTestArguments.class) + public void shouldCompleteReturnedFutureWhenNoPendingTasksRemain( + final DataStorageFormat storageFormat) { + setUp(storageFormat); downloadState.checkCompletion(header); assertThat(future).isCompleted(); assertThat(downloadState.isDownloading()).isFalse(); } - @Test - public void shouldStoreRootNodeBeforeReturnedFutureCompletes() { + @ParameterizedTest + @ArgumentsSource(FastWorldDownloadStateTestArguments.class) + public void shouldStoreRootNodeBeforeReturnedFutureCompletes( + final DataStorageFormat storageFormat) { + setUp(storageFormat); final CompletableFuture postFutureChecks = future.thenAccept( result -> @@ -124,8 +124,10 @@ public void shouldStoreRootNodeBeforeReturnedFutureCompletes() { assertThat(postFutureChecks).isCompleted(); } - @Test - public void shouldNotCompleteWhenThereArePendingTasks() { + @ParameterizedTest + @ArgumentsSource(FastWorldDownloadStateTestArguments.class) + public void shouldNotCompleteWhenThereArePendingTasks(final DataStorageFormat storageFormat) { + setUp(storageFormat); pendingRequests.add( NodeDataRequest.createAccountDataRequest(Hash.EMPTY_TRIE_HASH, Optional.empty())); @@ -136,8 +138,11 @@ public void shouldNotCompleteWhenThereArePendingTasks() { assertThat(downloadState.isDownloading()).isTrue(); } - @Test - public void shouldCancelOutstandingTasksWhenFutureIsCancelled() { + @ParameterizedTest + @ArgumentsSource(FastWorldDownloadStateTestArguments.class) + public void shouldCancelOutstandingTasksWhenFutureIsCancelled( + final DataStorageFormat storageFormat) { + setUp(storageFormat); final EthTask outstandingTask1 = mock(EthTask.class); final EthTask outstandingTask2 = mock(EthTask.class); downloadState.addOutstandingTask(outstandingTask1); @@ -158,8 +163,11 @@ public void shouldCancelOutstandingTasksWhenFutureIsCancelled() { assertThat(downloadState.isDownloading()).isFalse(); } - @Test - public void shouldResetRequestsSinceProgressCountWhenProgressIsMade() { + @ParameterizedTest + @ArgumentsSource(FastWorldDownloadStateTestArguments.class) + public void shouldResetRequestsSinceProgressCountWhenProgressIsMade( + final DataStorageFormat storageFormat) { + setUp(storageFormat); downloadState.requestComplete(false); downloadState.requestComplete(false); @@ -175,8 +183,11 @@ public void shouldResetRequestsSinceProgressCountWhenProgressIsMade() { assertWorldStateStalled(downloadState); } - @Test - public void shouldNotBeStalledWhenMaxRequestsReachedUntilMinimumTimeAlsoReached() { + @ParameterizedTest + @ArgumentsSource(FastWorldDownloadStateTestArguments.class) + public void shouldNotBeStalledWhenMaxRequestsReachedUntilMinimumTimeAlsoReached( + final DataStorageFormat storageFormat) { + setUp(storageFormat); for (int i = 0; i < MAX_REQUESTS_WITHOUT_PROGRESS; i++) { downloadState.requestComplete(false); assertThat(downloadState.getDownloadFuture()).isNotDone(); @@ -192,15 +203,21 @@ public void shouldNotBeStalledWhenMaxRequestsReachedUntilMinimumTimeAlsoReached( assertWorldStateStalled(downloadState); } - @Test - public void shouldNotBeStalledIfMinimumTimeIsReachedButMaximumRequestsIsNot() { + @ParameterizedTest + @ArgumentsSource(FastWorldDownloadStateTestArguments.class) + public void shouldNotBeStalledIfMinimumTimeIsReachedButMaximumRequestsIsNot( + final DataStorageFormat storageFormat) { + setUp(storageFormat); clock.stepMillis(MIN_MILLIS_BEFORE_STALLING + 1); downloadState.requestComplete(false); assertThat(downloadState.getDownloadFuture()).isNotDone(); } - @Test - public void shouldResetTimeSinceProgressWhenProgressIsMade() { + @ParameterizedTest + @ArgumentsSource(FastWorldDownloadStateTestArguments.class) + public void shouldResetTimeSinceProgressWhenProgressIsMade( + final DataStorageFormat storageFormat) { + setUp(storageFormat); // Enough time has progressed but the next request makes progress so we are not stalled. clock.stepMillis(MIN_MILLIS_BEFORE_STALLING + 1); downloadState.requestComplete(true); @@ -214,8 +231,10 @@ public void shouldResetTimeSinceProgressWhenProgressIsMade() { assertThat(downloadState.getDownloadFuture()).isNotDone(); } - @Test - public void shouldNotAddRequestsAfterDownloadIsCompleted() { + @ParameterizedTest + @ArgumentsSource(FastWorldDownloadStateTestArguments.class) + public void shouldNotAddRequestsAfterDownloadIsCompleted(final DataStorageFormat storageFormat) { + setUp(storageFormat); downloadState.checkCompletion(header); downloadState.enqueueRequests( diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldStateDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldStateDownloaderTest.java index fec755a8849..74c6364383e 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldStateDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldStateDownloaderTest.java @@ -93,17 +93,14 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.After; -import org.junit.Ignore; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.Timeout; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; -@Ignore("PIE-1434 - Ignored while working to make test more reliable") +@Disabled("PIE-1434 - Ignored while working to make test more reliable") public class FastWorldStateDownloaderTest { - @Rule public Timeout globalTimeout = Timeout.seconds(60); // 1 minute max per test - private static final Hash EMPTY_TRIE_ROOT = Hash.wrap(MerkleTrie.EMPTY_TRIE_NODE_HASH); private final BlockDataGenerator dataGen = new BlockDataGenerator(1); @@ -117,7 +114,7 @@ public class FastWorldStateDownloaderTest { final EthProtocolManager ethProtocolManager = EthProtocolManagerTestUtil.create(new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem())); - @After + @AfterEach public void tearDown() throws Exception { persistenceThread.shutdownNow(); assertThat(persistenceThread.awaitTermination(10, TimeUnit.SECONDS)).isTrue(); @@ -125,36 +122,43 @@ public void tearDown() throws Exception { } @Test + @Timeout(value = 60) public void downloadWorldStateFromPeers_onePeerOneWithManyRequestsOneAtATime() { downloadAvailableWorldStateFromPeers(1, 50, 1, 1); } @Test + @Timeout(value = 60) public void downloadWorldStateFromPeers_onePeerOneWithManyRequests() { downloadAvailableWorldStateFromPeers(1, 50, 1, 10); } @Test + @Timeout(value = 60) public void downloadWorldStateFromPeers_onePeerWithSingleRequest() { downloadAvailableWorldStateFromPeers(1, 1, 100, 10); } @Test + @Timeout(value = 60) public void downloadWorldStateFromPeers_largeStateFromMultiplePeers() { downloadAvailableWorldStateFromPeers(5, 100, 10, 10); } @Test + @Timeout(value = 60) public void downloadWorldStateFromPeers_smallStateFromMultiplePeers() { downloadAvailableWorldStateFromPeers(5, 5, 1, 10); } @Test + @Timeout(value = 60) public void downloadWorldStateFromPeers_singleRequestWithMultiplePeers() { downloadAvailableWorldStateFromPeers(5, 1, 50, 50); } @Test + @Timeout(value = 60) public void downloadEmptyWorldState() { final BlockHeader header = @@ -188,6 +192,7 @@ public void downloadEmptyWorldState() { } @Test + @Timeout(value = 60) public void downloadAlreadyAvailableWorldState() { // Setup existing state final DefaultWorldStateArchive worldStateArchive = createInMemoryWorldStateArchive(); @@ -227,6 +232,7 @@ public void downloadAlreadyAvailableWorldState() { } @Test + @Timeout(value = 60) public void canRecoverFromTimeouts() { final DeterministicEthScheduler.TimeoutPolicy timeoutPolicy = DeterministicEthScheduler.TimeoutPolicy.timeoutXTimes(2); @@ -282,11 +288,13 @@ public void canRecoverFromTimeouts() { } @Test + @Timeout(value = 60) public void handlesPartialResponsesFromNetwork() { downloadAvailableWorldStateFromPeers(5, 100, 10, 10, this::respondPartially); } @Test + @Timeout(value = 60) public void doesNotRequestKnownCodeFromNetwork() { // Setup "remote" state final WorldStateArchive remoteWorldStateArchive = createInMemoryWorldStateArchive(); @@ -353,11 +361,13 @@ public void doesNotRequestKnownCodeFromNetwork() { } @Test + @Timeout(value = 60) public void cancelDownloader() { testCancellation(false); } @Test + @Timeout(value = 60) public void cancelDownloaderFuture() { testCancellation(true); } @@ -441,6 +451,7 @@ private void testCancellation(final boolean shouldCancelFuture) { } @Test + @Timeout(value = 60) public void doesNotRequestKnownAccountTrieNodesFromNetwork() { // Setup "remote" state final WorldStateStorage remoteStorage = @@ -524,6 +535,7 @@ public void doesNotRequestKnownAccountTrieNodesFromNetwork() { } @Test + @Timeout(value = 60) public void doesNotRequestKnownStorageTrieNodesFromNetwork() { // Setup "remote" state final WorldStateStorage remoteStorage = @@ -625,6 +637,7 @@ public void doesNotRequestKnownStorageTrieNodesFromNetwork() { } @Test + @Timeout(value = 60) public void stalledDownloader() { final EthProtocolManager ethProtocolManager = EthProtocolManagerTestUtil.create(new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem())); @@ -688,6 +701,7 @@ public void stalledDownloader() { } @Test + @Timeout(value = 60) public void resumesFromNonEmptyQueue() { // Setup "remote" state final WorldStateStorage remoteStorage = diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/LoadLocalDataStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/LoadLocalDataStepTest.java index cb75570581e..625b3f72eaa 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/LoadLocalDataStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/LoadLocalDataStepTest.java @@ -31,7 +31,7 @@ import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; public class LoadLocalDataStepTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/NodeDataRequestTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/NodeDataRequestTest.java index 905d87d0e27..3e4e4d69905 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/NodeDataRequestTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/NodeDataRequestTest.java @@ -20,7 +20,7 @@ import java.util.Optional; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class NodeDataRequestTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStepTest.java index 693623d4c7b..e857648f7fc 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStepTest.java @@ -35,7 +35,7 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PersistDataStepTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/RequestDataStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/RequestDataStepTest.java index 1173c6e5f77..14669f62cb3 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/RequestDataStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/RequestDataStepTest.java @@ -37,8 +37,8 @@ import com.google.common.collect.ImmutableMap; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class RequestDataStepTest { @@ -62,7 +62,7 @@ public class RequestDataStepTest { private final RequestDataStep requestDataStep = new RequestDataStep(getNodeDataTaskFactory); - @Before + @BeforeEach public void setUp() { when(ethTask.run()).thenReturn(getDataFuture); } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/BetterSyncTargetEvaluatorTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/BetterSyncTargetEvaluatorTest.java index c552f1033ae..9acf45965d6 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/BetterSyncTargetEvaluatorTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/BetterSyncTargetEvaluatorTest.java @@ -28,8 +28,8 @@ import java.util.Optional; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class BetterSyncTargetEvaluatorTest { @@ -47,7 +47,7 @@ public class BetterSyncTargetEvaluatorTest { .build(), ethPeers); - @Before + @BeforeEach public void setupMocks() { when(ethPeers.getBestChainComparator()).thenReturn(EthPeers.HEAVIEST_CHAIN); } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullImportBlockStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullImportBlockStepTest.java index ddb8695b32f..dac31f2a72d 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullImportBlockStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullImportBlockStepTest.java @@ -30,13 +30,13 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class FullImportBlockStepTest { @Mock private ProtocolSchedule protocolSchedule; @@ -47,7 +47,7 @@ public class FullImportBlockStepTest { private FullImportBlockStep importBlocksStep; - @Before + @BeforeEach public void setUp() { when(protocolSchedule.getByBlockHeader(any(BlockHeader.class))).thenReturn(protocolSpec); when(protocolSpec.getBlockImporter()).thenReturn(blockImporter); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderForkTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderForkTest.java index cda6e900932..00a0e6d628f 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderForkTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderForkTest.java @@ -35,9 +35,11 @@ import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import java.io.IOException; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class FullSyncChainDownloaderForkTest { @@ -53,8 +55,8 @@ public class FullSyncChainDownloaderForkTest { protected Blockchain otherBlockchain; private final MetricsSystem metricsSystem = new NoOpMetricsSystem(); - @Before - public void setupTest() { + @BeforeEach + public void setupTest() throws IOException { localBlockchainSetup = BlockchainSetupUtil.forUpgradedFork(); localBlockchain = localBlockchainSetup.getBlockchain(); otherBlockchainSetup = BlockchainSetupUtil.forOutdatedFork(); @@ -74,7 +76,7 @@ public void setupTest() { syncState = new SyncState(protocolContext.getBlockchain(), ethContext.getEthPeers()); } - @After + @AfterEach public void tearDown() { ethProtocolManager.stop(); } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTest.java index f9c4cb1e9fa..b7588d1b4f9 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTest.java @@ -47,22 +47,20 @@ import org.hyperledger.besu.plugin.services.MetricsSystem; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.function.Function; +import java.util.stream.Stream; import org.awaitility.Awaitility; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -@RunWith(Parameterized.class) +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; + public class FullSyncChainDownloaderTest { protected ProtocolSchedule protocolSchedule; @@ -78,19 +76,15 @@ public class FullSyncChainDownloaderTest { protected Blockchain otherBlockchain; private final MetricsSystem metricsSystem = new NoOpMetricsSystem(); - @Parameters - public static Collection data() { - return Arrays.asList(new Object[][] {{DataStorageFormat.BONSAI}, {DataStorageFormat.FOREST}}); - } - - private final DataStorageFormat storageFormat; - - public FullSyncChainDownloaderTest(final DataStorageFormat storageFormat) { - this.storageFormat = storageFormat; + static class FullSyncChainDownloaderTestArguments implements ArgumentsProvider { + @Override + public Stream provideArguments(final ExtensionContext context) { + return Stream.of( + Arguments.of(DataStorageFormat.BONSAI), Arguments.of(DataStorageFormat.FOREST)); + } } - @Before - public void setupTest() { + public void setupTest(final DataStorageFormat storageFormat) { gen = new BlockDataGenerator(); localBlockchainSetup = BlockchainSetupUtil.forTesting(storageFormat); localBlockchain = localBlockchainSetup.getBlockchain(); @@ -111,7 +105,7 @@ public void setupTest() { syncState = new SyncState(protocolContext.getBlockchain(), ethContext.getEthPeers()); } - @After + @AfterEach public void tearDown() { ethProtocolManager.stop(); } @@ -136,8 +130,10 @@ private SynchronizerConfiguration.Builder syncConfigBuilder() { return SynchronizerConfiguration.builder(); } - @Test - public void syncsToBetterChain_multipleSegments() { + @ParameterizedTest + @ArgumentsSource(FullSyncChainDownloaderTestArguments.class) + public void syncsToBetterChain_multipleSegments(final DataStorageFormat storageFormat) { + setupTest(storageFormat); otherBlockchainSetup.importFirstBlocks(15); final long targetBlock = otherBlockchain.getChainHeadBlockNumber(); // Sanity check @@ -163,8 +159,10 @@ public void syncsToBetterChain_multipleSegments() { assertThat(localBlockchain.getChainHeadBlockNumber()).isEqualTo(targetBlock); } - @Test - public void syncsToBetterChain_singleSegment() { + @ParameterizedTest + @ArgumentsSource(FullSyncChainDownloaderTestArguments.class) + public void syncsToBetterChain_singleSegment(final DataStorageFormat storageFormat) { + setupTest(storageFormat); otherBlockchainSetup.importFirstBlocks(5); final long targetBlock = otherBlockchain.getChainHeadBlockNumber(); // Sanity check @@ -190,8 +188,10 @@ public void syncsToBetterChain_singleSegment() { assertThat(localBlockchain.getChainHeadBlockNumber()).isEqualTo(targetBlock); } - @Test - public void syncsToBetterChain_singleSegmentOnBoundary() { + @ParameterizedTest + @ArgumentsSource(FullSyncChainDownloaderTestArguments.class) + public void syncsToBetterChain_singleSegmentOnBoundary(final DataStorageFormat storageFormat) { + setupTest(storageFormat); otherBlockchainSetup.importFirstBlocks(5); final long targetBlock = otherBlockchain.getChainHeadBlockNumber(); // Sanity check @@ -217,8 +217,10 @@ public void syncsToBetterChain_singleSegmentOnBoundary() { assertThat(localBlockchain.getChainHeadBlockNumber()).isEqualTo(targetBlock); } - @Test - public void doesNotSyncToWorseChain() { + @ParameterizedTest + @ArgumentsSource(FullSyncChainDownloaderTestArguments.class) + public void doesNotSyncToWorseChain(final DataStorageFormat storageFormat) { + setupTest(storageFormat); localBlockchainSetup.importFirstBlocks(15); // Sanity check assertThat(localBlockchain.getChainHeadBlockNumber()) @@ -240,8 +242,10 @@ public void doesNotSyncToWorseChain() { assertThat(syncState.syncTarget()).isNotPresent(); } - @Test - public void syncsToBetterChain_fromFork() { + @ParameterizedTest + @ArgumentsSource(FullSyncChainDownloaderTestArguments.class) + public void syncsToBetterChain_fromFork(final DataStorageFormat storageFormat) { + setupTest(storageFormat); otherBlockchainSetup.importFirstBlocks(15); final long targetBlock = otherBlockchain.getChainHeadBlockNumber(); @@ -278,8 +282,10 @@ public void syncsToBetterChain_fromFork() { assertThat(localBlockchain.getChainHeadBlockNumber()).isEqualTo(targetBlock); } - @Test - public void choosesBestPeerAsSyncTarget_byTd() { + @ParameterizedTest + @ArgumentsSource(FullSyncChainDownloaderTestArguments.class) + public void choosesBestPeerAsSyncTarget_byTd(final DataStorageFormat storageFormat) { + setupTest(storageFormat); final Difficulty localTd = localBlockchain.getChainHead().getTotalDifficulty(); final RespondingEthPeer.Responder responder = @@ -300,8 +306,10 @@ public void choosesBestPeerAsSyncTarget_byTd() { assertThat(syncState.syncTarget().get().peer()).isEqualTo(peerB.getEthPeer()); } - @Test - public void choosesBestPeerAsSyncTarget_byTdAndHeight() { + @ParameterizedTest + @ArgumentsSource(FullSyncChainDownloaderTestArguments.class) + public void choosesBestPeerAsSyncTarget_byTdAndHeight(final DataStorageFormat storageFormat) { + setupTest(storageFormat); final Difficulty localTd = localBlockchain.getChainHead().getTotalDifficulty(); final RespondingEthPeer.Responder responder = @@ -322,8 +330,10 @@ public void choosesBestPeerAsSyncTarget_byTdAndHeight() { assertThat(syncState.syncTarget().get().peer()).isEqualTo(peerB.getEthPeer()); } - @Test - public void recoversFromSyncTargetDisconnect() { + @ParameterizedTest + @ArgumentsSource(FullSyncChainDownloaderTestArguments.class) + public void recoversFromSyncTargetDisconnect(final DataStorageFormat storageFormat) { + setupTest(storageFormat); localBlockchainSetup.importFirstBlocks(2); final long localChainHeadAtStart = localBlockchain.getChainHeadBlockNumber(); otherBlockchainSetup.importAllBlocks(); @@ -393,8 +403,10 @@ public void recoversFromSyncTargetDisconnect() { assertThat(localBlockchain.getChainHeadBlockNumber()).isEqualTo(secondBestPeerChainHead); } - @Test - public void requestsCheckpointsFromSyncTarget() { + @ParameterizedTest + @ArgumentsSource(FullSyncChainDownloaderTestArguments.class) + public void requestsCheckpointsFromSyncTarget(final DataStorageFormat storageFormat) { + setupTest(storageFormat); localBlockchainSetup.importFirstBlocks(2); otherBlockchainSetup.importAllBlocks(); final long targetBlock = otherBlockchain.getChainHeadBlockNumber(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTotalTerminalDifficultyTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTotalTerminalDifficultyTest.java index 1ec29f6994f..c86be6d6407 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTotalTerminalDifficultyTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTotalTerminalDifficultyTest.java @@ -35,18 +35,16 @@ import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; -import java.util.Arrays; -import java.util.Collection; import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; -@RunWith(Parameterized.class) public class FullSyncChainDownloaderTotalTerminalDifficultyTest { protected ProtocolSchedule protocolSchedule; @@ -62,19 +60,16 @@ public class FullSyncChainDownloaderTotalTerminalDifficultyTest { private final MetricsSystem metricsSystem = new NoOpMetricsSystem(); private static final Difficulty TARGET_TERMINAL_DIFFICULTY = Difficulty.of(1_000_000L); - @Parameters - public static Collection data() { - return Arrays.asList(new Object[][] {{DataStorageFormat.BONSAI}, {DataStorageFormat.FOREST}}); + static class FullSyncChainDownloaderTotalTerminalDifficultyTestArguments + implements ArgumentsProvider { + @Override + public Stream provideArguments(final ExtensionContext context) { + return Stream.of( + Arguments.of(DataStorageFormat.BONSAI), Arguments.of(DataStorageFormat.FOREST)); + } } - private final DataStorageFormat storageFormat; - - public FullSyncChainDownloaderTotalTerminalDifficultyTest(final DataStorageFormat storageFormat) { - this.storageFormat = storageFormat; - } - - @Before - public void setupTest() { + public void setupTest(final DataStorageFormat storageFormat) { localBlockchainSetup = BlockchainSetupUtil.forTesting(storageFormat); localBlockchain = localBlockchainSetup.getBlockchain(); otherBlockchainSetup = BlockchainSetupUtil.forTesting(storageFormat); @@ -94,7 +89,7 @@ public void setupTest() { syncState = new SyncState(protocolContext.getBlockchain(), ethContext.getEthPeers()); } - @After + @AfterEach public void tearDown() { ethProtocolManager.stop(); } @@ -116,8 +111,10 @@ private SynchronizerConfiguration.Builder syncConfigBuilder() { return SynchronizerConfiguration.builder(); } - @Test - public void syncsFullyAndStopsWhenTTDReached() { + @ParameterizedTest + @ArgumentsSource(FullSyncChainDownloaderTotalTerminalDifficultyTestArguments.class) + public void syncsFullyAndStopsWhenTTDReached(final DataStorageFormat storageFormat) { + setupTest(storageFormat); otherBlockchainSetup.importFirstBlocks(30); final long targetBlock = otherBlockchain.getChainHeadBlockNumber(); // Sanity check @@ -150,8 +147,10 @@ public void syncsFullyAndStopsWhenTTDReached() { assertThat(future.isDone()).isTrue(); } - @Test - public void syncsFullyAndContinuesWhenTTDNotSpecified() { + @ParameterizedTest + @ArgumentsSource(FullSyncChainDownloaderTotalTerminalDifficultyTestArguments.class) + public void syncsFullyAndContinuesWhenTTDNotSpecified(final DataStorageFormat storageFormat) { + setupTest(storageFormat); otherBlockchainSetup.importFirstBlocks(30); final long targetBlock = otherBlockchain.getChainHeadBlockNumber(); // Sanity check diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloaderTest.java index 65e81aafe32..aff0195db2d 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloaderTest.java @@ -33,17 +33,15 @@ import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; -import java.util.Arrays; -import java.util.Collection; +import java.util.stream.Stream; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; -@RunWith(Parameterized.class) public class FullSyncDownloaderTest { protected ProtocolSchedule protocolSchedule; @@ -56,19 +54,15 @@ public class FullSyncDownloaderTest { protected MutableBlockchain localBlockchain; private final MetricsSystem metricsSystem = new NoOpMetricsSystem(); - @Parameters - public static Collection data() { - return Arrays.asList(new Object[][] {{DataStorageFormat.BONSAI}, {DataStorageFormat.FOREST}}); + static class FullSyncDownloaderTestArguments implements ArgumentsProvider { + @Override + public Stream provideArguments(final ExtensionContext context) { + return Stream.of( + Arguments.of(DataStorageFormat.BONSAI), Arguments.of(DataStorageFormat.FOREST)); + } } - private final DataStorageFormat storageFormat; - - public FullSyncDownloaderTest(final DataStorageFormat storageFormat) { - this.storageFormat = storageFormat; - } - - @Before - public void setupTest() { + public void setupTest(final DataStorageFormat storageFormat) { localBlockchainSetup = BlockchainSetupUtil.forTesting(storageFormat); localBlockchain = localBlockchainSetup.getBlockchain(); @@ -86,7 +80,7 @@ public void setupTest() { syncState = new SyncState(protocolContext.getBlockchain(), ethContext.getEthPeers()); } - @After + @AfterEach public void tearDown() { ethProtocolManager.stop(); } @@ -102,8 +96,10 @@ private FullSyncDownloader downloader(final SynchronizerConfiguration syncConfig SyncTerminationCondition.never()); } - @Test - public void shouldLimitTrailingPeersWhenBehindChain() { + @ParameterizedTest + @ArgumentsSource(FullSyncDownloaderTestArguments.class) + public void shouldLimitTrailingPeersWhenBehindChain(final DataStorageFormat storageFormat) { + setupTest(storageFormat); localBlockchainSetup.importFirstBlocks(2); final int maxTailingPeers = 5; final FullSyncDownloader synchronizer = @@ -118,8 +114,10 @@ public void shouldLimitTrailingPeersWhenBehindChain() { assertThat(synchronizer.calculateTrailingPeerRequirements()).isEqualTo(expected); } - @Test - public void shouldNotLimitTrailingPeersWhenInSync() { + @ParameterizedTest + @ArgumentsSource(FullSyncDownloaderTestArguments.class) + public void shouldNotLimitTrailingPeersWhenInSync(final DataStorageFormat storageFormat) { + setupTest(storageFormat); localBlockchainSetup.importFirstBlocks(2); final int maxTailingPeers = 5; final FullSyncDownloader synchronizer = diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java index 29d9baca5e0..790e17998a3 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java @@ -38,18 +38,17 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; -import java.util.Arrays; -import java.util.Collection; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; -@RunWith(Parameterized.class) public class FullSyncTargetManagerTest { private EthProtocolManager ethProtocolManager; @@ -59,19 +58,15 @@ public class FullSyncTargetManagerTest { private RespondingEthPeer.Responder responder; private FullSyncTargetManager syncTargetManager; - @Parameterized.Parameters - public static Collection data() { - return Arrays.asList(new Object[][] {{DataStorageFormat.BONSAI}, {DataStorageFormat.FOREST}}); + static class FullSyncTargetManagerTestArguments implements ArgumentsProvider { + @Override + public Stream provideArguments(final ExtensionContext context) { + return Stream.of( + Arguments.of(DataStorageFormat.BONSAI), Arguments.of(DataStorageFormat.FOREST)); + } } - private final DataStorageFormat storageFormat; - - public FullSyncTargetManagerTest(final DataStorageFormat storageFormat) { - this.storageFormat = storageFormat; - } - - @Before - public void setup() { + public void setup(final DataStorageFormat storageFormat) { final BlockchainSetupUtil otherBlockchainSetup = BlockchainSetupUtil.forTesting(storageFormat); final Blockchain otherBlockchain = otherBlockchainSetup.getBlockchain(); responder = RespondingEthPeer.blockchainResponder(otherBlockchain); @@ -103,13 +98,15 @@ public void setup() { SyncTerminationCondition.never()); } - @After + @AfterEach public void tearDown() { ethProtocolManager.stop(); } - @Test - public void findSyncTarget_withHeightEstimates() { + @ParameterizedTest + @ArgumentsSource(FullSyncTargetManagerTest.FullSyncTargetManagerTestArguments.class) + public void findSyncTarget_withHeightEstimates(final DataStorageFormat storageFormat) { + setup(storageFormat); final BlockHeader chainHeadHeader = localBlockchain.getChainHeadHeader(); when(localWorldState.isWorldStateAvailable( chainHeadHeader.getStateRoot(), chainHeadHeader.getHash())) @@ -125,8 +122,10 @@ public void findSyncTarget_withHeightEstimates() { new SyncTarget(bestPeer.getEthPeer(), localBlockchain.getBlockHeader(4L).get())); } - @Test - public void findSyncTarget_noHeightEstimates() { + @ParameterizedTest + @ArgumentsSource(FullSyncTargetManagerTest.FullSyncTargetManagerTestArguments.class) + public void findSyncTarget_noHeightEstimates(final DataStorageFormat storageFormat) { + setup(storageFormat); final BlockHeader chainHeadHeader = localBlockchain.getChainHeadHeader(); when(localWorldState.isWorldStateAvailable( chainHeadHeader.getStateRoot(), chainHeadHeader.getHash())) @@ -140,8 +139,11 @@ public void findSyncTarget_noHeightEstimates() { assertThat(result).isNotCompleted(); } - @Test - public void shouldDisconnectPeerIfWorldStateIsUnavailableForCommonAncestor() { + @ParameterizedTest + @ArgumentsSource(FullSyncTargetManagerTest.FullSyncTargetManagerTestArguments.class) + public void shouldDisconnectPeerIfWorldStateIsUnavailableForCommonAncestor( + final DataStorageFormat storageFormat) { + setup(storageFormat); final BlockHeader chainHeadHeader = localBlockchain.getChainHeadHeader(); when(localWorldState.isWorldStateAvailable( chainHeadHeader.getStateRoot(), chainHeadHeader.getHash())) @@ -157,8 +159,11 @@ public void shouldDisconnectPeerIfWorldStateIsUnavailableForCommonAncestor() { assertThat(bestPeer.getPeerConnection().isDisconnected()).isTrue(); } - @Test - public void shouldAllowSyncTargetWhenIfWorldStateIsAvailableForCommonAncestor() { + @ParameterizedTest + @ArgumentsSource(FullSyncTargetManagerTest.FullSyncTargetManagerTestArguments.class) + public void shouldAllowSyncTargetWhenIfWorldStateIsAvailableForCommonAncestor( + final DataStorageFormat storageFormat) { + setup(storageFormat); final BlockHeader chainHeadHeader = localBlockchain.getChainHeadHeader(); when(localWorldState.isWorldStateAvailable( chainHeadHeader.getStateRoot(), chainHeadHeader.getHash())) diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/CompleteTaskStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/CompleteTaskStepTest.java index 6a1f7c9d045..214070d9684 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/CompleteTaskStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/CompleteTaskStepTest.java @@ -34,8 +34,8 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class CompleteTaskStepTest { @@ -50,7 +50,7 @@ public class CompleteTaskStepTest { private final CompleteTaskStep completeTaskStep = new CompleteTaskStep(snapSyncState, new NoOpMetricsSystem()); - @Before + @BeforeEach public void setup() { when(snapSyncState.getPivotBlockHeader()).thenReturn(Optional.of(blockHeader)); } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/DynamicPivotBlockManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/DynamicPivotBlockManagerTest.java index 4e413f263f7..c4adf1267f7 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/DynamicPivotBlockManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/DynamicPivotBlockManagerTest.java @@ -30,8 +30,8 @@ import java.util.OptionalLong; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class DynamicPivotBlockManagerTest { @@ -41,7 +41,7 @@ public class DynamicPivotBlockManagerTest { private final EthContext ethContext = mock(EthContext.class); private DynamicPivotBlockSelector dynamicPivotBlockManager; - @Before + @BeforeEach public void setup() { when(fastSyncActions.getSyncState()).thenReturn(syncState); when(ethContext.getScheduler()).thenReturn(new DeterministicEthScheduler()); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/LoadLocalDataStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/LoadLocalDataStepTest.java index a8562985365..7ecd284e98f 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/LoadLocalDataStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/LoadLocalDataStepTest.java @@ -37,8 +37,8 @@ import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; public class LoadLocalDataStepTest { @@ -71,7 +71,7 @@ public class LoadLocalDataStepTest { new NoOpMetricsSystem(), snapSyncState); - @Before + @BeforeEach public void setup() { when(snapSyncState.hasPivotBlockHeader()).thenReturn(true); when(snapSyncState.getPivotBlockHeader()).thenReturn(Optional.of(blockHeader)); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java index 81e036af7b6..69047bc6e50 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java @@ -33,8 +33,8 @@ import java.util.List; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class PersistDataStepTest { @@ -48,7 +48,7 @@ public class PersistDataStepTest { private final PersistDataStep persistDataStep = new PersistDataStep(snapSyncState, worldStateStorage, downloadState, snapSyncConfiguration); - @Before + @BeforeEach public void setUp() { when(downloadState.getMetricsManager()).thenReturn(mock(SnapsyncMetricsManager.class)); } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/RangeManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/RangeManagerTest.java index 4e065c8ef22..003db79a7e2 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/RangeManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/RangeManagerTest.java @@ -34,14 +34,14 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Test; +import org.junit.jupiter.api.Test; public final class RangeManagerTest { @Test public void testRemainingRangesEqualToOneWhenFirstRangeContainsMoreThanHalf() { TreeMap items = new TreeMap<>(); - items.put(Bytes32.repeat((byte) 0xbb), Bytes.wrap(new byte[] {0x03})); + items.put(Bytes32.fromHexString("bb".repeat(32)), Bytes.wrap(new byte[] {0x03})); int nbRanges = RangeManager.getRangeCount(RangeManager.MIN_RANGE, RangeManager.MAX_RANGE, items); assertThat(nbRanges).isEqualTo(1); @@ -50,7 +50,7 @@ public void testRemainingRangesEqualToOneWhenFirstRangeContainsMoreThanHalf() { @Test public void testRemainingRangesEqualToOneWhenFirstRangeContainsLessThanHalf() { TreeMap items = new TreeMap<>(); - items.put(Bytes32.repeat((byte) 0x77), Bytes.wrap(new byte[] {0x03})); + items.put(Bytes32.fromHexString("77".repeat(32)), Bytes.wrap(new byte[] {0x03})); int nbRanges = RangeManager.getRangeCount(RangeManager.MIN_RANGE, RangeManager.MAX_RANGE, items); assertThat(nbRanges).isEqualTo(2); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadStateTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadStateTest.java index ac513ebd97e..14305363cd3 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadStateTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadStateTest.java @@ -47,24 +47,23 @@ import org.hyperledger.besu.services.tasks.InMemoryTasksPriorityQueues; import org.hyperledger.besu.testutil.TestClock; -import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.function.BiConsumer; +import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; @SuppressWarnings("unchecked") -@RunWith(Parameterized.class) public class SnapWorldDownloadStateTest { private static final Bytes ROOT_NODE_DATA = Bytes.of(1, 2, 3, 4); @@ -92,27 +91,17 @@ public class SnapWorldDownloadStateTest { private CompletableFuture future; - @Parameterized.Parameters - public static Collection data() { - return Arrays.asList( - new Object[][] { - {DataStorageFormat.BONSAI, true}, - {DataStorageFormat.BONSAI, false}, - {DataStorageFormat.FOREST, false} - }); - } - - private final DataStorageFormat storageFormat; - private final boolean isFlatDbHealingEnabled; - - public SnapWorldDownloadStateTest( - final DataStorageFormat storageFormat, final boolean isFlatDbHealingEnabled) { - this.storageFormat = storageFormat; - this.isFlatDbHealingEnabled = isFlatDbHealingEnabled; + static class SnapWorldDownloadStateTestArguments implements ArgumentsProvider { + @Override + public Stream provideArguments(final ExtensionContext context) { + return Stream.of( + Arguments.of(DataStorageFormat.BONSAI, true), + Arguments.of(DataStorageFormat.BONSAI, false), + Arguments.of(DataStorageFormat.FOREST, false)); + } } - @Before - public void setUp() { + public void setUp(final DataStorageFormat storageFormat) { when(metricsManager.getMetricsSystem()).thenReturn(new NoOpMetricsSystem()); @@ -150,8 +139,11 @@ public void setUp() { assertThat(downloadState.isDownloading()).isTrue(); } - @Test - public void shouldCompleteReturnedFutureWhenNoPendingTasksRemain() { + @ParameterizedTest + @ArgumentsSource(SnapWorldDownloadStateTestArguments.class) + public void shouldCompleteReturnedFutureWhenNoPendingTasksRemain( + final DataStorageFormat storageFormat, final boolean isFlatDbHealingEnabled) { + setUp(storageFormat); when(snapSyncState.isHealTrieInProgress()).thenReturn(true); when(snapSyncState.isHealFlatDatabaseInProgress()).thenReturn(true); downloadState.checkCompletion(header); @@ -160,8 +152,11 @@ public void shouldCompleteReturnedFutureWhenNoPendingTasksRemain() { assertThat(downloadState.isDownloading()).isFalse(); } - @Test - public void shouldStartHealWhenNoSnapsyncPendingTasksRemain() { + @ParameterizedTest + @ArgumentsSource(SnapWorldDownloadStateTestArguments.class) + public void shouldStartHealWhenNoSnapsyncPendingTasksRemain( + final DataStorageFormat storageFormat, final boolean isFlatDbHealingEnabled) { + setUp(storageFormat); when(snapSyncState.isHealTrieInProgress()).thenReturn(false); when(snapSyncState.getPivotBlockHeader()).thenReturn(Optional.of(mock(BlockHeader.class))); assertThat(downloadState.pendingTrieNodeRequests.isEmpty()).isTrue(); @@ -171,8 +166,11 @@ public void shouldStartHealWhenNoSnapsyncPendingTasksRemain() { assertThat(downloadState.pendingTrieNodeRequests.isEmpty()).isFalse(); } - @Test - public void shouldStoreRootNodeBeforeReturnedFutureCompletes() { + @ParameterizedTest + @ArgumentsSource(SnapWorldDownloadStateTestArguments.class) + public void shouldStoreRootNodeBeforeReturnedFutureCompletes( + final DataStorageFormat storageFormat, final boolean isFlatDbHealingEnabled) { + setUp(storageFormat); when(snapSyncState.isHealTrieInProgress()).thenReturn(true); when(snapSyncState.isHealFlatDatabaseInProgress()).thenReturn(true); final CompletableFuture postFutureChecks = @@ -187,8 +185,11 @@ public void shouldStoreRootNodeBeforeReturnedFutureCompletes() { assertThat(postFutureChecks).isCompleted(); } - @Test - public void shouldNotCompleteWhenThereAreAccountPendingTasks() { + @ParameterizedTest + @ArgumentsSource(SnapWorldDownloadStateTestArguments.class) + public void shouldNotCompleteWhenThereAreAccountPendingTasks( + final DataStorageFormat storageFormat, final boolean isFlatDbHealingEnabled) { + setUp(storageFormat); when(snapSyncState.isHealTrieInProgress()).thenReturn(false); downloadState.pendingAccountRequests.add( SnapDataRequest.createAccountDataRequest( @@ -204,8 +205,11 @@ public void shouldNotCompleteWhenThereAreAccountPendingTasks() { assertThat(downloadState.isDownloading()).isTrue(); } - @Test - public void shouldNotCompleteWhenThereAreStoragePendingTasks() { + @ParameterizedTest + @ArgumentsSource(SnapWorldDownloadStateTestArguments.class) + public void shouldNotCompleteWhenThereAreStoragePendingTasks( + final DataStorageFormat storageFormat, final boolean isFlatDbHealingEnabled) { + setUp(storageFormat); when(snapSyncState.isHealTrieInProgress()).thenReturn(false); downloadState.pendingStorageRequests.add( SnapDataRequest.createStorageTrieNodeDataRequest( @@ -228,8 +232,11 @@ public void shouldNotCompleteWhenThereAreStoragePendingTasks() { assertThat(downloadState.isDownloading()).isTrue(); } - @Test - public void shouldNotCompleteWhenThereAreTriePendingTasks() { + @ParameterizedTest + @ArgumentsSource(SnapWorldDownloadStateTestArguments.class) + public void shouldNotCompleteWhenThereAreTriePendingTasks( + final DataStorageFormat storageFormat, final boolean isFlatDbHealingEnabled) { + setUp(storageFormat); when(snapSyncState.isHealTrieInProgress()).thenReturn(true); downloadState.pendingTrieNodeRequests.add( SnapDataRequest.createAccountTrieNodeDataRequest( @@ -242,8 +249,11 @@ public void shouldNotCompleteWhenThereAreTriePendingTasks() { assertThat(downloadState.isDownloading()).isTrue(); } - @Test - public void shouldNotCompleteWhenThereAreFlatDBHealingPendingTasks() { + @ParameterizedTest + @ArgumentsSource(SnapWorldDownloadStateTestArguments.class) + public void shouldNotCompleteWhenThereAreFlatDBHealingPendingTasks( + final DataStorageFormat storageFormat, final boolean isFlatDbHealingEnabled) { + setUp(storageFormat); when(snapSyncState.isHealTrieInProgress()).thenReturn(true); when(snapSyncState.isHealFlatDatabaseInProgress()).thenReturn(true); downloadState.pendingAccountFlatDatabaseHealingRequests.add( @@ -257,8 +267,11 @@ public void shouldNotCompleteWhenThereAreFlatDBHealingPendingTasks() { assertThat(downloadState.isDownloading()).isTrue(); } - @Test - public void shouldCancelOutstandingTasksWhenFutureIsCancelled() { + @ParameterizedTest + @ArgumentsSource(SnapWorldDownloadStateTestArguments.class) + public void shouldCancelOutstandingTasksWhenFutureIsCancelled( + final DataStorageFormat storageFormat, final boolean isFlatDbHealingEnabled) { + setUp(storageFormat); final EthTask outstandingTask1 = mock(EthTask.class); final EthTask outstandingTask2 = mock(EthTask.class); downloadState.addOutstandingTask(outstandingTask1); @@ -286,8 +299,11 @@ public void shouldCancelOutstandingTasksWhenFutureIsCancelled() { assertThat(downloadState.isDownloading()).isFalse(); } - @Test - public void shouldRestartHealWhenNewPivotBlock() { + @ParameterizedTest + @ArgumentsSource(SnapWorldDownloadStateTestArguments.class) + public void shouldRestartHealWhenNewPivotBlock( + final DataStorageFormat storageFormat, final boolean isFlatDbHealingEnabled) { + setUp(storageFormat); when(snapSyncState.getPivotBlockHeader()).thenReturn(Optional.of(mock(BlockHeader.class))); when(snapSyncState.isHealTrieInProgress()).thenReturn(false); assertThat(downloadState.pendingTrieNodeRequests.isEmpty()).isTrue(); @@ -307,8 +323,11 @@ public void shouldRestartHealWhenNewPivotBlock() { assertThat(downloadState.pendingCodeRequests.isEmpty()).isTrue(); } - @Test - public void shouldWaitingBlockchainWhenTooBehind() { + @ParameterizedTest + @ArgumentsSource(SnapWorldDownloadStateTestArguments.class) + public void shouldWaitingBlockchainWhenTooBehind( + final DataStorageFormat storageFormat, final boolean isFlatDbHealingEnabled) { + setUp(storageFormat); when(snapSyncState.isHealTrieInProgress()).thenReturn(true); downloadState.setPivotBlockSelector(dynamicPivotBlockManager); @@ -327,8 +346,11 @@ public void shouldWaitingBlockchainWhenTooBehind() { assertThat(downloadState.isDownloading()).isTrue(); } - @Test - public void shouldStopWaitingBlockchainWhenNewPivotBlockAvailable() { + @ParameterizedTest + @ArgumentsSource(SnapWorldDownloadStateTestArguments.class) + public void shouldStopWaitingBlockchainWhenNewPivotBlockAvailable( + final DataStorageFormat storageFormat, final boolean isFlatDbHealingEnabled) { + setUp(storageFormat); when(snapSyncState.isHealTrieInProgress()).thenReturn(true); @@ -364,8 +386,11 @@ public void shouldStopWaitingBlockchainWhenNewPivotBlockAvailable() { verify(snapSyncState).setWaitingBlockchain(false); } - @Test - public void shouldStopWaitingBlockchainWhenCloseToTheHead() { + @ParameterizedTest + @ArgumentsSource(SnapWorldDownloadStateTestArguments.class) + public void shouldStopWaitingBlockchainWhenCloseToTheHead( + final DataStorageFormat storageFormat, final boolean isFlatDbHealingEnabled) { + setUp(storageFormat); when(snapSyncState.isHealTrieInProgress()).thenReturn(true); @@ -390,9 +415,12 @@ public void shouldStopWaitingBlockchainWhenCloseToTheHead() { verify(snapSyncState).setWaitingBlockchain(false); } - @Test - public void shouldCompleteReturnedFutureWhenNoPendingTasksRemainAndFlatDBHealNotNeeded() { - Assume.assumeTrue( + @ParameterizedTest + @ArgumentsSource(SnapWorldDownloadStateTestArguments.class) + public void shouldCompleteReturnedFutureWhenNoPendingTasksRemainAndFlatDBHealNotNeeded( + final DataStorageFormat storageFormat, final boolean isFlatDbHealingEnabled) { + setUp(storageFormat); + Assumptions.assumeTrue( storageFormat == DataStorageFormat.FOREST || (storageFormat == DataStorageFormat.BONSAI && !isFlatDbHealingEnabled)); when(snapSyncState.isHealTrieInProgress()).thenReturn(true); @@ -402,10 +430,13 @@ public void shouldCompleteReturnedFutureWhenNoPendingTasksRemainAndFlatDBHealNot assertThat(downloadState.isDownloading()).isFalse(); } - @Test - public void shouldNotCompleteReturnedFutureWhenNoPendingTasksRemainAndFlatDBHealNeeded() { - Assume.assumeTrue(storageFormat == DataStorageFormat.BONSAI); - Assume.assumeTrue(isFlatDbHealingEnabled); + @ParameterizedTest + @ArgumentsSource(SnapWorldDownloadStateTestArguments.class) + public void shouldNotCompleteReturnedFutureWhenNoPendingTasksRemainAndFlatDBHealNeeded( + final DataStorageFormat storageFormat, final boolean isFlatDbHealingEnabled) { + setUp(storageFormat); + Assumptions.assumeTrue(storageFormat == DataStorageFormat.BONSAI); + Assumptions.assumeTrue(isFlatDbHealingEnabled); ((BonsaiWorldStateKeyValueStorage) worldStateStorage).upgradeToFullFlatDbMode(); when(snapSyncState.isHealTrieInProgress()).thenReturn(true); downloadState.checkCompletion(header); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/StackTrieTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/StackTrieTest.java index 26e5cd5af42..10a0cf3f84c 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/StackTrieTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/StackTrieTest.java @@ -30,7 +30,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class StackTrieTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequestTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequestTest.java index f1063d9ed7a..0f07056296e 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequestTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequestTest.java @@ -47,20 +47,23 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class AccountFlatDatabaseHealingRangeRequestTest { @Mock private SnapWorldDownloadState downloadState; @Mock private SnapSyncProcessState snapSyncState; - @Before + @BeforeEach public void setup() { Mockito.when(downloadState.getMetricsManager()) .thenReturn(Mockito.mock(SnapsyncMetricsManager.class)); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageFlatDatabaseHealingRangeRequestTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageFlatDatabaseHealingRangeRequestTest.java index ded60664a99..a281385dd5b 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageFlatDatabaseHealingRangeRequestTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageFlatDatabaseHealingRangeRequestTest.java @@ -48,15 +48,15 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) -public class StorageFlatDatabaseHealingRangeRequestTest { +@ExtendWith(MockitoExtension.class) +class StorageFlatDatabaseHealingRangeRequestTest { @Mock private SnapWorldDownloadState downloadState; @Mock private SnapSyncProcessState snapSyncState; @@ -74,7 +74,7 @@ public class StorageFlatDatabaseHealingRangeRequestTest { private Hash account0Hash; private Hash account0StorageRoot; - @Before + @BeforeEach public void setup() { final StorageProvider storageProvider = new InMemoryKeyValueStorageProvider(); worldStateStorage = @@ -82,8 +82,9 @@ public void setup() { proofProvider = new WorldStateProofProvider(worldStateStorage); trie = TrieGenerator.generateTrie( - worldStateStorage, accounts.stream().map(Hash::hash).collect(Collectors.toList())); - account0Hash = Hash.hash(accounts.get(0)); + worldStateStorage, + accounts.stream().map(Address::addressHash).collect(Collectors.toList())); + account0Hash = accounts.get(0).addressHash(); account0StorageRoot = trie.get(account0Hash) .map(RLP::input) @@ -93,7 +94,7 @@ public void setup() { } @Test - public void shouldReturnChildRequests() { + void shouldReturnChildRequests() { final StoredMerklePatriciaTrie storageTrie = new StoredMerklePatriciaTrie<>( @@ -150,7 +151,7 @@ public void shouldReturnChildRequests() { } @Test - public void shouldNotReturnChildRequestsWhenNoMoreSlots() { + void shouldNotReturnChildRequestsWhenNoMoreSlots() { final StoredMerklePatriciaTrie storageTrie = new StoredMerklePatriciaTrie<>( @@ -191,7 +192,7 @@ public void shouldNotReturnChildRequestsWhenNoMoreSlots() { } @Test - public void doNotPersistWhenProofIsValid() { + void doNotPersistWhenProofIsValid() { final StoredMerklePatriciaTrie storageTrie = new StoredMerklePatriciaTrie<>( @@ -248,7 +249,7 @@ public void doNotPersistWhenProofIsValid() { } @Test - public void doHealAndPersistWhenProofIsInvalid() { + void doHealAndPersistWhenProofIsInvalid() { final StoredMerklePatriciaTrie storageTrie = new StoredMerklePatriciaTrie<>( diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequestTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequestTest.java new file mode 100644 index 00000000000..14e4d551f72 --- /dev/null +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequestTest.java @@ -0,0 +1,113 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; +import org.hyperledger.besu.ethereum.core.TrieGenerator; +import org.hyperledger.besu.ethereum.eth.sync.snapsync.SnapWorldDownloadState; +import org.hyperledger.besu.ethereum.rlp.RLP; +import org.hyperledger.besu.ethereum.storage.StorageProvider; +import org.hyperledger.besu.ethereum.storage.keyvalue.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.trie.MerkleTrie; +import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; +import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.apache.tuweni.bytes.Bytes; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class StorageTrieNodeHealingRequestTest { + + @Mock private SnapWorldDownloadState downloadState; + final List

    accounts = + List.of( + Address.fromHexString("0xdeadbeef"), + Address.fromHexString("0xdeadbeee"), + Address.fromHexString("0xdeadbeea"), + Address.fromHexString("0xdeadbeeb")); + + private WorldStateStorage worldStateStorage; + + private Hash account0Hash; + private Hash account0StorageRoot; + + static class StorageFormatArguments implements ArgumentsProvider { + @Override + public Stream provideArguments(final ExtensionContext context) { + return Stream.of( + Arguments.of(DataStorageFormat.BONSAI), Arguments.of(DataStorageFormat.FOREST)); + } + } + + public void setup(final DataStorageFormat storageFormat) { + if (storageFormat.equals(DataStorageFormat.FOREST)) { + worldStateStorage = new WorldStateKeyValueStorage(new InMemoryKeyValueStorage()); + } else { + final StorageProvider storageProvider = new InMemoryKeyValueStorageProvider(); + worldStateStorage = + new BonsaiWorldStateKeyValueStorage(storageProvider, new NoOpMetricsSystem()); + } + final MerkleTrie trie = + TrieGenerator.generateTrie( + worldStateStorage, + accounts.stream().map(Address::addressHash).collect(Collectors.toList())); + account0Hash = accounts.get(0).addressHash(); + account0StorageRoot = + trie.get(account0Hash) + .map(RLP::input) + .map(StateTrieAccountValue::readFrom) + .map(StateTrieAccountValue::getStorageRoot) + .orElseThrow(); + } + + @ParameterizedTest + @ArgumentsSource(StorageFormatArguments.class) + void shouldDetectExistingData(final DataStorageFormat storageFormat) { + setup(storageFormat); + final StorageTrieNodeHealingRequest request = + new StorageTrieNodeHealingRequest( + account0StorageRoot, account0Hash, Hash.EMPTY, Bytes.EMPTY); + + Assertions.assertThat(request.getExistingData(downloadState, worldStateStorage)).isPresent(); + } + + @ParameterizedTest + @ArgumentsSource(StorageFormatArguments.class) + void shouldDetectMissingData(final DataStorageFormat storageFormat) { + setup(storageFormat); + final StorageTrieNodeHealingRequest request = + new StorageTrieNodeHealingRequest(Hash.EMPTY, account0Hash, Hash.EMPTY, Bytes.EMPTY); + + Assertions.assertThat(request.getExistingData(downloadState, worldStateStorage)).isEmpty(); + } +} diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/PendingBlocksManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/PendingBlocksManagerTest.java index be61c8fa338..d908fb941c4 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/PendingBlocksManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/PendingBlocksManagerTest.java @@ -28,8 +28,8 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class PendingBlocksManagerTest { @@ -39,7 +39,7 @@ public class PendingBlocksManagerTest { private PendingBlocksManager pendingBlocksManager; private BlockDataGenerator gen; - @Before + @BeforeEach public void setup() { pendingBlocksManager = new PendingBlocksManager( diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncStateTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncStateTest.java index be068067361..d3dcb855990 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncStateTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncStateTest.java @@ -51,14 +51,14 @@ import java.util.List; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class SyncStateTest { private static final Difficulty standardDifficultyPerBlock = Difficulty.ONE; @@ -88,7 +88,7 @@ public class SyncStateTest { private RespondingEthPeer otherPeer; private SyncState syncState; - @Before + @BeforeEach public void setUp() { ethProtocolManager = EthProtocolManagerTestUtil.create(blockchain); ethPeers = spy(ethProtocolManager.ethContext().getEthPeers()); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/cache/PendingBlockCacheTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/cache/PendingBlockCacheTest.java index c4e3145eb28..cb1a65198cd 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/cache/PendingBlockCacheTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/cache/PendingBlockCacheTest.java @@ -20,8 +20,8 @@ import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class PendingBlockCacheTest { @@ -34,7 +34,7 @@ public class PendingBlockCacheTest { private Block parentBlock; - @Before + @BeforeEach public void setup() { gen = new BlockDataGenerator(); parentBlock = gen.block(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/CompleteBlocksTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/CompleteBlocksTaskTest.java index 2723740bd08..e8049af736e 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/CompleteBlocksTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/CompleteBlocksTaskTest.java @@ -51,7 +51,7 @@ import java.util.stream.Collectors; import org.apache.tuweni.units.bigints.UInt64; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; public class CompleteBlocksTaskTest extends RetryingMessageTaskTest> { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskParameterizedTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskParameterizedTest.java index 74cddc5e569..3eddd2bae24 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskParameterizedTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskParameterizedTest.java @@ -42,22 +42,19 @@ import org.hyperledger.besu.plugin.services.MetricsSystem; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Stream; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public class DetermineCommonAncestorTaskParameterizedTest { private final ProtocolSchedule protocolSchedule = ProtocolScheduleFixture.MAINNET; private static final BlockDataGenerator blockDataGenerator = new BlockDataGenerator(); @@ -66,18 +63,10 @@ public class DetermineCommonAncestorTaskParameterizedTest { private static Block genesisBlock; private static MutableBlockchain localBlockchain; private static final int chainHeight = 50; - private final int headerRequestSize; - private final int commonAncestorHeight; private MutableBlockchain remoteBlockchain; - public DetermineCommonAncestorTaskParameterizedTest( - final int headerRequestSize, final int commonAncestorHeight) { - this.headerRequestSize = headerRequestSize; - this.commonAncestorHeight = commonAncestorHeight; - } - - @BeforeClass + @BeforeAll public static void setupClass() { genesisBlock = blockDataGenerator.genesisBlock(); localBlockchain = createInMemoryBlockchain(genesisBlock); @@ -94,25 +83,25 @@ public static void setupClass() { } } - @Before + @BeforeEach public void setup() { remoteBlockchain = createInMemoryBlockchain(genesisBlock); } - @Parameters(name = "requestSize={0}, commonAncestor={1}") - public static Collection parameters() throws IOException { + public static Stream parameters() throws IOException { final int[] requestSizes = {5, 12, chainHeight, chainHeight * 2}; - final List params = new ArrayList<>(); + final Stream.Builder builder = Stream.builder(); for (final int requestSize : requestSizes) { for (int i = 0; i <= chainHeight; i++) { - params.add(new Object[] {requestSize, i}); + builder.add(Arguments.of(requestSize, i)); } } - return params; + return builder.build(); } - @Test - public void searchesAgainstNetwork() { + @ParameterizedTest(name = "requestSize={0}, commonAncestor={1}") + @MethodSource("parameters") + public void searchesAgainstNetwork(final int headerRequestSize, final int commonAncestorHeight) { BlockHeader commonHeader = genesisBlock.getHeader(); for (long i = 1; i <= commonAncestorHeight; i++) { commonHeader = localBlockchain.getBlockHeader(i).get(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java index 8e2fd6cbae0..ca183d57af0 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java @@ -59,8 +59,8 @@ import java.util.concurrent.atomic.AtomicReference; import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class DetermineCommonAncestorTaskTest { @@ -74,7 +74,7 @@ public class DetermineCommonAncestorTaskTest { private EthContext ethContext; private ProtocolContext protocolContext; - @Before + @BeforeEach public void setup() { localGenesisBlock = blockDataGenerator.genesisBlock(); localBlockchain = createInMemoryBlockchain(localGenesisBlock); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTaskTest.java index 9fcb5c147ee..d7a36a5d8f4 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTaskTest.java @@ -36,7 +36,7 @@ import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class DownloadHeaderSequenceTaskTest extends RetryingMessageTaskTest> { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/GetReceiptsForHeadersTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/GetReceiptsForHeadersTaskTest.java index 57d8270e04b..2b28e8a5c98 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/GetReceiptsForHeadersTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/GetReceiptsForHeadersTaskTest.java @@ -30,7 +30,7 @@ import java.util.Map; import com.google.common.collect.ImmutableMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class GetReceiptsForHeadersTaskTest extends RetryingMessageTaskTest>> { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/PersistBlockTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/PersistBlockTaskTest.java index 5498e96173d..5d02f398470 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/PersistBlockTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/PersistBlockTaskTest.java @@ -34,19 +34,19 @@ import org.hyperledger.besu.plugin.services.MetricsSystem; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; import org.awaitility.Awaitility; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; import org.mockito.Mockito; -@RunWith(Parameterized.class) public class PersistBlockTaskTest { private BlockchainSetupUtil blockchainUtil; @@ -56,19 +56,15 @@ public class PersistBlockTaskTest { private MutableBlockchain blockchain; private final MetricsSystem metricsSystem = new NoOpMetricsSystem(); - @Parameterized.Parameters - public static Collection data() { - return Arrays.asList(new Object[][] {{DataStorageFormat.BONSAI}, {DataStorageFormat.FOREST}}); - } - - private final DataStorageFormat storageFormat; - - public PersistBlockTaskTest(final DataStorageFormat storageFormat) { - this.storageFormat = storageFormat; + static class PersistBlockTaskTestArguments implements ArgumentsProvider { + @Override + public Stream provideArguments(final ExtensionContext context) { + return Stream.of( + Arguments.of(DataStorageFormat.BONSAI), Arguments.of(DataStorageFormat.FOREST)); + } } - @Before - public void setup() { + public void setup(final DataStorageFormat storageFormat) { blockchainUtil = BlockchainSetupUtil.forTesting(storageFormat); protocolSchedule = blockchainUtil.getProtocolSchedule(); protocolContext = blockchainUtil.getProtocolContext(); @@ -77,8 +73,10 @@ public void setup() { ethContext = ethProtocolManager.ethContext(); } - @Test - public void importsValidBlock() throws Exception { + @ParameterizedTest + @ArgumentsSource(PersistBlockTaskTest.PersistBlockTaskTestArguments.class) + public void importsValidBlock(final DataStorageFormat storageFormat) throws Exception { + setup(storageFormat); blockchainUtil.importFirstBlocks(3); final Block nextBlock = blockchainUtil.getBlock(3); @@ -103,8 +101,10 @@ public void importsValidBlock() throws Exception { assertThat(blockchain.contains(nextBlock.getHash())).isTrue(); } - @Test - public void failsToImportInvalidBlock() { + @ParameterizedTest + @ArgumentsSource(PersistBlockTaskTest.PersistBlockTaskTestArguments.class) + public void failsToImportInvalidBlock(final DataStorageFormat storageFormat) { + setup(storageFormat); final BlockDataGenerator gen = new BlockDataGenerator(); blockchainUtil.importFirstBlocks(3); final Block nextBlock = gen.block(); @@ -130,8 +130,11 @@ public void failsToImportInvalidBlock() { assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); } - @Test - public void importsValidBlockSequence() throws Exception { + @ParameterizedTest + @ArgumentsSource(PersistBlockTaskTest.PersistBlockTaskTestArguments.class) + public void importsValidBlockSequence(final DataStorageFormat storageFormat) throws Exception { + + setup(storageFormat); blockchainUtil.importFirstBlocks(3); final List nextBlocks = Arrays.asList(blockchainUtil.getBlock(3), blockchainUtil.getBlock(4)); @@ -161,8 +164,11 @@ public void importsValidBlockSequence() throws Exception { } } - @Test - public void failsToImportInvalidBlockSequenceWhereSecondBlockFails() { + @ParameterizedTest + @ArgumentsSource(PersistBlockTaskTest.PersistBlockTaskTestArguments.class) + public void failsToImportInvalidBlockSequenceWhereSecondBlockFails( + final DataStorageFormat storageFormat) { + setup(storageFormat); final BlockDataGenerator gen = new BlockDataGenerator(); blockchainUtil.importFirstBlocks(3); final List nextBlocks = Arrays.asList(blockchainUtil.getBlock(3), gen.block()); @@ -191,8 +197,11 @@ public void failsToImportInvalidBlockSequenceWhereSecondBlockFails() { assertThat(blockchain.contains(nextBlocks.get(1).getHash())).isFalse(); } - @Test - public void failsToImportInvalidBlockSequenceWhereFirstBlockFails() { + @ParameterizedTest + @ArgumentsSource(PersistBlockTaskTest.PersistBlockTaskTestArguments.class) + public void failsToImportInvalidBlockSequenceWhereFirstBlockFails( + final DataStorageFormat storageFormat) { + setup(storageFormat); final BlockDataGenerator gen = new BlockDataGenerator(); blockchainUtil.importFirstBlocks(3); final List nextBlocks = Arrays.asList(gen.block(), blockchainUtil.getBlock(3)); @@ -221,8 +230,10 @@ public void failsToImportInvalidBlockSequenceWhereFirstBlockFails() { assertThat(blockchain.contains(nextBlocks.get(1).getHash())).isFalse(); } - @Test - public void importsValidUnorderedBlocks() throws Exception { + @ParameterizedTest + @ArgumentsSource(PersistBlockTaskTest.PersistBlockTaskTestArguments.class) + public void importsValidUnorderedBlocks(final DataStorageFormat storageFormat) throws Exception { + setup(storageFormat); blockchainUtil.importFirstBlocks(3); final Block valid = blockchainUtil.getBlock(3); final List nextBlocks = Collections.singletonList(valid); @@ -253,8 +264,10 @@ public void importsValidUnorderedBlocks() throws Exception { } } - @Test - public void importsInvalidUnorderedBlock() { + @ParameterizedTest + @ArgumentsSource(PersistBlockTaskTest.PersistBlockTaskTestArguments.class) + public void importsInvalidUnorderedBlock(final DataStorageFormat storageFormat) { + setup(storageFormat); final BlockDataGenerator gen = new BlockDataGenerator(); blockchainUtil.importFirstBlocks(3); final Block invalid = gen.block(); @@ -284,8 +297,10 @@ public void importsInvalidUnorderedBlock() { } } - @Test - public void importsInvalidUnorderedBlocks() { + @ParameterizedTest + @ArgumentsSource(PersistBlockTaskTest.PersistBlockTaskTestArguments.class) + public void importsInvalidUnorderedBlocks(final DataStorageFormat storageFormat) { + setup(storageFormat); final BlockDataGenerator gen = new BlockDataGenerator(); blockchainUtil.importFirstBlocks(3); final List nextBlocks = Arrays.asList(gen.block(), gen.block()); @@ -314,8 +329,11 @@ public void importsInvalidUnorderedBlocks() { } } - @Test - public void importsUnorderedBlocksWithMixOfValidAndInvalidBlocks() throws Exception { + @ParameterizedTest + @ArgumentsSource(PersistBlockTaskTest.PersistBlockTaskTestArguments.class) + public void importsUnorderedBlocksWithMixOfValidAndInvalidBlocks( + final DataStorageFormat storageFormat) throws Exception { + setup(storageFormat); final BlockDataGenerator gen = new BlockDataGenerator(); blockchainUtil.importFirstBlocks(3); final Block valid = blockchainUtil.getBlock(3); @@ -347,8 +365,10 @@ public void importsUnorderedBlocksWithMixOfValidAndInvalidBlocks() throws Except assertThat(blockchain.contains(invalid.getHash())).isFalse(); } - @Test - public void cancelBeforeRunning() { + @ParameterizedTest + @ArgumentsSource(PersistBlockTaskTest.PersistBlockTaskTestArguments.class) + public void cancelBeforeRunning(final DataStorageFormat storageFormat) { + setup(storageFormat); blockchainUtil.importFirstBlocks(3); final Block nextBlock = blockchainUtil.getBlock(3); @@ -372,8 +392,10 @@ public void cancelBeforeRunning() { assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); } - @Test - public void cancelAfterRunning() { + @ParameterizedTest + @ArgumentsSource(PersistBlockTaskTest.PersistBlockTaskTestArguments.class) + public void cancelAfterRunning(final DataStorageFormat storageFormat) { + setup(storageFormat); blockchainUtil.importFirstBlocks(3); final Block nextBlock = blockchainUtil.getBlock(3); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/RetryingGetHeaderFromPeerByNumberTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/RetryingGetHeaderFromPeerByNumberTaskTest.java index a63decb61a1..1174b53cff4 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/RetryingGetHeaderFromPeerByNumberTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/RetryingGetHeaderFromPeerByNumberTaskTest.java @@ -22,8 +22,8 @@ import java.util.List; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; public class RetryingGetHeaderFromPeerByNumberTaskTest extends RetryingMessageTaskTest> { @@ -43,6 +43,6 @@ protected EthTask> createTask(final List requeste @Test @Override - @Ignore("It's not possible to return a partial result as we only ever request one header.") + @Disabled("It's not possible to return a partial result as we only ever request one header.") public void failsWhenPeerReturnsPartialResultThenStops() {} } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java index 4312b63c329..eaaff72a3e3 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java @@ -58,10 +58,10 @@ import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; import org.hyperledger.besu.ethereum.eth.messages.EthPV65; -import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionValidator; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams; +import org.hyperledger.besu.ethereum.mainnet.TransactionValidatorFactory; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; @@ -81,6 +81,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @@ -97,7 +98,10 @@ public abstract class AbstractTransactionPoolTest { private static final KeyPair KEY_PAIR2 = SignatureAlgorithmFactory.getInstance().generateKeyPair(); - @Mock protected MainnetTransactionValidator transactionValidator; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + protected TransactionValidatorFactory transactionValidatorFactory; + @Mock protected PendingTransactionAddedListener listener; @Mock protected MiningParameters miningParameters; @Mock protected TransactionsMessageSender transactionsMessageSender; @@ -136,7 +140,7 @@ public void setUp() { protocolContext = executionContext.getProtocolContext(); blockchain = executionContext.getBlockchain(); transactions = spy(createPendingTransactionsSorter()); - when(protocolSpec.getTransactionValidator()).thenReturn(transactionValidator); + when(protocolSpec.getTransactionValidatorFactory()).thenReturn(transactionValidatorFactory); when(protocolSpec.getFeeMarket()).thenReturn(getFeeMarket()); protocolSchedule = spy(executionContext.getProtocolSchedule()); doReturn(protocolSpec).when(protocolSchedule).getByBlockHeader(any()); @@ -364,13 +368,13 @@ public void shouldNotAddRemoteTransactionsWhenGasPriceBelowMinimum() { transactionPool.addRemoteTransactions(singletonList(transaction)); assertTransactionNotPending(transaction); - verifyNoMoreInteractions(transactionValidator); + verifyNoMoreInteractions(transactionValidatorFactory); } @Test public void shouldNotAddRemoteTransactionsWhenThereIsAnLowestInvalidNonceForTheSender() { givenTransactionIsValid(transaction2); - when(transactionValidator.validate(eq(transaction1), any(Optional.class), any())) + when(transactionValidatorFactory.get().validate(eq(transaction1), any(Optional.class), any())) .thenReturn(ValidationResult.invalid(NONCE_TOO_LOW)); transactionPool.addRemoteTransactions(asList(transaction1, transaction2)); @@ -384,20 +388,23 @@ public void shouldNotAddRemoteTransactionsWhenThereIsAnLowestInvalidNonceForTheS public void shouldNotAddRemoteTransactionsThatAreInvalidAccordingToStateDependentChecks() { givenTransactionIsValid(transaction1); givenTransactionIsValid(transaction2); - when(transactionValidator.validateForSender( - eq(transaction2), eq(null), any(TransactionValidationParams.class))) + when(transactionValidatorFactory + .get() + .validateForSender(eq(transaction2), eq(null), any(TransactionValidationParams.class))) .thenReturn(ValidationResult.invalid(NONCE_TOO_LOW)); transactionPool.addRemoteTransactions(asList(transaction1, transaction2)); assertTransactionPending(transaction1); assertTransactionNotPending(transaction2); verify(transactionBroadcaster).onTransactionsAdded(singletonList(transaction1)); - verify(transactionValidator).validate(eq(transaction1), any(Optional.class), any()); - verify(transactionValidator) + verify(transactionValidatorFactory.get()) + .validate(eq(transaction1), any(Optional.class), any()); + verify(transactionValidatorFactory.get()) .validateForSender(eq(transaction1), eq(null), any(TransactionValidationParams.class)); - verify(transactionValidator).validate(eq(transaction2), any(Optional.class), any()); - verify(transactionValidator).validateForSender(eq(transaction2), any(), any()); - verifyNoMoreInteractions(transactionValidator); + verify(transactionValidatorFactory.get()) + .validate(eq(transaction2), any(Optional.class), any()); + verify(transactionValidatorFactory.get()).validateForSender(eq(transaction2), any(), any()); + verifyNoMoreInteractions(transactionValidatorFactory.get()); } @ParameterizedTest @@ -440,7 +447,7 @@ public void shouldDiscardRemoteTransactionThatAlreadyExistsBeforeValidation() { transactionPool.addRemoteTransactions(singletonList(transaction1)); verify(transactions).containsTransaction(transaction1); - verifyNoInteractions(transactionValidator); + verifyNoInteractions(transactionValidatorFactory); } @Test @@ -584,9 +591,11 @@ public void shouldCallValidatorWithExpectedValidationParameters() { final ArgumentCaptor txValidationParamCaptor = ArgumentCaptor.forClass(TransactionValidationParams.class); - when(transactionValidator.validate(eq(transaction1), any(Optional.class), any())) + when(transactionValidatorFactory.get().validate(eq(transaction1), any(Optional.class), any())) .thenReturn(valid()); - when(transactionValidator.validateForSender(any(), any(), txValidationParamCaptor.capture())) + when(transactionValidatorFactory + .get() + .validateForSender(any(), any(), txValidationParamCaptor.capture())) .thenReturn(valid()); final TransactionValidationParams expectedValidationParams = @@ -685,10 +694,12 @@ protected void protocolSupportsTxReplayProtection( } protected void givenTransactionIsValid(final Transaction transaction) { - when(transactionValidator.validate(eq(transaction), any(Optional.class), any())) + when(transactionValidatorFactory.get().validate(eq(transaction), any(Optional.class), any())) .thenReturn(valid()); - when(transactionValidator.validateForSender( - eq(transaction), nullable(Account.class), any(TransactionValidationParams.class))) + when(transactionValidatorFactory + .get() + .validateForSender( + eq(transaction), nullable(Account.class), any(TransactionValidationParams.class))) .thenReturn(valid()); } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionsLayeredPendingTransactionsTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionsLayeredPendingTransactionsTest.java index 20e61b50d3f..a303a3bb704 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionsLayeredPendingTransactionsTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionsLayeredPendingTransactionsTest.java @@ -58,10 +58,10 @@ import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; import org.hyperledger.besu.ethereum.eth.messages.EthPV65; -import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionValidator; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams; +import org.hyperledger.besu.ethereum.mainnet.TransactionValidatorFactory; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; @@ -77,15 +77,19 @@ import java.util.function.BiFunction; import java.util.function.Consumer; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; @SuppressWarnings("unchecked") -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public abstract class AbstractTransactionsLayeredPendingTransactionsTest { protected static final KeyPair KEY_PAIR1 = @@ -93,7 +97,10 @@ public abstract class AbstractTransactionsLayeredPendingTransactionsTest { private static final KeyPair KEY_PAIR2 = SignatureAlgorithmFactory.getInstance().generateKeyPair(); - @Mock protected MainnetTransactionValidator transactionValidator; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + protected TransactionValidatorFactory transactionValidatorFactory; + @Mock protected PendingTransactionAddedListener listener; @Mock protected MiningParameters miningParameters; @Mock protected TransactionsMessageSender transactionsMessageSender; @@ -129,13 +136,13 @@ protected abstract PendingTransactions createPendingTransactionsSorter( protected abstract FeeMarket getFeeMarket(); - @Before + @BeforeEach public void setUp() { executionContext = createExecutionContextTestFixture(); protocolContext = executionContext.getProtocolContext(); blockchain = executionContext.getBlockchain(); - when(protocolSpec.getTransactionValidator()).thenReturn(transactionValidator); + when(protocolSpec.getTransactionValidatorFactory()).thenReturn(transactionValidatorFactory); when(protocolSpec.getFeeMarket()).thenReturn(getFeeMarket()); protocolSchedule = spy(executionContext.getProtocolSchedule()); doReturn(protocolSpec).when(protocolSchedule).getByBlockHeader(any()); @@ -362,27 +369,30 @@ public void shouldNotAddRemoteTransactionsWhenGasPriceBelowMinimum() { transactionPool.addRemoteTransactions(singletonList(transaction)); assertTransactionNotPending(transaction); - verifyNoMoreInteractions(transactionValidator); + verifyNoMoreInteractions(transactionValidatorFactory); } @Test public void shouldNotAddRemoteTransactionsThatAreInvalidAccordingToStateDependentChecks() { givenTransactionIsValid(transaction0); givenTransactionIsValid(transaction1); - when(transactionValidator.validateForSender( - eq(transaction1), eq(null), any(TransactionValidationParams.class))) + when(transactionValidatorFactory + .get() + .validateForSender(eq(transaction1), eq(null), any(TransactionValidationParams.class))) .thenReturn(ValidationResult.invalid(NONCE_TOO_LOW)); transactionPool.addRemoteTransactions(asList(transaction0, transaction1)); assertTransactionPending(transaction0); assertTransactionNotPending(transaction1); verify(transactionBroadcaster).onTransactionsAdded(singletonList(transaction0)); - verify(transactionValidator).validate(eq(transaction0), any(Optional.class), any()); - verify(transactionValidator) + verify(transactionValidatorFactory.get()) + .validate(eq(transaction0), any(Optional.class), any()); + verify(transactionValidatorFactory.get()) .validateForSender(eq(transaction0), eq(null), any(TransactionValidationParams.class)); - verify(transactionValidator).validate(eq(transaction1), any(Optional.class), any()); - verify(transactionValidator).validateForSender(eq(transaction1), any(), any()); - verifyNoMoreInteractions(transactionValidator); + verify(transactionValidatorFactory.get()) + .validate(eq(transaction1), any(Optional.class), any()); + verify(transactionValidatorFactory.get()).validateForSender(eq(transaction1), any(), any()); + verifyNoMoreInteractions(transactionValidatorFactory.get()); } @Test @@ -423,7 +433,7 @@ public void shouldDiscardRemoteTransactionThatAlreadyExistsBeforeValidation() { transactionPool.addRemoteTransactions(singletonList(transaction0)); verify(transactions).containsTransaction(transaction0); - verifyNoInteractions(transactionValidator); + verifyNoInteractions(transactionValidatorFactory); } @Test @@ -551,9 +561,11 @@ public void shouldCallValidatorWithExpectedValidationParameters() { final ArgumentCaptor txValidationParamCaptor = ArgumentCaptor.forClass(TransactionValidationParams.class); - when(transactionValidator.validate(eq(transaction0), any(Optional.class), any())) + when(transactionValidatorFactory.get().validate(eq(transaction0), any(Optional.class), any())) .thenReturn(valid()); - when(transactionValidator.validateForSender(any(), any(), txValidationParamCaptor.capture())) + when(transactionValidatorFactory + .get() + .validateForSender(any(), any(), txValidationParamCaptor.capture())) .thenReturn(valid()); final TransactionValidationParams expectedValidationParams = @@ -647,10 +659,12 @@ protected void protocolSupportsTxReplayProtection( } protected void givenTransactionIsValid(final Transaction transaction) { - when(transactionValidator.validate(eq(transaction), any(Optional.class), any())) + when(transactionValidatorFactory.get().validate(eq(transaction), any(Optional.class), any())) .thenReturn(valid()); - when(transactionValidator.validateForSender( - eq(transaction), nullable(Account.class), any(TransactionValidationParams.class))) + when(transactionValidatorFactory + .get() + .validateForSender( + eq(transaction), nullable(Account.class), any(TransactionValidationParams.class))) .thenReturn(valid()); } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageProcessorTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageProcessorTest.java index 36c1a451d84..4b137ca3937 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageProcessorTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageProcessorTest.java @@ -30,6 +30,7 @@ import static org.mockito.Mockito.when; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.EthProtocol; @@ -43,7 +44,6 @@ import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLPException; import org.hyperledger.besu.metrics.StubMetricsSystem; -import org.hyperledger.besu.plugin.data.TransactionType; import java.time.Duration; import java.util.ArrayList; @@ -53,13 +53,16 @@ import java.util.stream.Collectors; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class NewPooledTransactionHashesMessageProcessorTest { @Mock private TransactionPool transactionPool; @@ -82,7 +85,7 @@ public class NewPooledTransactionHashesMessageProcessorTest { private NewPooledTransactionHashesMessageProcessor messageHandler; private StubMetricsSystem metricsSystem; - @Before + @BeforeEach public void setup() { metricsSystem = new StubMetricsSystem(); when(transactionPoolConfiguration.getEth65TrxAnnouncedBufferingPeriod()) diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageSenderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageSenderTest.java index 07e15b5eac6..ec6f772c796 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageSenderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageSenderTest.java @@ -42,8 +42,8 @@ import java.util.stream.Collectors; import com.google.common.collect.Sets; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; public class NewPooledTransactionHashesMessageSenderTest { @@ -61,7 +61,7 @@ public class NewPooledTransactionHashesMessageSenderTest { private PeerTransactionTracker transactionTracker; private NewPooledTransactionHashesMessageSender messageSender; - @Before + @BeforeEach public void setUp() { transactionTracker = new PeerTransactionTracker(); messageSender = new NewPooledTransactionHashesMessageSender(transactionTracker); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/PeerTransactionTrackerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/PeerTransactionTrackerTest.java index 05162fc2f02..e1f1c83f588 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/PeerTransactionTrackerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/PeerTransactionTrackerTest.java @@ -22,7 +22,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthPeer; import com.google.common.collect.ImmutableSet; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PeerTransactionTrackerTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactionEstimatedMemorySizeTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactionEstimatedMemorySizeTest.java index 48317545bed..d5b41d870e5 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactionEstimatedMemorySizeTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactionEstimatedMemorySizeTest.java @@ -18,6 +18,7 @@ import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; @@ -25,7 +26,6 @@ import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.evm.AccessListEntry; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.HashSet; import java.util.List; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java index 111fa072297..02df9cb177f 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java @@ -15,7 +15,7 @@ package org.hyperledger.besu.ethereum.eth.transactions; import static java.util.Collections.singletonList; -import static org.assertj.core.util.Preconditions.checkNotNull; +import static java.util.Objects.requireNonNull; import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryBlockchain; import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryWorldStateArchive; import static org.mockito.ArgumentMatchers.anyLong; @@ -96,8 +96,8 @@ public TestNode( final Integer port, final KeyPair kp, final DiscoveryConfiguration discoveryCfg) { - checkNotNull(vertx); - checkNotNull(discoveryCfg); + requireNonNull(vertx); + requireNonNull(discoveryCfg); final int listenPort = port != null ? port : 0; this.nodeKey = kp != null ? NodeKeyUtils.createFrom(kp) : NodeKeyUtils.generate(); @@ -269,6 +269,6 @@ public void receiveLocalTransaction(final Transaction transaction) { } public int getPendingTransactionCount() { - return transactionPool.getPendingTransactions().size(); + return transactionPool.count(); } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionBroadcasterTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionBroadcasterTest.java index 52193c74037..b7d6d054f93 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionBroadcasterTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionBroadcasterTest.java @@ -15,8 +15,8 @@ package org.hyperledger.besu.ethereum.eth.transactions; import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.datatypes.TransactionType.BLOB; import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.toTransactionList; -import static org.hyperledger.besu.plugin.data.TransactionType.BLOB; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; @@ -26,6 +26,7 @@ import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.manager.EthContext; @@ -33,7 +34,6 @@ import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.messages.EthPV65; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.ArrayList; import java.util.Collection; @@ -43,14 +43,17 @@ import java.util.stream.IntStream; import java.util.stream.Stream; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class TransactionBroadcasterTest { @Mock private EthContext ethContext; @@ -70,7 +73,7 @@ public class TransactionBroadcasterTest { private TransactionBroadcaster txBroadcaster; private ArgumentCaptor sendTaskCapture; - @Before + @BeforeEach public void setUp() { when(ethPeerNoEth65.hasSupportForMessage(EthPV65.NEW_POOLED_TRANSACTION_HASHES)) .thenReturn(Boolean.FALSE); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java index 865a9a9c2fb..78641da086d 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java @@ -51,7 +51,6 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; -import org.hyperledger.besu.plugin.data.EnodeURL; import org.hyperledger.besu.plugin.services.permissioning.NodeMessagePermissioningProvider; import org.hyperledger.besu.testutil.TestClock; @@ -62,14 +61,17 @@ import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Condition; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class TransactionPoolFactoryTest { @Mock ProtocolSchedule schedule; @Mock ProtocolContext context; @@ -78,11 +80,8 @@ public class TransactionPoolFactoryTest { @Mock EthContext ethContext; @Mock EthMessages ethMessages; @Mock EthScheduler ethScheduler; - - @Mock PendingTransactions pendingTransactions; @Mock PeerTransactionTracker peerTransactionTracker; @Mock TransactionsMessageSender transactionsMessageSender; - @Mock NewPooledTransactionHashesMessageSender newPooledTransactionHashesMessageSender; TransactionPool pool; @@ -94,18 +93,12 @@ public class TransactionPoolFactoryTest { ProtocolContext protocolContext; - @Before + @BeforeEach public void setup() { when(blockchain.getBlockHashByNumber(anyLong())).thenReturn(Optional.of(mock(Hash.class))); when(context.getBlockchain()).thenReturn(blockchain); - final NodeMessagePermissioningProvider nmpp = - new NodeMessagePermissioningProvider() { - @Override - public boolean isMessagePermitted(final EnodeURL destinationEnode, final int code) { - return true; - } - }; + final NodeMessagePermissioningProvider nmpp = (destinationEnode, code) -> true; ethPeers = new EthPeers( "ETH", @@ -279,7 +272,8 @@ public void createTransactionPool_shouldUseBaseFeePendingTransactionsSorter_when final TransactionPool pool = createTransactionPool(); - assertThat(pool.getPendingTransactions()).isInstanceOf(BaseFeePendingTransactionsSorter.class); + assertThat(pool.pendingTransactionsImplementation()) + .isEqualTo(BaseFeePendingTransactionsSorter.class); } @Test @@ -289,7 +283,8 @@ public void createTransactionPool_shouldUseBaseFeePendingTransactionsSorter_when final TransactionPool pool = createTransactionPool(); - assertThat(pool.getPendingTransactions()).isInstanceOf(GasPricePendingTransactionsSorter.class); + assertThat(pool.pendingTransactionsImplementation()) + .isEqualTo(GasPricePendingTransactionsSorter.class); } private void setupScheduleWith(final StubGenesisConfigOptions config) { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolLegacyTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolLegacyTest.java index 31f9c120726..e2e2946f3c9 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolLegacyTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolLegacyTest.java @@ -21,6 +21,7 @@ import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.REPLAY_PROTECTED_SIGNATURE_REQUIRED; import static org.mockito.Mockito.when; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; @@ -33,7 +34,6 @@ import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.eth.transactions.sorter.GasPricePendingTransactionsSorter; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.testutil.TestClock; import java.math.BigInteger; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolLondonTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolLondonTest.java index 3c17b39b133..fc03f9805ce 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolLondonTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolLondonTest.java @@ -21,6 +21,7 @@ import static org.mockito.Mockito.when; import org.hyperledger.besu.config.StubGenesisConfigOptions; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; @@ -40,7 +41,6 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.evm.internal.EvmConfiguration; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.testutil.TestClock; import java.math.BigInteger; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolReplacementHandlerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolReplacementHandlerTest.java index d678dd4fe47..f57d6fac3e7 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolReplacementHandlerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolReplacementHandlerTest.java @@ -21,23 +21,20 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public class TransactionPoolReplacementHandlerTest { - @Parameterized.Parameters public static Collection data() { return asList( new Object[][] { @@ -53,27 +50,20 @@ public static Collection data() { }); } - private final List rules; - private final PendingTransaction oldPendingTransaction; - private final PendingTransaction newPendingTransaction; - private final boolean expectedResult; private final BlockHeader header; - public TransactionPoolReplacementHandlerTest( - final List rules, - final PendingTransaction oldPendingTransaction, - final PendingTransaction newPendingTransaction, - final boolean expectedResult) { - this.rules = rules; - this.oldPendingTransaction = oldPendingTransaction; - this.newPendingTransaction = newPendingTransaction; - this.expectedResult = expectedResult; + public TransactionPoolReplacementHandlerTest() { header = mock(BlockHeader.class); when(header.getBaseFee()).thenReturn(Optional.empty()); } - @Test - public void shouldReplace() { + @ParameterizedTest + @MethodSource("data") + public void shouldReplace( + final List rules, + final PendingTransaction oldPendingTransaction, + final PendingTransaction newPendingTransaction, + final boolean expectedResult) { assertThat( new TransactionPoolReplacementHandler(rules) .shouldReplace(oldPendingTransaction, newPendingTransaction, header)) diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionReplacementRulesTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionReplacementRulesTest.java index f6b13813ff0..f4488fe857d 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionReplacementRulesTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionReplacementRulesTest.java @@ -20,24 +20,21 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.util.number.Percentage; import java.math.BigInteger; import java.util.Collection; import java.util.Optional; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public class TransactionReplacementRulesTest { - @Parameterized.Parameters public static Collection data() { return asList( new Object[][] { @@ -56,7 +53,6 @@ public static Collection data() { {frontierTx(100L), frontierTx(105L), Optional.of(Wei.of(3L)), 10, false}, {frontierTx(100L), frontierTx(110L), Optional.of(Wei.of(3L)), 10, false}, {frontierTx(100L), frontierTx(111L), Optional.of(Wei.of(3L)), 10, true}, - // TransactionReplacementByFeeMarketRule // eip1559 replacing frontier {frontierTx(5L), eip1559Tx(3L, 6L), Optional.of(Wei.of(1L)), 0, false}, @@ -81,27 +77,14 @@ public static Collection data() { }); } - private final PendingTransaction oldTx; - private final PendingTransaction newTx; - private final Optional baseFee; - private final int priceBump; - private final boolean expected; - - public TransactionReplacementRulesTest( + @ParameterizedTest + @MethodSource("data") + public void shouldReplace( final PendingTransaction oldTx, final PendingTransaction newTx, final Optional baseFee, final int priceBump, final boolean expected) { - this.oldTx = oldTx; - this.newTx = newTx; - this.baseFee = baseFee; - this.priceBump = priceBump; - this.expected = expected; - } - - @Test - public void shouldReplace() { BlockHeader mockHeader = mock(BlockHeader.class); when(mockHeader.getBaseFee()).thenReturn(baseFee); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageProcessorTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageProcessorTest.java index b8a3593b139..b49407871be 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageProcessorTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageProcessorTest.java @@ -28,13 +28,13 @@ import org.hyperledger.besu.ethereum.eth.messages.TransactionsMessage; import org.hyperledger.besu.metrics.StubMetricsSystem; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class TransactionsMessageProcessorTest { @Mock private TransactionPool transactionPool; @@ -49,7 +49,7 @@ public class TransactionsMessageProcessorTest { private TransactionsMessageProcessor messageHandler; private StubMetricsSystem metricsSystem; - @Before + @BeforeEach public void setup() { metricsSystem = new StubMetricsSystem(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageSenderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageSenderTest.java index c806b3fcb14..02a2d248bcb 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageSenderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageSenderTest.java @@ -33,7 +33,7 @@ import java.util.Set; import com.google.common.collect.Sets; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; public class TransactionsMessageSenderTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseFeePrioritizedTransactionsTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseFeePrioritizedTransactionsTest.java index f21c62e9d96..adbc7077d9b 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseFeePrioritizedTransactionsTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseFeePrioritizedTransactionsTest.java @@ -14,12 +14,13 @@ */ package org.hyperledger.besu.ethereum.eth.transactions.layered; -import static org.hyperledger.besu.plugin.data.TransactionType.EIP1559; -import static org.hyperledger.besu.plugin.data.TransactionType.FRONTIER; +import static org.hyperledger.besu.datatypes.TransactionType.EIP1559; +import static org.hyperledger.besu.datatypes.TransactionType.FRONTIER; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import org.hyperledger.besu.crypto.KeyPair; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; @@ -28,7 +29,6 @@ import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.Comparator; import java.util.List; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseTransactionPoolTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseTransactionPoolTest.java index defafb1b369..b735055445a 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseTransactionPoolTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseTransactionPoolTest.java @@ -20,6 +20,7 @@ import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; @@ -29,7 +30,6 @@ import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics; import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.metrics.StubMetricsSystem; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.Optional; import java.util.Random; @@ -110,7 +110,7 @@ protected TransactionTestFixture prepareTransaction( .nonce(nonce) .type(type); if (payloadSize > 0) { - var payloadBytes = Bytes.repeat((byte) 1, payloadSize); + var payloadBytes = Bytes.fromHexString("01".repeat(payloadSize)); tx.payload(payloadBytes); } if (type.supports1559FeeMarket()) { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredPendingTransactionsLegacyTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredPendingTransactionsLegacyTest.java index c1659446336..57cb9e1452f 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredPendingTransactionsLegacyTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredPendingTransactionsLegacyTest.java @@ -21,6 +21,7 @@ import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.REPLAY_PROTECTED_SIGNATURE_REQUIRED; import static org.mockito.Mockito.when; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; @@ -37,19 +38,18 @@ import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; -import org.hyperledger.besu.plugin.data.TransactionType; import java.math.BigInteger; import java.util.List; import java.util.Optional; import java.util.function.BiFunction; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; @SuppressWarnings("unchecked") -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class LayeredPendingTransactionsLegacyTest extends AbstractTransactionsLayeredPendingTransactionsTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredPendingTransactionsLondonTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredPendingTransactionsLondonTest.java index 9be50ea03ca..068988464ab 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredPendingTransactionsLondonTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredPendingTransactionsLondonTest.java @@ -21,6 +21,7 @@ import static org.mockito.Mockito.when; import org.hyperledger.besu.config.StubGenesisConfigOptions; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; @@ -44,7 +45,6 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.evm.internal.EvmConfiguration; -import org.hyperledger.besu.plugin.data.TransactionType; import java.math.BigInteger; import java.util.List; @@ -52,7 +52,7 @@ import java.util.function.BiFunction; import java.util.function.Function; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class LayeredPendingTransactionsLondonTest extends AbstractTransactionsLayeredPendingTransactionsTest { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AbstractPendingTransactionsTestBase.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AbstractPendingTransactionsTestBase.java index 4c7b352f6cf..6b2318f0086 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AbstractPendingTransactionsTestBase.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AbstractPendingTransactionsTestBase.java @@ -58,7 +58,7 @@ import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import com.google.common.collect.Lists; -import org.junit.Test; +import org.junit.jupiter.api.Test; public abstract class AbstractPendingTransactionsTestBase { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/BaseFeePendingTransactionsTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/BaseFeePendingTransactionsTest.java index fc47600e247..41bf8763811 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/BaseFeePendingTransactionsTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/BaseFeePendingTransactionsTest.java @@ -14,11 +14,11 @@ */ package org.hyperledger.besu.ethereum.eth.transactions.sorter; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.testutil.TestClock; import java.time.Clock; diff --git a/ethereum/ethstats/build.gradle b/ethereum/ethstats/build.gradle index c361c16c860..2097f0f1bb6 100644 --- a/ethereum/ethstats/build.gradle +++ b/ethereum/ethstats/build.gradle @@ -34,7 +34,7 @@ dependencies { implementation 'com.google.guava:guava' implementation 'com.squareup.okhttp3:okhttp' implementation 'io.vertx:vertx-core' - implementation 'org.apache.tuweni:tuweni-bytes' + implementation 'io.tmio:tuweni-bytes' implementation project(':consensus:clique') implementation project(':config') @@ -57,10 +57,8 @@ dependencies { testImplementation project(':testutil') testImplementation project(':metrics:core') - testImplementation 'junit:junit' testImplementation 'org.assertj:assertj-core' testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.mockito:mockito-core' - - testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' + testImplementation 'org.mockito:mockito-junit-jupiter' } diff --git a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/EthStatsService.java b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/EthStatsService.java index 873fad9324d..5adbf8978fb 100644 --- a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/EthStatsService.java +++ b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/EthStatsService.java @@ -402,7 +402,7 @@ private void sendHistoryReport(final List blocks) { /** Sends the number of pending transactions in the pool */ private void sendPendingTransactionReport() { - final int pendingTransactionsNumber = transactionPool.getPendingTransactions().size(); + final int pendingTransactionsNumber = transactionPool.count(); final PendingTransactionsReport pendingTransactionsReport = ImmutablePendingTransactionsReport.builder() diff --git a/ethereum/ethstats/src/test/java/org/hyperledger/besu/ethstats/EthStatsServiceTest.java b/ethereum/ethstats/src/test/java/org/hyperledger/besu/ethstats/EthStatsServiceTest.java index da4b08caaeb..1e46f90fd1d 100644 --- a/ethereum/ethstats/src/test/java/org/hyperledger/besu/ethstats/EthStatsServiceTest.java +++ b/ethereum/ethstats/src/test/java/org/hyperledger/besu/ethstats/EthStatsServiceTest.java @@ -50,15 +50,18 @@ import io.vertx.core.http.HttpClientOptions; import io.vertx.core.http.WebSocket; import io.vertx.core.http.WebSocketConnectOptions; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; @SuppressWarnings("unchecked") -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class EthStatsServiceTest { @Mock private Vertx vertx; @@ -94,7 +97,7 @@ public class EthStatsServiceTest { private EthStatsService ethStatsService; - @Before + @BeforeEach public void initMocks() { when(ethProtocolManager.ethContext()).thenReturn(ethContext); when(ethContext.getScheduler()).thenReturn(ethScheduler); diff --git a/ethereum/ethstats/src/test/java/org/hyperledger/besu/ethstats/util/EthStatsConnectOptionsTest.java b/ethereum/ethstats/src/test/java/org/hyperledger/besu/ethstats/util/EthStatsConnectOptionsTest.java index 577ac5b3c41..f3227a62e76 100644 --- a/ethereum/ethstats/src/test/java/org/hyperledger/besu/ethstats/util/EthStatsConnectOptionsTest.java +++ b/ethereum/ethstats/src/test/java/org/hyperledger/besu/ethstats/util/EthStatsConnectOptionsTest.java @@ -19,7 +19,7 @@ import java.nio.file.Path; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; diff --git a/ethereum/ethstats/src/test/java/org/hyperledger/besu/ethstats/util/PrimusHeartBeatsHelperTest.java b/ethereum/ethstats/src/test/java/org/hyperledger/besu/ethstats/util/PrimusHeartBeatsHelperTest.java index 10506298902..4d9e20fb1e0 100644 --- a/ethereum/ethstats/src/test/java/org/hyperledger/besu/ethstats/util/PrimusHeartBeatsHelperTest.java +++ b/ethereum/ethstats/src/test/java/org/hyperledger/besu/ethstats/util/PrimusHeartBeatsHelperTest.java @@ -22,7 +22,7 @@ import java.util.regex.Pattern; import io.vertx.core.http.WebSocket; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; @SuppressWarnings("unchecked") diff --git a/ethereum/evmtool/build.gradle b/ethereum/evmtool/build.gradle index f4bf5d8030f..c5604d7a52c 100644 --- a/ethereum/evmtool/build.gradle +++ b/ethereum/evmtool/build.gradle @@ -56,17 +56,17 @@ dependencies { implementation 'info.picocli:picocli' implementation 'io.vertx:vertx-core' - runtimeOnly 'org.slf4j:slf4j-nop' - annotationProcessor 'com.google.dagger:dagger-compiler' annotationProcessor 'info.picocli:picocli-codegen' - testImplementation 'junit:junit' testImplementation 'org.assertj:assertj-core' testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.mockito:mockito-core' testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' + + // No logging in grallvm EvmTool + nativeImageClasspath 'org.slf4j:slf4j-nop' } mainClassName = 'org.hyperledger.besu.evmtool.EvmTool' diff --git a/ethereum/evmtool/src/main/graal/reflection-config.json b/ethereum/evmtool/src/main/graal/reflection-config.json index 12c2d5e9737..bedc322c76c 100644 --- a/ethereum/evmtool/src/main/graal/reflection-config.json +++ b/ethereum/evmtool/src/main/graal/reflection-config.json @@ -102,7 +102,7 @@ "unsafeAllocated": true }, { - "name": "org.hyperledger.besu.evmtool.T8nSubCommand$RejectedTransaction", + "name": "org.hyperledger.besu.evmtool.T8nExecutor$RejectedTransaction", "queryAllPublicConstructors": true, "queryAllPublicMethods": true, "allDeclaredConstructors": true, diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/B11rSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/B11rSubCommand.java index e1143c5a8fe..6c65fc2804e 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/B11rSubCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/B11rSubCommand.java @@ -19,10 +19,12 @@ import static org.hyperledger.besu.evmtool.B11rSubCommand.COMMAND_ALIAS; import static org.hyperledger.besu.evmtool.B11rSubCommand.COMMAND_NAME; +import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; import org.hyperledger.besu.ethereum.referencetests.BlockchainReferenceTestCaseSpec.ReferenceTestBlockHeader; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; +import org.hyperledger.besu.util.LogConfigurator; import java.io.FileNotFoundException; import java.io.FileOutputStream; @@ -152,6 +154,9 @@ public B11rSubCommand(final EvmToolCommand parentCommand) { @Override public void run() { + LogConfigurator.setLevel("", "OFF"); + // presume ethereum mainnet for reference and state tests + SignatureAlgorithmFactory.setDefaultInstance(); ObjectMapper objectMapper = JsonUtils.createObjectMapper(); final ObjectReader b11rReader = objectMapper.reader(); @@ -210,7 +215,7 @@ public void run() { if (config.has("txs")) { String txsString = config.get("txs").textValue(); - if (txsString.length() > 0) { + if (!txsString.isEmpty()) { txsBytes = Bytes.fromHexString(txsString); } } @@ -222,7 +227,7 @@ public void run() { BytesValueRLPOutput rlpOut = new BytesValueRLPOutput(); rlpOut.startList(); newHeader.writeTo(rlpOut); - if (txsBytes != null && txsBytes.size() > 0) { + if (txsBytes != null && !txsBytes.isEmpty()) { rlpOut.writeRaw(txsBytes); } else { rlpOut.startList(); diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/BenchmarkSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/BenchmarkSubCommand.java new file mode 100644 index 00000000000..078a6e1c4c2 --- /dev/null +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/BenchmarkSubCommand.java @@ -0,0 +1,95 @@ +/* + * Copyright contributors to Hyperledger Besu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evmtool; + +import static org.hyperledger.besu.evmtool.BenchmarkSubCommand.COMMAND_NAME; +import static picocli.CommandLine.ScopeType.INHERIT; + +import org.hyperledger.besu.BesuInfo; +import org.hyperledger.besu.evm.EvmSpecVersion; +import org.hyperledger.besu.evmtool.benchmarks.AltBN128Benchmark; +import org.hyperledger.besu.evmtool.benchmarks.BenchmarkExecutor; +import org.hyperledger.besu.evmtool.benchmarks.ECRecoverBenchmark; +import org.hyperledger.besu.evmtool.benchmarks.ModExpBenchmark; +import org.hyperledger.besu.evmtool.benchmarks.Secp256k1Benchmark; + +import java.io.PrintStream; +import java.util.EnumSet; + +import picocli.CommandLine; +import picocli.CommandLine.Option; +import picocli.CommandLine.Parameters; +import picocli.CommandLine.ParentCommand; + +@CommandLine.Command( + name = COMMAND_NAME, + description = "Execute an Ethereum State Test.", + mixinStandardHelpOptions = true, + versionProvider = VersionProvider.class) +public class BenchmarkSubCommand implements Runnable { + public static final String COMMAND_NAME = "benchmark"; + private final PrintStream output; + + enum Benchmark { + altBn128(new AltBN128Benchmark()), + // blake2f + EcRecover(new ECRecoverBenchmark()), + ModExp(new ModExpBenchmark()), + Secp256k1(new Secp256k1Benchmark()); + + final BenchmarkExecutor benchmarkExecutor; + + Benchmark(final BenchmarkExecutor benchmarkExecutor) { + this.benchmarkExecutor = benchmarkExecutor; + } + } + + @Option( + names = {"--native"}, + description = "Use the native libraries.", + scope = INHERIT, + negatable = true) + Boolean nativeCode; + + @Option( + names = {"--fork"}, + paramLabel = "", + description = "Fork to evaluate, when it impacts gas costing.") + String fork = EvmSpecVersion.defaultVersion().getName(); + + @Parameters(description = "One or more of ${COMPLETION-CANDIDATES}.") + EnumSet benchmarks = EnumSet.noneOf(Benchmark.class); + + @ParentCommand EvmToolCommand parentCommand; + + public BenchmarkSubCommand() { + // PicoCLI requires this + this(System.out); + } + + public BenchmarkSubCommand(final PrintStream output) { + this.output = output; + } + + @Override + public void run() { + System.out.println(BesuInfo.version()); + var benchmarksToRun = benchmarks.isEmpty() ? EnumSet.allOf(Benchmark.class) : benchmarks; + for (var benchmark : benchmarksToRun) { + System.out.println("Benchmarks for " + benchmark); + benchmark.benchmarkExecutor.runBenchmark(output, nativeCode, fork); + } + } +} diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java index 67bfadccb09..4c51fc55998 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java @@ -36,13 +36,12 @@ import org.hyperledger.besu.evm.code.CodeInvalid; import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.log.LogsBloomFilter; -import org.hyperledger.besu.evm.precompile.PrecompileContractRegistry; -import org.hyperledger.besu.evm.processor.MessageCallProcessor; import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.tracing.StandardJsonTracer; import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.metrics.MetricsSystemModule; +import org.hyperledger.besu.util.LogConfigurator; import java.io.BufferedWriter; import java.io.ByteArrayInputStream; @@ -52,7 +51,6 @@ import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.time.Instant; -import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @@ -87,6 +85,7 @@ footerHeading = "%n", footer = "Hyperledger Besu is licensed under the Apache License 2.0", subcommands = { + BenchmarkSubCommand.class, B11rSubCommand.class, CodeValidateSubCommand.class, StateTestSubCommand.class, @@ -229,6 +228,9 @@ void execute(final InputStream input, final PrintWriter output, final String[] a out = output; in = input; + // don't require exact case to match enum values + commandLine.setCaseInsensitiveEnumValuesAllowed(true); + // add dagger-injected options commandLine.addMixin("Dagger Options", daggerOptions); @@ -283,6 +285,7 @@ private static void addForkHelp(final CommandLine subCommandLine) { @Override public void run() { + LogConfigurator.setLevel("", "OFF"); try { final EvmToolComponent component = DaggerEvmToolComponent.builder() @@ -343,8 +346,6 @@ public void run() { .orElse(0L); long txGas = gas - intrinsicGasCost - accessListCost; - final PrecompileContractRegistry precompileContractRegistry = - protocolSpec.getPrecompileContractRegistry(); final EVM evm = protocolSpec.getEvm(); Code code = evm.getCode(Hash.hash(codeBytes), codeBytes); if (!code.isValid()) { @@ -365,11 +366,9 @@ public void run() { updater.getOrCreate(sender); updater.getOrCreate(receiver); - final Deque messageFrameStack = new ArrayDeque<>(); - messageFrameStack.add( + MessageFrame initialMessageFrame = MessageFrame.builder() .type(MessageFrame.Type.MESSAGE_CALL) - .messageFrameStack(messageFrameStack) .worldUpdater(updater) .initialGas(txGas) .contract(Address.ZERO) @@ -382,17 +381,16 @@ public void run() { .apparentValue(ethValue) .code(code) .blockValues(blockHeader) - .depth(0) .completer(c -> {}) .miningBeneficiary(blockHeader.getCoinbase()) .blockHashLookup(new CachingBlockHashLookup(blockHeader, component.getBlockchain())) - .build()); + .build(); + Deque messageFrameStack = initialMessageFrame.getMessageFrameStack(); - final MessageCallProcessor mcp = new MessageCallProcessor(evm, precompileContractRegistry); stopwatch.start(); while (!messageFrameStack.isEmpty()) { final MessageFrame messageFrame = messageFrameStack.peek(); - mcp.process(messageFrame, tracer); + protocolSpec.getTransactionProcessor().process(messageFrame, tracer); if (messageFrameStack.isEmpty()) { stopwatch.stop(); if (lastTime == 0) { @@ -446,7 +444,7 @@ public static void dumpWorldState(final WorldState worldState, final PrintWriter account -> { out.println( " \"" + account.getAddress().map(Address::toHexString).orElse("-") + "\": {"); - if (account.getCode() != null && account.getCode().size() > 0) { + if (account.getCode() != null && !account.getCode().isEmpty()) { out.println(" \"code\": \"" + account.getCode().toHexString() + "\","); } NavigableMap storageEntries = diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java index 89c361b7d42..5445fe2b43d 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java @@ -17,6 +17,8 @@ import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.config.StubGenesisConfigOptions; +import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.crypto.SignatureAlgorithmType; import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; @@ -33,6 +35,8 @@ import java.util.function.Supplier; import javax.inject.Named; +import picocli.CommandLine; + class MainnetGenesisFileModule extends GenesisFileModule { MainnetGenesisFileModule(final String genesisConfig) { @@ -49,6 +53,19 @@ ProtocolSchedule provideProtocolSchedule( final GenesisConfigOptions configOptions, @Named("Fork") final Optional fork, @Named("RevertReasonEnabled") final boolean revertReasonEnabled) { + + final Optional ecCurve = configOptions.getEcCurve(); + if (ecCurve.isEmpty()) { + SignatureAlgorithmFactory.setDefaultInstance(); + } else { + try { + SignatureAlgorithmFactory.setInstance(SignatureAlgorithmType.create(ecCurve.get())); + } catch (final IllegalArgumentException e) { + throw new CommandLine.InitializationException( + "Invalid genesis file configuration for ecCurve. " + e.getMessage()); + } + } + if (fork.isPresent()) { var schedules = createSchedules(); var schedule = schedules.get(fork.map(String::toLowerCase).get()); diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java index 4b86cbb0eb0..a670ff945b2 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java @@ -20,7 +20,8 @@ import static org.hyperledger.besu.ethereum.referencetests.ReferenceTestProtocolSchedules.shouldClearEmptyAccounts; import static org.hyperledger.besu.evmtool.StateTestSubCommand.COMMAND_NAME; -import org.hyperledger.besu.datatypes.DataGas; +import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -44,6 +45,7 @@ import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evmtool.exception.UnsupportedForkException; +import org.hyperledger.besu.util.LogConfigurator; import java.io.BufferedReader; import java.io.File; @@ -80,6 +82,21 @@ public class StateTestSubCommand implements Runnable { description = "Force the state tests to run on a specific fork.") private String fork = null; + @Option( + names = {"--data-index"}, + description = "Limit execution to one data variable.") + private Integer dataIndex = null; + + @Option( + names = {"--gas-index"}, + description = "Limit execution to one gas variable.") + private Integer gasIndex = null; + + @Option( + names = {"--value-index"}, + description = "Limit execution to one value variable.") + private Integer valueIndex = null; + @ParentCommand private final EvmToolCommand parentCommand; @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") // picocli does it magically @@ -98,6 +115,9 @@ public StateTestSubCommand() { @Override public void run() { + LogConfigurator.setLevel("", "OFF"); + // presume ethereum mainnet for reference and state tests + SignatureAlgorithmFactory.setDefaultInstance(); final ObjectMapper stateTestMapper = JsonUtils.createObjectMapper(); final JavaType javaType = @@ -167,6 +187,15 @@ private void traceTestSpecs(final String test, final List extractTransactions( + final PrintWriter out, + final Iterator it, + final List transactions, + final List rejections) { + int i = 0; + while (it.hasNext()) { + try { + JsonNode txNode = it.next(); + if (txNode.isTextual()) { + BytesValueRLPInput rlpInput = + new BytesValueRLPInput(Bytes.fromHexString(txNode.asText()), false); + rlpInput.enterList(); + while (!rlpInput.isEndOfCurrentList()) { + Transaction tx = Transaction.readFrom(rlpInput); + transactions.add(tx); + } + } else if (txNode.isObject()) { + if (txNode.has("txBytes")) { + Transaction tx = + Transaction.readFrom(Bytes.fromHexString(txNode.get("txbytes").asText())); + transactions.add(tx); + } else { + Transaction.Builder builder = Transaction.builder(); + int type = Bytes.fromHexStringLenient(txNode.get("type").textValue()).toInt(); + BigInteger chainId = + Bytes.fromHexStringLenient(txNode.get("chainId").textValue()) + .toUnsignedBigInteger(); + TransactionType transactionType = TransactionType.of(type == 0 ? 0xf8 : type); + builder.type(transactionType); + builder.nonce(Bytes.fromHexStringLenient(txNode.get("nonce").textValue()).toLong()); + builder.gasLimit(Bytes.fromHexStringLenient(txNode.get("gas").textValue()).toLong()); + builder.value(Wei.fromHexString(txNode.get("value").textValue())); + builder.payload(Bytes.fromHexString(txNode.get("input").textValue())); + + if (txNode.has("gasPrice")) { + builder.gasPrice(Wei.fromHexString(txNode.get("gasPrice").textValue())); + } + if (txNode.has("maxPriorityFeePerGas")) { + builder.maxPriorityFeePerGas( + Wei.fromHexString(txNode.get("maxPriorityFeePerGas").textValue())); + } + if (txNode.has("maxFeePerGas")) { + builder.maxFeePerGas(Wei.fromHexString(txNode.get("maxFeePerGas").textValue())); + } + if (txNode.has("maxFeePerBlobGas")) { + builder.maxFeePerBlobGas( + Wei.fromHexString(txNode.get("maxFeePerBlobGas").textValue())); + } + + if (txNode.has("to")) { + builder.to(Address.fromHexString(txNode.get("to").textValue())); + } + BigInteger v = + Bytes.fromHexStringLenient(txNode.get("v").textValue()).toUnsignedBigInteger(); + if (transactionType.requiresChainId() || (v.compareTo(REPLAY_PROTECTED_V_MIN) > 0)) { + // chainid if protected + builder.chainId(chainId); + } + + if (txNode.has("accessList")) { + JsonNode accessList = txNode.get("accessList"); + if (!accessList.isArray()) { + out.printf( + "TX json node unparseable: expected accessList to be an array - %s%n", txNode); + continue; + } + List entries = new ArrayList<>(accessList.size()); + for (JsonNode entryAsJson : accessList) { + Address address = Address.fromHexString(entryAsJson.get("address").textValue()); + List storageKeys = + StreamSupport.stream( + Spliterators.spliteratorUnknownSize( + entryAsJson.get("storageKeys").elements(), Spliterator.ORDERED), + false) + .map(JsonNode::textValue) + .toList(); + var accessListEntry = AccessListEntry.createAccessListEntry(address, storageKeys); + entries.add(accessListEntry); + } + builder.accessList(entries); + } + + if (txNode.has("blobVersionedHashes")) { + JsonNode blobVersionedHashes = txNode.get("blobVersionedHashes"); + if (!blobVersionedHashes.isArray()) { + out.printf( + "TX json node unparseable: expected blobVersionedHashes to be an array - %s%n", + txNode); + continue; + } + + List entries = new ArrayList<>(blobVersionedHashes.size()); + for (JsonNode versionedHashNode : blobVersionedHashes) { + entries.add( + new VersionedHash(Bytes32.fromHexString(versionedHashNode.textValue()))); + } + builder.versionedHashes(entries); + } + + if (txNode.has("secretKey")) { + SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance(); + KeyPair keys = + signatureAlgorithm.createKeyPair( + signatureAlgorithm.createPrivateKey( + Bytes32.fromHexString(txNode.get("secretKey").textValue()))); + + transactions.add(builder.signAndBuild(keys)); + } else { + if (transactionType == TransactionType.FRONTIER) { + if (v.compareTo(REPLAY_PROTECTED_V_MIN) > 0) { + v = + v.subtract(REPLAY_PROTECTED_V_BASE) + .subtract(chainId.multiply(BigInteger.TWO)); + } else { + v = v.subtract(REPLAY_UNPROTECTED_V_BASE); + } + } + builder.signature( + SignatureAlgorithmFactory.getInstance() + .createSignature( + Bytes.fromHexStringLenient(txNode.get("r").textValue()) + .toUnsignedBigInteger(), + Bytes.fromHexStringLenient(txNode.get("s").textValue()) + .toUnsignedBigInteger(), + v.byteValueExact())); + transactions.add(builder.build()); + } + } + } else { + out.printf("TX json node unparseable: %s%n", txNode); + } + } catch (IllegalArgumentException iae) { + rejections.add(new RejectedTransaction(i, iae.getMessage())); + } + i++; + } + return transactions; + } + static T8nResult runTest( final Long chainId, final String fork, @@ -72,6 +231,7 @@ static T8nResult runTest( final ReferenceTestEnv referenceTestEnv, final MutableWorldState initialWorldState, final List transactions, + final List rejections, final TracerManager tracerManager) { final ReferenceTestProtocolSchedules referenceTestProtocolSchedules = @@ -91,11 +251,13 @@ static T8nResult runTest( final MainnetTransactionProcessor processor = protocolSpec.getTransactionProcessor(); final WorldUpdater worldStateUpdater = worldState.updater(); final ReferenceTestBlockchain blockchain = new ReferenceTestBlockchain(blockHeader.getNumber()); - // Todo: EIP-4844 use the excessDataGas of the parent instead of DataGas.ZERO - final Wei dataGasPrice = protocolSpec.getFeeMarket().dataPrice(DataGas.ZERO); + final Wei blobGasPrice = + protocolSpec + .getFeeMarket() + .blobGasPricePerGas(blockHeader.getExcessBlobGas().orElse(BlobGas.ZERO)); List receipts = new ArrayList<>(); - List invalidTransactions = new ArrayList<>(); + List invalidTransactions = new ArrayList<>(rejections); List validTransactions = new ArrayList<>(); ArrayNode receiptsArray = objectMapper.createArrayNode(); long gasUsed = 0; @@ -119,7 +281,7 @@ static T8nResult runTest( false, TransactionValidationParams.processingBlock(), tracer, - dataGasPrice); + blobGasPrice); tracerManager.disposeTracer(tracer); } catch (Exception e) { throw new RuntimeException(e); @@ -138,8 +300,7 @@ static T8nResult runTest( } if (result.isInvalid()) { invalidTransactions.add( - new T8nSubCommand.RejectedTransaction( - i, result.getValidationResult().getErrorMessage())); + new RejectedTransaction(i, result.getValidationResult().getErrorMessage())); } else { validTransactions.add(transaction); @@ -232,7 +393,7 @@ static T8nResult runTest( resultObject.put( "currentDifficulty", - blockHeader.getDifficultyBytes().trimLeadingZeros().size() > 0 + !blockHeader.getDifficultyBytes().trimLeadingZeros().isEmpty() ? blockHeader.getDifficultyBytes().toShortHexString() : null); resultObject.put("gasUsed", Bytes.ofUnsignedLong(gasUsed).toQuantityHexString()); @@ -242,6 +403,17 @@ static T8nResult runTest( blockHeader .getWithdrawalsRoot() .ifPresent(wr -> resultObject.put("withdrawalsRoot", wr.toHexString())); + blockHeader + .getBlobGasUsed() + .ifPresentOrElse( + bgu -> resultObject.put("blobGasUsed", Bytes.ofUnsignedLong(bgu).toQuantityHexString()), + () -> + blockHeader + .getExcessBlobGas() + .ifPresent(ebg -> resultObject.put("blobGasUsed", "0x0"))); + blockHeader + .getExcessBlobGas() + .ifPresent(ebg -> resultObject.put("currentExcessBlobGas", ebg.toShortHexString())); ObjectNode allocObject = objectMapper.createObjectNode(); worldState @@ -252,7 +424,7 @@ static T8nResult runTest( ObjectNode accountObject = allocObject.putObject( account.getAddress().map(Address::toHexString).orElse("0x")); - if (account.getCode() != null && account.getCode().size() > 0) { + if (account.getCode() != null && !account.getCode().isEmpty()) { accountObject.put("code", account.getCode().toHexString()); } NavigableMap storageEntries = diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nServerSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nServerSubCommand.java index a93ac8ac7a1..eec78ee50d1 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nServerSubCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nServerSubCommand.java @@ -15,33 +15,36 @@ */ package org.hyperledger.besu.evmtool; -import org.hyperledger.besu.crypto.KeyPair; -import org.hyperledger.besu.crypto.SignatureAlgorithm; +import static org.hyperledger.besu.evmtool.T8nExecutor.extractTransactions; + import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; -import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.referencetests.ReferenceTestEnv; import org.hyperledger.besu.ethereum.referencetests.ReferenceTestWorldState; -import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; +import org.hyperledger.besu.evm.EvmSpecVersion; import org.hyperledger.besu.evm.tracing.OperationTracer; -import org.hyperledger.besu.plugin.data.TransactionType; +import org.hyperledger.besu.evmtool.T8nExecutor.RejectedTransaction; import org.hyperledger.besu.util.LogConfigurator; -import java.math.BigInteger; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectReader; +import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.TextNode; import io.vertx.core.Vertx; -import io.vertx.core.json.JsonArray; -import io.vertx.core.json.JsonObject; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpServerOptions; +import io.vertx.core.http.HttpServerRequest; import picocli.CommandLine; @CommandLine.Command( @@ -63,151 +66,143 @@ public class T8nServerSubCommand implements Runnable { @Override public void run() { LogConfigurator.setLevel("", "OFF"); + // presume ethereum mainnet for reference and state tests + SignatureAlgorithmFactory.setDefaultInstance(); Vertx.vertx() - .createHttpServer() - .requestHandler( - req -> - req.bodyHandler( - body -> { - JsonObject t8nRequest = body.toJsonObject(); - JsonObject state = t8nRequest.getJsonObject("state"); - String fork = state.getString("fork"); - Long chainId = Long.valueOf(state.getString("chainid")); - String reward = state.getString("reward"); - - JsonObject input = t8nRequest.getJsonObject("input"); - ReferenceTestEnv referenceTestEnv = - input.getJsonObject("env").mapTo(ReferenceTestEnv.class); - ReferenceTestWorldState initialWorldState = - input.getJsonObject("alloc").mapTo(ReferenceTestWorldState.class); - initialWorldState.persist(null); - List transactions = Collections.emptyList(); - Object txs = input.getValue("txs"); - if (txs != null) { - if (txs instanceof JsonArray txsArray) { - transactions = extractTransactions(txsArray); - } else if (txs instanceof String tx) { - transactions = - extractTransactions(new JsonArray().add(removeSurrounding("\"", tx))); - } - } - - ObjectMapper objectMapper = JsonUtils.createObjectMapper(); - final T8nExecutor.T8nResult result = - T8nExecutor.runTest( - chainId, - fork, - reward, - objectMapper, - referenceTestEnv, - initialWorldState, - transactions, - new T8nExecutor.TracerManager() { - @Override - public OperationTracer getManagedTracer( - final int txIndex, final Hash txHash) { - return OperationTracer.NO_TRACING; - } - - @Override - public void disposeTracer(final OperationTracer tracer) { - // No output streams to dispose of - } - }); - - ObjectNode outputObject = objectMapper.createObjectNode(); - outputObject.set("alloc", result.allocObject()); - outputObject.set("body", result.bodyBytes()); - outputObject.set("result", result.resultObject()); - - try { - req.response() - .putHeader("Content-Type", "application/json") - .end( - objectMapper - .writerWithDefaultPrettyPrinter() - .writeValueAsString(outputObject)); - } catch (JsonProcessingException e) { - req.response().setStatusCode(500).end(e.getMessage()); - } - })) - .listen(port, host) + .createHttpServer( + new HttpServerOptions() + .setHost(host) + .setPort(port) + .setHandle100ContinueAutomatically(true) + .setCompressionSupported(true)) + .requestHandler(req -> req.bodyHandler(body -> handle(req, body))) + .listen() .onSuccess( server -> System.out.println("Transition server listening on " + server.actualPort())) .onFailure( err -> System.err.println("Failed to start transition server: " + err.getMessage())); } - private List extractTransactions(final JsonArray jsonArray) { - List transactions = new ArrayList<>(); - for (int i = 0; i < jsonArray.size(); i++) { - Object rawTx = jsonArray.getValue(i); - if (rawTx instanceof String txNode) { - BytesValueRLPInput rlpInput = new BytesValueRLPInput(Bytes.fromHexString(txNode), false); - rlpInput.enterList(); - while (!rlpInput.isEndOfCurrentList()) { - Transaction tx = Transaction.readFrom(rlpInput); - transactions.add(tx); - } - } else if (rawTx instanceof JsonObject txNode) { - if (txNode.containsKey("txBytes")) { - JsonObject txBytesNode = txNode.getJsonObject("txBytes"); - Transaction tx = - Transaction.readFrom(Bytes.fromHexString(txBytesNode.getString("txbytes"))); - transactions.add(tx); - } else { - Transaction.Builder builder = Transaction.builder(); - int type = Bytes.fromHexStringLenient(txNode.getString("type")).toInt(); - TransactionType transactionType = TransactionType.of(type == 0 ? 0xf8 : type); - builder.type(transactionType); - builder.nonce(Bytes.fromHexStringLenient(txNode.getString("nonce")).toLong()); - builder.gasPrice(Wei.fromHexString(txNode.getString("gasPrice"))); - builder.gasLimit(Bytes.fromHexStringLenient(txNode.getString("gas")).toLong()); - builder.value(Wei.fromHexString(txNode.getString("value"))); - builder.payload(Bytes.fromHexString(txNode.getString("input"))); - if (txNode.containsKey("to")) { - builder.to(Address.fromHexString(txNode.getString("to"))); - } - - if (transactionType.requiresChainId() - || !txNode.containsKey("protected") - || txNode.getBoolean("protected")) { - // chainid if protected - builder.chainId( - new BigInteger( - 1, Bytes.fromHexStringLenient(txNode.getString("chainId")).toArrayUnsafe())); - } - - if (txNode.containsKey("secretKey")) { - SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance(); - KeyPair keys = - signatureAlgorithm.createKeyPair( - signatureAlgorithm.createPrivateKey( - Bytes32.fromHexString(txNode.getString("secretKey")))); - - transactions.add(builder.signAndBuild(keys)); - } else { - builder.signature( - SignatureAlgorithmFactory.getInstance() - .createSignature( - Bytes.fromHexString(txNode.getString("r")).toUnsignedBigInteger(), - Bytes.fromHexString(txNode.getString("s")).toUnsignedBigInteger(), - Bytes.fromHexString(txNode.getString("v")) - .toUnsignedBigInteger() - .subtract(Transaction.REPLAY_UNPROTECTED_V_BASE) - .byteValueExact())); - transactions.add(builder.build()); - } + void handle(final HttpServerRequest req, final Buffer body) { + ObjectMapper objectMapper = JsonUtils.createObjectMapper(); + final ObjectReader t8nReader = objectMapper.reader(); + try { + var t8nRequest = t8nReader.readTree(body.toString()); + JsonNode state = t8nRequest.get("state"); + JsonNode input = t8nRequest.get("input"); + + if (state != null && input != null) { + handleT8nRequest(req, objectMapper, state, input); + } else { + sendHelp(req, objectMapper); + } + req.response().send(); + } catch (JsonProcessingException e) { + req.response().setStatusCode(500).end(e.getMessage()); + } + } + + void handleT8nRequest( + final HttpServerRequest req, + final ObjectMapper objectMapper, + final JsonNode state, + final JsonNode input) { + try { + String fork = state.get("fork").asText(); + Long chainId = Long.valueOf(state.get("chainid").asText()); + String reward = state.get("reward").asText(); + + ReferenceTestEnv referenceTestEnv = + objectMapper.convertValue(input.get("env"), ReferenceTestEnv.class); + ReferenceTestWorldState initialWorldState = + objectMapper.convertValue(input.get("alloc"), ReferenceTestWorldState.class); + initialWorldState.persist(null); + List transactions = new ArrayList<>(); + List rejections = new ArrayList<>(); + JsonNode txs = input.get("txs"); + if (txs != null) { + if (txs instanceof ArrayNode txsArray) { + extractTransactions( + new PrintWriter(System.err, true, StandardCharsets.UTF_8), + txsArray.elements(), + transactions, + rejections); + } else if (txs instanceof TextNode txt) { + transactions = + extractTransactions( + new PrintWriter(System.err, true, StandardCharsets.UTF_8), + List.of(txt).iterator(), + transactions, + rejections); } } + + final T8nExecutor.T8nResult result = + T8nExecutor.runTest( + chainId, + fork, + reward, + objectMapper, + referenceTestEnv, + initialWorldState, + transactions, + rejections, + new T8nExecutor.TracerManager() { + @Override + public OperationTracer getManagedTracer(final int txIndex, final Hash txHash) { + return OperationTracer.NO_TRACING; + } + + @Override + public void disposeTracer(final OperationTracer tracer) { + // No output streams to dispose of + } + }); + + ObjectNode outputObject = objectMapper.createObjectNode(); + outputObject.set("alloc", result.allocObject()); + outputObject.set("body", result.bodyBytes()); + outputObject.set("result", result.resultObject()); + + try { + String response = + objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(outputObject); + req.response().setChunked(true); + req.response().putHeader("Content-Type", "application/json").send(response); + } catch (JsonProcessingException e) { + req.response().setStatusCode(500).end(e.getMessage()); + } + } catch (Throwable t) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(baos, true, StandardCharsets.UTF_8); + t.printStackTrace(ps); + ObjectNode json = objectMapper.createObjectNode(); + json.put("error", t.getMessage()); + json.put("stacktrace", baos.toString(StandardCharsets.UTF_8)); + + t.printStackTrace(System.out); + + req.response().setStatusCode(500).end(json.toString()); } - return transactions; } - private static String removeSurrounding(final String delimiter, final String message) { - if (message.startsWith(delimiter) && message.endsWith(delimiter)) { - return message.substring(delimiter.length(), message.length() - delimiter.length()); + private void sendHelp(final HttpServerRequest req, final ObjectMapper objectMapper) { + ObjectNode outputObject = objectMapper.createObjectNode(); + outputObject.set("version", TextNode.valueOf(new VersionProvider().getVersion()[0])); + ArrayNode forks = objectMapper.createArrayNode(); + outputObject.set("forks", forks); + for (var fork : EvmSpecVersion.values()) { + forks.add(TextNode.valueOf(fork.getName())); + } + outputObject.set("error", TextNode.valueOf("Both 'state' and 'input' fields must be set")); + + try { + req.response() + .putHeader("Content-Type", "application/json") + .end(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(outputObject)); + + } catch (JsonProcessingException e) { + req.response().setStatusCode(500).end(e.getMessage()); } - return message; } } diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nSubCommand.java index 426c34e2514..1571dc3551e 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nSubCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nSubCommand.java @@ -19,28 +19,22 @@ import static org.hyperledger.besu.evmtool.T8nSubCommand.COMMAND_ALIAS; import static org.hyperledger.besu.evmtool.T8nSubCommand.COMMAND_NAME; -import org.hyperledger.besu.crypto.KeyPair; -import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; -import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.referencetests.ReferenceTestEnv; import org.hyperledger.besu.ethereum.referencetests.ReferenceTestWorldState; -import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; -import org.hyperledger.besu.evm.AccessListEntry; import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.tracing.StandardJsonTracer; -import org.hyperledger.besu.plugin.data.TransactionType; +import org.hyperledger.besu.evmtool.T8nExecutor.RejectedTransaction; +import org.hyperledger.besu.util.LogConfigurator; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; -import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.ArrayList; @@ -49,10 +43,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Spliterator; -import java.util.Spliterators; import java.util.Stack; -import java.util.stream.StreamSupport; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; @@ -60,8 +51,6 @@ import com.fasterxml.jackson.databind.ObjectReader; import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.databind.node.ObjectNode; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; import picocli.CommandLine.Command; import picocli.CommandLine.IParameterConsumer; import picocli.CommandLine.Model.ArgSpec; @@ -79,8 +68,6 @@ versionProvider = VersionProvider.class) public class T8nSubCommand implements Runnable { - record RejectedTransaction(int index, String error) {} - static final String COMMAND_NAME = "transition"; static final String COMMAND_ALIAS = "t8n"; private static final Path stdoutPath = Path.of("stdout"); @@ -182,12 +169,16 @@ public T8nSubCommand(final EvmToolCommand parentCommand) { @Override public void run() { + LogConfigurator.setLevel("", "OFF"); + // presume ethereum mainnet for reference and state tests + SignatureAlgorithmFactory.setDefaultInstance(); final ObjectMapper objectMapper = JsonUtils.createObjectMapper(); final ObjectReader t8nReader = objectMapper.reader(); MutableWorldState initialWorldState; ReferenceTestEnv referenceTestEnv; - List transactions; + List transactions = new ArrayList<>(); + List rejections = new ArrayList<>(); try { ObjectNode config; if (env.equals(stdinPath) || alloc.equals(stdinPath) || txs.equals(stdinPath)) { @@ -229,7 +220,7 @@ public void run() { it = List.of(node).iterator(); } - transactions = extractTransactions(it); + T8nExecutor.extractTransactions(parentCommand.out, it, transactions, rejections); if (!outDir.toString().isBlank()) { outDir.toFile().mkdirs(); } @@ -299,6 +290,7 @@ public void disposeTracer(final OperationTracer tracer) { referenceTestEnv, initialWorldState, transactions, + rejections, tracerManager); try { @@ -332,7 +324,7 @@ public void disposeTracer(final OperationTracer tracer) { } } - if (outputObject.size() > 0) { + if (!outputObject.isEmpty()) { parentCommand.out.println(writer.writeValueAsString(outputObject)); } } catch (IOException ioe) { @@ -340,96 +332,4 @@ public void disposeTracer(final OperationTracer tracer) { ioe.printStackTrace(System.err); } } - - private List extractTransactions(final Iterator it) { - List transactions = new ArrayList<>(); - while (it.hasNext()) { - JsonNode txNode = it.next(); - if (txNode.isTextual()) { - BytesValueRLPInput rlpInput = - new BytesValueRLPInput(Bytes.fromHexString(txNode.asText()), false); - rlpInput.enterList(); - while (!rlpInput.isEndOfCurrentList()) { - Transaction tx = Transaction.readFrom(rlpInput); - transactions.add(tx); - } - } else if (txNode.isObject()) { - if (txNode.has("txBytes")) { - Transaction tx = - Transaction.readFrom(Bytes.fromHexString(txNode.get("txbytes").asText())); - transactions.add(tx); - } else { - Transaction.Builder builder = Transaction.builder(); - int type = Bytes.fromHexStringLenient(txNode.get("type").textValue()).toInt(); - TransactionType transactionType = TransactionType.of(type == 0 ? 0xf8 : type); - builder.type(transactionType); - builder.nonce(Bytes.fromHexStringLenient(txNode.get("nonce").textValue()).toLong()); - builder.gasPrice(Wei.fromHexString(txNode.get("gasPrice").textValue())); - builder.gasLimit(Bytes.fromHexStringLenient(txNode.get("gas").textValue()).toLong()); - builder.value(Wei.fromHexString(txNode.get("value").textValue())); - builder.payload(Bytes.fromHexString(txNode.get("input").textValue())); - if (txNode.has("to")) { - builder.to(Address.fromHexString(txNode.get("to").textValue())); - } - - if (transactionType.requiresChainId() - || !txNode.has("protected") - || txNode.get("protected").booleanValue()) { - // chainid if protected - builder.chainId( - new BigInteger( - 1, - Bytes.fromHexStringLenient(txNode.get("chainId").textValue()).toArrayUnsafe())); - } - - if (txNode.has("accessList")) { - JsonNode accessList = txNode.get("accessList"); - if (!accessList.isArray()) { - parentCommand.out.printf( - "TX json node unparseable: expected accessList to be an array - %s%n", txNode); - continue; - } - List entries = new ArrayList<>(accessList.size()); - for (JsonNode entryAsJson : accessList) { - Address address = Address.fromHexString(entryAsJson.get("address").textValue()); - List storageKeys = - StreamSupport.stream( - Spliterators.spliteratorUnknownSize( - entryAsJson.get("storageKeys").elements(), Spliterator.ORDERED), - false) - .map(JsonNode::textValue) - .toList(); - var accessListEntry = AccessListEntry.createAccessListEntry(address, storageKeys); - entries.add(accessListEntry); - } - builder.accessList(entries); - } - - if (txNode.has("secretKey")) { - SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance(); - KeyPair keys = - signatureAlgorithm.createKeyPair( - signatureAlgorithm.createPrivateKey( - Bytes32.fromHexString(txNode.get("secretKey").textValue()))); - - transactions.add(builder.signAndBuild(keys)); - } else { - builder.signature( - SignatureAlgorithmFactory.getInstance() - .createSignature( - Bytes.fromHexString(txNode.get("r").textValue()).toUnsignedBigInteger(), - Bytes.fromHexString(txNode.get("s").textValue()).toUnsignedBigInteger(), - Bytes.fromHexString(txNode.get("v").textValue()) - .toUnsignedBigInteger() - .subtract(Transaction.REPLAY_UNPROTECTED_V_BASE) - .byteValueExact())); - transactions.add(builder.build()); - } - } - } else { - parentCommand.out.printf("TX json node unparseable: %s%n", txNode); - } - } - return transactions; - } } diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/AltBN128Benchmark.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/AltBN128Benchmark.java new file mode 100644 index 00000000000..1145cfbf1af --- /dev/null +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/AltBN128Benchmark.java @@ -0,0 +1,183 @@ +/* + * Copyright contributors to Hyperledger Besu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evmtool.benchmarks; + +import org.hyperledger.besu.evm.EvmSpecVersion; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; +import org.hyperledger.besu.evm.precompile.AbstractAltBnPrecompiledContract; +import org.hyperledger.besu.evm.precompile.AltBN128AddPrecompiledContract; +import org.hyperledger.besu.evm.precompile.AltBN128MulPrecompiledContract; +import org.hyperledger.besu.evm.precompile.AltBN128PairingPrecompiledContract; + +import java.io.PrintStream; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.tuweni.bytes.Bytes; + +/** Benchmark AltBN128 add, mul, and pairings */ +public class AltBN128Benchmark extends BenchmarkExecutor { + + /** Benchmark AltBN128 add, mul, and pairings with default warmup and iterations */ + public AltBN128Benchmark() { + super(MATH_WARMUP, MATH_ITERATIONS); + } + + @Override + public void runBenchmark( + final PrintStream output, final Boolean attemptNative, final String fork) { + + EvmSpecVersion forkVersion = EvmSpecVersion.fromName(fork); + + if (attemptNative != null + && (!attemptNative || !AbstractAltBnPrecompiledContract.maybeEnableNative())) { + AbstractAltBnPrecompiledContract.disableNative(); + } + output.println( + AbstractAltBnPrecompiledContract.isNative() ? "Native AltBN128" : "Java AltBN128"); + GasCalculator gasCalculator = gasCalculatorForFork(fork); + + benchmarkAdd(output, gasCalculator, forkVersion); + benchmarkMul(output, gasCalculator, forkVersion); + benchmarkPairings(output, gasCalculator, forkVersion); + } + + private void benchmarkAdd( + final PrintStream output, + final GasCalculator gasCalculator, + final EvmSpecVersion forkVersion) { + final Map addTestCases = new LinkedHashMap<>(); + addTestCases.put( + "Add", + Bytes.fromHexString( + "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa9" + + "01e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c" + + "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa9" + + "2e83f8d734803fc370eba25ed1f6b8768bd6d83887b87165fc2434fe11a830cb")); + + AltBN128AddPrecompiledContract addContract = + EvmSpecVersion.ISTANBUL.compareTo(forkVersion) < 0 + ? AltBN128AddPrecompiledContract.byzantium(gasCalculator) + : AltBN128AddPrecompiledContract.istanbul(gasCalculator); + warmup = MATH_WARMUP / addTestCases.size(); + iterations = MATH_ITERATIONS / addTestCases.size(); + double execTime = Double.MIN_VALUE; // a way to dodge divide by zero + long gasCost = 0; + for (final Map.Entry testCase : addTestCases.entrySet()) { + execTime += runPrecompileBenchmark(testCase.getValue(), addContract); + gasCost += addContract.gasRequirement(testCase.getValue()); + } + execTime /= addTestCases.size(); + gasCost /= addTestCases.size(); + output.printf( + "AltBN128 Add %,6d gas @%,7.1f µs /%,8.1f MGps%n", + gasCost, execTime * 1_000_000, gasCost / execTime / 1_000_000); + } + + private void benchmarkMul( + final PrintStream output, + final GasCalculator gasCalculator, + final EvmSpecVersion forkVersion) { + final Map mulTestCases = new LinkedHashMap<>(); + mulTestCases.put( + "mul", + Bytes.fromHexString( + "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa9" + + "01e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c" + + "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa9" + + "2e83f8d734803fc370eba25ed1f6b8768bd6d83887b87165fc2434fe11a830cb")); + + AltBN128MulPrecompiledContract mulContract = + EvmSpecVersion.ISTANBUL.compareTo(forkVersion) < 0 + ? AltBN128MulPrecompiledContract.byzantium(gasCalculator) + : AltBN128MulPrecompiledContract.istanbul(gasCalculator); + warmup = MATH_WARMUP / mulTestCases.size(); + iterations = MATH_ITERATIONS / mulTestCases.size(); + double execTime = Double.MIN_VALUE; // a way to dodge divide by zero + long gasCost = 0; + for (final Map.Entry testCase : mulTestCases.entrySet()) { + execTime += runPrecompileBenchmark(testCase.getValue(), mulContract); + gasCost += mulContract.gasRequirement(testCase.getValue()); + } + execTime /= mulTestCases.size(); + gasCost /= mulTestCases.size(); + output.printf( + "AltBN128 Mul %,6d gas @%,7.1f µs /%,8.1f MGps%n", + gasCost, execTime * 1_000_000, gasCost / execTime / 1_000_000); + } + + private void benchmarkPairings( + final PrintStream output, + final GasCalculator gasCalculator, + final EvmSpecVersion forkVersion) { + final Bytes[] pairings = { + Bytes.fromHexString( + "0x0fc6ebd1758207e311a99674dc77d28128643c057fb9ca2c92b4205b6bf57ed2" + + "1e50042f97b7a1f2768fa15f6683eca9ee7fa8ee655d94246ab85fb1da3f0b90" + + "198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2" + + "1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed" + + "090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b" + + "12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa"), + Bytes.fromHexString( + "0x2b101be01b2f064cba109e065dc0b5e5bf6b64ed4054b82af3a7e6e34c1e2005" + + "1a4d9ceecf9115a98efd147c4abb2684102d3e925938989153b9ff330523cdb4" + + "08d554bf59102bbb961ba81107ec71785ef9ce6638e5332b6c1a58b87447d181" + + "01cf7cc93bfbf7b2c5f04a3bc9cb8b72bbcf2defcabdceb09860c493bdf1588d" + + "02cb2a424885c9e412b94c40905b359e3043275cd29f5b557f008cd0a3e0c0dc" + + "204e5d81d86c561f9344ad5f122a625f259996b065b80cbbe74a9ad97b6d7cc2" + + "07402fdc3bc28a434909f24695adea3e9418d9857efc8c71f67a470a17f3cf12" + + "255dbc3a8b5c2c1a7a3f8c59e2f5b6e04bc4d7b7bb82fcbe18b2294305c8473b" + + "19156e854972d656d1020003e5781972d84081309cdf71baacf6c6e29272f5ff" + + "2acded377df8902b7a75de6c0f53c161f3a2ff3f374470b78d5b3c4d826d84d5" + + "1731ef3b84913296c30a649461b2ca35e3fcc2e3031ea2386d32f885ff096559" + + "0919e7685f6ea605db14f311dede6e83f21937f05cfc53ac1dbe45891c47bf2a"), + Bytes.fromHexString( + "0x1a3fabea802788c8aa88741c6a68f271b221eb75838bb1079381f3f1ae414f40" + + "126308d6cdb6b7efceb1ec0016b99cf7a1e5780f5a9a775d43bc7f2b6fd510e2" + + "11b35cf2c85531eab64b96eb2eef487e0eb60fb9207fe4763e7f6e02dcead646" + + "2cbea52f3417b398aed9e355ed16934a81b72d2646e3bf90dbc2dcba294b631d" + + "2c6518cd26310e541a799357d1ae8bc477b162f2040407b965ecd777e26d31f7" + + "125170b5860fb8f8da2c43e00ea4a83bcc1a974e47e59fcd657851d2b0dd1655" + + "130a2183533392b5fd031857eb4c199a19382f39fcb666d6133b3a6e5784d6a5" + + "2cca76f2bc625d2e61a41b5f382eadf1df1756dd392f639c3d9f3513099e63f9" + + "07ecba8131b3fb354272c86d01577e228c5bd5fb6404bbaf106d7f4858dc2996" + + "1c5d49a9ae291a2a2213da57a76653391fa1fc0fa7c534afa124ad71b7fdd719" + + "10f1a73f94a8f077f478d069d7cf1c49444f64cd20ed75d4f6de3d8986147cf8" + + "0d5816f2f116c5cc0be7dfc4c0b4c592204864acb70ad5f789013389a0092ce4" + + "2650b89e5540eea1375b27dfd9081a0622e03352e5c6a7593df72e2113328e64" + + "21991b3e5100845cd9b8f0fa16c7fe5f40152e702e61f4cdf0d98e7f213b1a47" + + "10520008be7609bdb92145596ac6bf37da0269f7460e04e8e4701c3afbae0e52" + + "0664e736b2af7bf9125f69fe5c3706cd893cd769b1dae8a6e3d639e2d76e66e2" + + "1cacce8776f5ada6b35036f9343faab26c91b9aea83d3cb59cf5628ffe18ab1b" + + "03b48ca7e6d84fca619aaf81745fbf9c30e5a78ed4766cc62b0f12aea5044f56") + }; + final AltBN128PairingPrecompiledContract contract = + EvmSpecVersion.ISTANBUL.compareTo(forkVersion) < 0 + ? AltBN128PairingPrecompiledContract.byzantium(gasCalculator) + : AltBN128PairingPrecompiledContract.istanbul(gasCalculator); + + warmup = MATH_WARMUP / 20; + iterations = MATH_ITERATIONS / 20; + + for (int i = 0; i < pairings.length; i++) { + final double execTime = runPrecompileBenchmark(pairings[i], contract); + final long gasCost = contract.gasRequirement(pairings[i]); + + output.printf( + "AltBN128 %d pairing %,6d gas @%,7.1f µs /%,8.1f MGps%n", + i * 2 + 2, gasCost, execTime * 1_000_000, gasCost / execTime / 1_000_000); + } + } +} diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/BenchmarkExecutor.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/BenchmarkExecutor.java new file mode 100644 index 00000000000..c552512cb7d --- /dev/null +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/BenchmarkExecutor.java @@ -0,0 +1,153 @@ +/* + * Copyright contributors to Hyperledger Besu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evmtool.benchmarks; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.evm.EvmSpecVersion; +import org.hyperledger.besu.evm.code.CodeV0; +import org.hyperledger.besu.evm.fluent.SimpleBlockValues; +import org.hyperledger.besu.evm.fluent.SimpleWorld; +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.BerlinGasCalculator; +import org.hyperledger.besu.evm.gascalculator.ByzantiumGasCalculator; +import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; +import org.hyperledger.besu.evm.gascalculator.ConstantinopleGasCalculator; +import org.hyperledger.besu.evm.gascalculator.FrontierGasCalculator; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; +import org.hyperledger.besu.evm.gascalculator.HomesteadGasCalculator; +import org.hyperledger.besu.evm.gascalculator.IstanbulGasCalculator; +import org.hyperledger.besu.evm.gascalculator.LondonGasCalculator; +import org.hyperledger.besu.evm.gascalculator.PetersburgGasCalculator; +import org.hyperledger.besu.evm.gascalculator.ShanghaiGasCalculator; +import org.hyperledger.besu.evm.precompile.PrecompiledContract; + +import java.io.PrintStream; +import java.util.concurrent.TimeUnit; + +import com.google.common.base.Stopwatch; +import org.apache.tuweni.bytes.Bytes; + +/** Abstract class to support benchmarking of various client algorithms */ +public abstract class BenchmarkExecutor { + + static final int MATH_WARMUP = 10_000; + static final int MATH_ITERATIONS = 1_000; + + int warmup; + int iterations; + + static final MessageFrame fakeFrame = + MessageFrame.builder() + .type(MessageFrame.Type.CONTRACT_CREATION) + .contract(Address.ZERO) + .inputData(Bytes.EMPTY) + .sender(Address.ZERO) + .value(Wei.ZERO) + .apparentValue(Wei.ZERO) + .code(CodeV0.EMPTY_CODE) + .completer(__ -> {}) + .address(Address.ZERO) + .blockHashLookup(n -> null) + .blockValues(new SimpleBlockValues()) + .gasPrice(Wei.ZERO) + .miningBeneficiary(Address.ZERO) + .originator(Address.ZERO) + .initialGas(100_000L) + .worldUpdater(new SimpleWorld()) + .build(); + + /** + * Run benchmarks with specified warmup and iterations + * + * @param warmup number of executions to run before timing + * @param iterations number of executions to time. + */ + protected BenchmarkExecutor(final int warmup, final int iterations) { + this.warmup = warmup; + this.iterations = iterations; + } + + /** Run benchmarks with warmup and iterations set to MATH style benchmarks. */ + protected BenchmarkExecutor() { + this(MATH_WARMUP, MATH_ITERATIONS); + } + + /** + * Run the benchmark with the specific args. Execution will be done warmup + iterations times + * + * @param arg the bytes areguments to pass into the contract + * @param contract the precompiled contract to benchmark + * @return the mean number of seconds each timed iteration took. + */ + protected double runPrecompileBenchmark(final Bytes arg, final PrecompiledContract contract) { + if (contract.computePrecompile(arg, fakeFrame).getOutput() == null) { + throw new RuntimeException("Input is Invalid"); + } + + final Stopwatch timer = Stopwatch.createStarted(); + for (int i = 0; i < warmup && timer.elapsed().getSeconds() < 1; i++) { + contract.computePrecompile(arg, fakeFrame); + } + timer.reset(); + timer.start(); + int executions = 0; + while (executions < iterations && timer.elapsed().getSeconds() < 1) { + contract.computePrecompile(arg, fakeFrame); + executions++; + } + timer.stop(); + + if (executions < 1) { + return Double.NaN; + } + + final double elapsed = timer.elapsed(TimeUnit.NANOSECONDS) / 1.0e9D; + return elapsed / executions; + } + + /** + * Return the gas calculator at a given fork. Some forks don't have a specific gas calculator and + * will return the prior one + * + * @param fork name of the fork + * @return a gas calculator + */ + public static GasCalculator gasCalculatorForFork(final String fork) { + return switch (EvmSpecVersion.valueOf(fork.toUpperCase())) { + case HOMESTEAD -> new HomesteadGasCalculator(); + case FRONTIER -> new FrontierGasCalculator(); + case BYZANTIUM -> new ByzantiumGasCalculator(); + case CONSTANTINOPLE -> new ConstantinopleGasCalculator(); + case PETERSBURG -> new PetersburgGasCalculator(); + case ISTANBUL -> new IstanbulGasCalculator(); + case BERLIN -> new BerlinGasCalculator(); + case LONDON, PARIS -> new LondonGasCalculator(); + case SHANGHAI -> new ShanghaiGasCalculator(); + default -> new CancunGasCalculator(); + }; + } + + /** + * Run the benchmarks + * + * @param output stream to print results to (typicall System.out) + * @param attemptNative Should the benchmark attempt to us native libraries? (null use the + * default, false disabled, true enabled) + * @param fork the fork name to run the benchmark against. + */ + public abstract void runBenchmark( + final PrintStream output, final Boolean attemptNative, final String fork); +} diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/ECRecoverBenchmark.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/ECRecoverBenchmark.java new file mode 100644 index 00000000000..a2cca4c5846 --- /dev/null +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/ECRecoverBenchmark.java @@ -0,0 +1,466 @@ +/* + * Copyright contributors to Hyperledger Besu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evmtool.benchmarks; + +import org.hyperledger.besu.crypto.SECP256K1; +import org.hyperledger.besu.evm.precompile.ECRECPrecompiledContract; + +import java.io.PrintStream; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.tuweni.bytes.Bytes; + +/** Benchmark ECRecover precompile (ECDSA key extraction + keccak hash) */ +public class ECRecoverBenchmark extends BenchmarkExecutor { + + /** Use default math based warmup and interations */ + public ECRecoverBenchmark() { + super(MATH_WARMUP, MATH_ITERATIONS); + } + + @Override + public void runBenchmark( + final PrintStream output, final Boolean attemptNative, final String fork) { + final Map testCases = new LinkedHashMap<>(); + testCases.put( + "0x0c65a9d9ffc02c7c99e36e32ce0f950c7804ceda", + Bytes.fromHexString( + "0x0049872459827432342344987245982743234234498724598274323423429943000000000000000000000000000000000000000000000000000000000000001be8359c341771db7f9ea3a662a1741d27775ce277961470028e054ed3285aab8e31f63eaac35c4e6178abbc2a1073040ac9bbb0b67f2bc89a2e9593ba9abe8c53")); + testCases.put( + "0xc6e93f4c1920eaeaa1e699f76a7a8c18e3056074", + Bytes.fromHexString( + "0x82f3df49d3645876de6313df2bbe9fbce593f21341a7b03acdb9423bc171fcc9000000000000000000000000000000000000000000000000000000000000001cba13918f50da910f2d55a7ea64cf716ba31dad91856f45908dde900530377d8a112d60f36900d18eb8f9d3b4f85a697b545085614509e3520e4b762e35d0d6bd")); + testCases.put( + "0xfe26206ad0a5897a478dd046c56164553adaea20", + Bytes.fromHexString( + "0x0fcdd8f8c550589cbae6183bc40713beb8d11898a201d13d6d5e40bc9ebf221d000000000000000000000000000000000000000000000000000000000000001c3824317158d005cbe49614fa05798ea00f2ca9db302a5e92d55bcaecd33d33da3c7de48ebec95be7b5111a7812febed1421f839d4d480c98501b78666aefdcd3")); + testCases.put( + "0x39c0f4fbcd41581d5b440a7c9f964b903037e09e", + Bytes.fromHexString( + "0xeb9a6731fa269c24c2535aa00a4b31d7117a2791188120c71aacd97664d1cc16000000000000000000000000000000000000000000000000000000000000001c707c68dd904de055d735f9e5c4dfba46296ad38ff6ba8f0e5e3f4ae83243b84a5b1920d628abc74e4f3a09449011a9664ab9885f74fdc7628d417599207bde74")); + testCases.put( + "0x64849cfbf0353f2c80e2a1e558982f7c4738d9f1", + Bytes.fromHexString( + "0xf3ae1d9176371dd31accd73bb6bbaee561a041f5ac291a548880e1abe7b19e38000000000000000000000000000000000000000000000000000000000000001b116bd86d971b70ed540dc7c13756a99ff17644ed433781a3ffcc7359541d02fc4a2358ffc21682ece870e633cc8537f04be4ff75a142ecd35a951fc95fd1de57")); + testCases.put( + "0x5026d2655bc28bee480b2f31934f0970e8acc647", + Bytes.fromHexString( + "0x69567625d007e5c915eadb8b768f008227d57f4951f9d5711dfc72a8af13d35f000000000000000000000000000000000000000000000000000000000000001ba3ef328e9f95b4a28d9b8c20f3e9fc939bf94ad3611b4e1aaabb442f1c40545f6f83fe2c067d7a35f9bcb655894d15cd6d95d5e05c9fad33b2efa67592c0a4fe")); + testCases.put( + "0x24bf97810c294811aa8165c9a05717a7731342a0", + Bytes.fromHexString( + "0x5ecdd449eb48c111c596d6b41047547deb4bbb27eafa419d1d041d842f1d81cb000000000000000000000000000000000000000000000000000000000000001c7ee309958bcd2f7a8d0fa904f16358d7b1dd52dc653f62b0eba42eec74335a620bf25c9db104a22c77af694cdb56e115fe259eef0a5e7968698bad0a592f6a2d")); + testCases.put( + "0x9bdeac37b1bf31980c6e8cbc5bdfa38dacbc4c43", + Bytes.fromHexString( + "0x9a996c7083b19106163161ad5117a11703507ac61cad659c5bb164cd9d368672000000000000000000000000000000000000000000000000000000000000001bffc032f93b534eec6f76d194821f9fa70de06f0aac391e7f105401b23ab1a23071b55820c93857ed7e079e72f65798b2d5afad4f999048c1a987152bc5dbf78a")); + testCases.put( + "0x9ded673711119881765005a33ef7bb1961bfe98d", + Bytes.fromHexString( + "0xea3305a892449d8215a5c41c619a42aeef22f888ee1b2c370584a6eb9e16fa27000000000000000000000000000000000000000000000000000000000000001b8efcc5180b219820d57856f018a7de24b0c4c633dfae40a96a5110c4f94b947151f4320da2e79e2d5e5c0efaef659b60b7d3de1debb4e37853746395f9426f2b")); + testCases.put( + "0xd4bbacccff27e6e8534d14cd8fcd665d455dddf2", + Bytes.fromHexString( + "0xebb2b43c1070b6000aaa866071de173a24dbdec57443b9467c1aa11c0090d20c000000000000000000000000000000000000000000000000000000000000001bb52ebd3ee958d6487d7a6d68faa5df32e8f34a4703201feb6ea7687c1abf5b28439215bef624ef3799919da5980f3793f6aa14fd6dc43df3c5c652a4e2f6149b")); + testCases.put( + "0x5b73664bd5ef270f91775d27f47e436d960aa853", + Bytes.fromHexString( + "0xb28e4662bf41c1043e06400119c6c7804dcea81b1e4e8555c9db5be41380b1d3000000000000000000000000000000000000000000000000000000000000001ca010458d4c545fca2831e8ee9eb7857955d083feba0080c0b58a1b94233650572bfb5978a642da7b7f255562c47404ee3ad236d9f0319413f2e5a69cfafec2cb")); + testCases.put( + "0x200d8d10eab444331cb2a0802219771c11443205", + Bytes.fromHexString( + "0x694bace9fe95c0370ef0eb3c0c629186616e33469972ff6a7ecce90f3fe2ab2d000000000000000000000000000000000000000000000000000000000000001ca07e9497d29f7c9adae37b9a985c876b5b3ee6d21a9bc83cfcf27531cb5eb67879f317e2c145caaa798bb1b30fd96f32d843636559f195622f2fac69297f935a")); + testCases.put( + "0x4135437a672c7d48fefc4be43a26783fe030e9b7", + Bytes.fromHexString( + "0xc3964b44adfd407ce69ccae93c033b6418ab903c674e794681baadf3173e37c1000000000000000000000000000000000000000000000000000000000000001c28e8ff8b5d9e55740da1ab2f7cfb9b527509439b2a99117d40a2158501a5b4354cdda2112aa6a7e89019556011f50abec5c3ae48501a1594b831275a2f031999")); + testCases.put( + "0xff2726d26e39daf03ae70b7f4cce693329e3a027", + Bytes.fromHexString( + "0x0d56ee3eb6ecd6a949793c8afaa905550333dc9063bc58cdcace8a146f23b2af000000000000000000000000000000000000000000000000000000000000001cebdb65ebfd20803c364d393e4df95a3631d906d3ebeb7fae31bc5bdbf9297e6c5d4e7a93d40278c1c3ddd4659c58a0eeb01fa41a3ca78fdb184b4bf7b2e34af1")); + testCases.put( + "0x6c36670046a1f02fe217d95c5e78f5c84efd703e", + Bytes.fromHexString( + "0x23fa3e10e5b041840a8bd9055e9f6aca4c9764b6b21658bd6f126e6cf821e963000000000000000000000000000000000000000000000000000000000000001c19552a6e36c2c2c8fa97534c8e0a0575420364acd73f9399a6a375cb6ab8685d619a8afcdc09d88344dce929d90eed48f9caef102acb28c632340386d168cd14")); + testCases.put( + "0x52d2883c39100d09a6b8d793e0f693fd7f2bac51", + Bytes.fromHexString( + "0xe4e5120a2c41c1beac3a04fe7895fb93db7e53e33a4f279cf196ac8d12e4eccc000000000000000000000000000000000000000000000000000000000000001bc113be6e205a4851f4aa56b499aee3fe75389382fb7b4da2eb894537addf20980dac9e071a562749cce0ea9da2f4cac450509ec03ebcf23898c52b3375c29169")); + testCases.put( + "0xc65a2a9ef32f747865a119d1c044ad836a8f6d73", + Bytes.fromHexString( + "0x7b4ba1f9fd096f738c26df77a1a87a87153d5eb253a4622cc41ca1e57f678370000000000000000000000000000000000000000000000000000000000000001bbdb9a84a3eaea6f3a16bb084387c1dd1bf91c0be1300cc99ece1cf8d239d7e0d37f24155f143635a761427684207ffabfa00dda09d502056768a4e57e0f336c5")); + testCases.put( + "0x5cfe5b8bf54dee364ef6f411aac9bbb6eb051202", + Bytes.fromHexString( + "0x4c16d10f1bfbaa34814a39d017cdcc18590d08a52ee01be38b43742cf0f76ee9000000000000000000000000000000000000000000000000000000000000001c75d276f5646653753fdcec2ab92d27e58a59c614aab6cc3568834a4ef36819bd54bcaf3c605ed948a20e56cfe58c1595d727877b0bfa9b9b6553879ba0e08a2b")); + testCases.put( + "0xf34405682c4deb55da399822373b632cf5ca25c0", + Bytes.fromHexString( + "0x8e4ae0eb9cb54e2378b3d161eeedc36654269cd1bef02d68751cc1b0021b709f000000000000000000000000000000000000000000000000000000000000001c01f53df1ac64d831f7cb45bcf9037052162900e3d7fb4d62934112a8c4b257d50c0c36cc064d72ba8a3ba57b1d2eee88b0628907dfe2cf0088dbf69d89c2f1c7")); + testCases.put( + "0x617c0e2ac02fd3e876fd5bd8581e73937df53c5d", + Bytes.fromHexString( + "0xb755e67b6ba34376ac93bc8f81b072df191aed5c5e1bc7131cf1556731fad13e000000000000000000000000000000000000000000000000000000000000001b61b542768763d72e298e93cf8635ac430c2155835c079eb508e47d0cff5fb1fa62fb0cf03fd42a35bd6ade27fd10ba4e22975a61c259e1e71664892cb9f89f6c")); + testCases.put( + "0x2b43183e036afb83fed9ad70f1bfadda5497dbba", + Bytes.fromHexString( + "0x361a00e41d8e97cb935320dad3ba8b071f198e4c2424a2dbe110ab59a9a74511000000000000000000000000000000000000000000000000000000000000001c703cb0a9ee3a332e5b53664ee0495a757fbf1c168971a618f0010a894e8f00152d0fd7a61bbcfde075675e868593ff695298cb1dd7640ebdccd2864bd4f5fd71")); + testCases.put( + "0x81b6898913b2d49aec6e0bbcc8c192cff4d0eed8", + Bytes.fromHexString( + "0xff94a2c7dbfbb566784a5d0df05c461f050dbc826f622940ca96ea949f9e1a87000000000000000000000000000000000000000000000000000000000000001b66489a58f64e058f150ffdb7e22a0993f4299073fc2b0840b082850138990fb54fcaca68705d1108a555ed4733a959c8e302510098c80b5e3c9353b1a86a64de")); + testCases.put( + "0xb48bc9d6546fb5156954699062774443a7676986", + Bytes.fromHexString( + "0xf655a5caf4dba704f63f5e17e5a94535ea7d277f2b8f4d69951291319f5c2c1b000000000000000000000000000000000000000000000000000000000000001b66987335ff22966a6084e88a4dbdc96f2cfb126aba2f6a477c18bf0fb3c42f2a5f1ef94acf1184da542f3f7271032a931bfcf3afeb3a9dafca95d5aff68bdee5")); + testCases.put( + "0x13cb19ae4e86177abfcc9d44139dcebb993ebdc1", + Bytes.fromHexString( + "0x19e7a1205c185da64a45bb5e04f35c54cd092b70bb1a1527f8372f1ae67b4bb7000000000000000000000000000000000000000000000000000000000000001becde2323e521681126ea23af56953a18166158919d3fa445e93fcf957f60185a4738fce3d006827c432e5f6c1b8d7e3450fb434172b6ab4d619fe49a09ed4b68")); + testCases.put( + "0x6d78fd01abb065be75ffeef89a9df8f87926daf1", + Bytes.fromHexString( + "0x42d1878efb373fb18df168ce9687fae3cf8c1afa3063fb15b44f309adae25894000000000000000000000000000000000000000000000000000000000000001b15439bd45f426bdab38723290e9691371196e2105bee21c9dc36f77b3797fb6849f66ca42c6a4d5dde4b2996f68082c930fa6466e16077b074a63551d0a36bd4")); + testCases.put( + "0xd213383f34edd2a9d6e89dc6ed2bdedb2b875a3f", + Bytes.fromHexString( + "0x91f5c73a9e6b54b896940478ac0995d6d757feb38790cfeeaa0ca0c4c0c72db7000000000000000000000000000000000000000000000000000000000000001b5d26a45936c8b69117451625649c356a7a40627635f60e038313afd5a9e8082323aa5968522ea56d32beff94e628e36ebc0ceb68cf89f7141175b3dca19e2446")); + testCases.put( + "0x0bcfc1ef1f89de5d6bcd354d797faf3047ace632", + Bytes.fromHexString( + "0x654643af5d8045129adcbd4e2fe3a0270eae3072765e952ae1a8d239905f1848000000000000000000000000000000000000000000000000000000000000001cb3fdc5124a4193b35ba4eee7a3a764ea3ef14b0bacc61ce0a32e52258c64a31b2f66dc6529567230fc420f48e650a589146a409b85cb7b7d1d25cd7782198873")); + testCases.put( + "0xe2faafdf582764fa4b65004ef676466552f4bfe3", + Bytes.fromHexString( + "0xa3dcb3d6e954a0da9e57fef6322a489935535fb892eb60fc2aee0153207441f2000000000000000000000000000000000000000000000000000000000000001c58d31b5c643c2e2376e5420c250ab85ac58a730523449998d08c55ce7ef1a8871777e9f81e84fa66f656615e414b7f89e5800d429f618cf2fe88aa67631db651")); + testCases.put( + "0xa32c72d11ac3723ad0129c6f395c7d118db9e5db", + Bytes.fromHexString( + "0x98eec766a1da31be4aa5b56a3c1d388610a4a37f7b8ef17011c78c135c999783000000000000000000000000000000000000000000000000000000000000001c30a0d88c1733418d1248ffecf0b3585abde3999aa4c4b4496dce559a6a9cc1c81c1de713d501fef22da4bfd4afa7bbb65d0b2217ac03dbc3bc3c75156593a8f9")); + testCases.put( + "0x75cc7deb0bea00df88dc37a6a69038489b7a00da", + Bytes.fromHexString( + "0xd646626db60c8f37f0d67df1f7795860dc97f70fb26e85b7dd67fdd8865d70a1000000000000000000000000000000000000000000000000000000000000001c3f4c0a2e4c038aac868040990b4334a6c007e8394837ef2b467ac417075b502e2b67b91a1a52df65501d16645b7835849f70aa50a72d25ab9baeda90528003f4")); + testCases.put( + "0x8b38952f5858f58d8b448da2bfc7cd5f203d9874", + Bytes.fromHexString( + "0x4a3842955bc493c1478b8e5d091f5ea38b6e1fbfe29e2a76af6b642829a674d5000000000000000000000000000000000000000000000000000000000000001b9fdc9d14a459294ecdf918920dbc4f5bf957425563fcd2fcda6db19ef1ae37a144ec3663dbec38c0acb40623552b4062981c635842434e5529a6961eb468a815")); + testCases.put( + "0x01e86c2dc7888aaf69c067c3d81d3324b221ac4e", + Bytes.fromHexString( + "0x1fa23790ba1f754c40131e8ebd40ad95e8c3f9ed32308395907bd9b6f451286d000000000000000000000000000000000000000000000000000000000000001cb9eb00b69db8a908c0fb24cf9a54fecd06b568efac82ffa38df3c0a088825f6002e574107158e2a83da1227343a536966fd4e92b298e473893ccbaf20ca3b479")); + testCases.put( + "0xd7f38f4cdbf5cde5a68111970cb377003f971dd6", + Bytes.fromHexString( + "0x88f8b41d758a53d0065691f5c771b999c241508a26b6d49b0698f99675602372000000000000000000000000000000000000000000000000000000000000001b5f97bee8c1a2660617aa6d00b48cae9dc866e7dd92471a18e34f863841e4e7954a20c134006aa0a19fa7d1eecbdd3a7213029fc1b173157d2354a62e6add5a0a")); + testCases.put( + "0xb72b25e2dc98013d1e429180a95ce8d763b92ad3", + Bytes.fromHexString( + "0x85bced90e31303e32e094be2d0210d8ae7f4ff29a793bd3e5959fc86a79b2738000000000000000000000000000000000000000000000000000000000000001b04efc53658e9a47738a7078783dd6ef305b9912443fb6008451026e80a38a8f64d0abf58ef63bdf5ed576c6f0e99bdd3dc7f73f17549303222b144868bf17b58")); + testCases.put( + "0x270433b68a15b4979186f44c3594041e8f6fae80", + Bytes.fromHexString( + "0xb0df0e432f097fc53dfb8d14165a63a24313cff79254a7cbe554ab7eebd43bc6000000000000000000000000000000000000000000000000000000000000001bee9e7ad060f9c969b7d289c5006eb9b03cebb508af9e5647228d48030d1bf2c87d0d66c0cefaef9eb15617a891963d51bb1e19bc7cb33544e919c94bd2235ea6")); + testCases.put( + "0xa6182f0f4ceb72de969d20684f71660c2cd2ada0", + Bytes.fromHexString( + "0x70d6236cd7c57cb44dd1f99e20e785668b6cdead0b007458d0ed4e9655d7f990000000000000000000000000000000000000000000000000000000000000001bb262ec123fde934f67facf354ca12eb19b6b453a8bcd7beeb0566743fe4ed78607baec6194afcc4f66cb3c42518f0eda63e5f94df9121242e4e128133ede0024")); + testCases.put( + "0xecd91ebd69948e971744c52ceff54b5681c6d419", + Bytes.fromHexString( + "0xabcbaaca73cafb7fbf215909dd5750ec1ded7a3e151ff830df92590fad8cbf30000000000000000000000000000000000000000000000000000000000000001c0168786a30ab53bff4fac2f46c7f2cad22e96c0e80be8c6f96f1bf987b134c726caf9c6b4fafb3689506f8ed360cb61be6529c4de87e1d9bf553f7f3734beb6a")); + testCases.put( + "0x8cd8416864cc82c1061c00a2571e2b6ef1bc8f9f", + Bytes.fromHexString( + "0x4e166b5f7df865f51522a4ccc9616a4d8c9b83df29dbde6dc96dc94a13e4a7e4000000000000000000000000000000000000000000000000000000000000001ba43b80dd0721a715082425bf9252322c4b61671102e860b7371871abe5bd6a5e5c8abaf399cb7e6f39405a0583031f73b40ef41963b3827f3d20d5103ccd3517")); + testCases.put( + "0xa91aefd1bddca65485567c7014ebf4b48917e3de", + Bytes.fromHexString( + "0x515ac051195596523c6664ac8d8e48345ea5932cda58d22ac49339dc234127e1000000000000000000000000000000000000000000000000000000000000001ba780c9c0aea4501f09cf5a75d133e9c89386ffea400719dc82d9586975cfb6ab41adfa6195e155b7a2a7f598c32a754010d5ce98e967a2f812f77050e72d67cd")); + testCases.put( + "0xd5be345de0dd0d15d34899173b7c375d31140f24", + Bytes.fromHexString( + "0x3c5ad848eecf1a48d12f17ee1ef6a4ee45f3c1ae7cb5b843fbf70d0f9b7b4a13000000000000000000000000000000000000000000000000000000000000001c50cad8bc91ef3924d32ce6194c79a6104686de2e2f0e67c3353262489aa7f6451532f54f6b99e8f4ce54377a86a515088bfe440eebec374402122c69fb691f5f")); + testCases.put( + "0xfe4701547b7dbaba4c0702f226dc48a2663e18bc", + Bytes.fromHexString( + "0xfcde24b61bbd3ece34d2f7d99751e57e0d840cbcbd58fa1777a5e6be8f74bcd6000000000000000000000000000000000000000000000000000000000000001b378491f640df70d59dfba12f7135fec6e7b0ecd67bd07a29e3644f85071438ae0a737efc36831bd13576d2c517b2b4694181ee687f40732d428cc5478a8fa7f5")); + testCases.put( + "0x66036bc0f0fdcfbf8d814da7f3f16885132a43ec", + Bytes.fromHexString( + "0x83326209a1fc9e7f4e111a20ed12e2ce6d0639e8eeeb75fe403a9bb180288a47000000000000000000000000000000000000000000000000000000000000001cad837bf4ac65dc6741fd911ecc41ce1d137e135540bd1035a06cc732d23b3fe243b3d70317177dd578027952eeb6e701280beb3685cb44a9cbc6685cd3149aa7")); + testCases.put( + "0xa4e7416ef65b74c3b61a1eee53a33eb1d2b51a63", + Bytes.fromHexString( + "0x4ab6fb0952a3e801814a72bdeb8630aeb9edce54f0b08c8284bc7efa0d737ff0000000000000000000000000000000000000000000000000000000000000001cc8fc37b1724ce16d169b4856fe2113ff305290859070a3cb5cfbb93f90a248e3382c9ca18fa7f926e914cf781999c2c8de6ea1fa4e8536030699005b45efce86")); + testCases.put( + "0xabb83304268fec4160d80e3e45d1376c0b458636", + Bytes.fromHexString( + "0x80d7c38d08128721cb1d6b78f26b2f53b7bdcb2448a6d87668f4fe4e19cf5dcb000000000000000000000000000000000000000000000000000000000000001be5dc7cddccc9c61eac363691c6305420bc393a4ca17f1e10bc5192ff63b5d03f02536812a3fd90cc50208fc3b886efca921c520b4a66ef00d3228cf02fbad675")); + testCases.put( + "0x78bbe6f432b755a9bc0bf9798ea82e2574d01930", + Bytes.fromHexString( + "0x1e4c87808973dd4b705d20186d4daf911f7002006aeca1ae1a476ec23a3eb67b000000000000000000000000000000000000000000000000000000000000001b942c0416506f34ae4a5aff5bde5fbe4e093f4fca798e4d8be460a84c5cbe8a1a0fdc6113fa280b9c4e736147ccd5bf8d383353556692f27405e77344b7c9b253")); + testCases.put( + "0xd309698bda9fbc6ba8f56ec71cd0fe50374ab147", + Bytes.fromHexString( + "0x5a174e433de66595c112432074d5d6fd07239edb8f3e1bc6b78814d4ce41cf22000000000000000000000000000000000000000000000000000000000000001c964fc2baba65aef4a47358132fd87ac92dbdf08e7fab49605293e43f47a76fac320d603d6e841fea09a4dd7b7bddb8b9c6bbb30b81893ee655bb8a16e3939d51")); + testCases.put( + "0xf658c09eaa7cdf744e34b676a92de4cdbef19306", + Bytes.fromHexString( + "0x390fe5599dcc23aabd594ae17f08b27a3f686f5a12d3ebd2624811738976e21a000000000000000000000000000000000000000000000000000000000000001c4d32732c7278ba4060cd00c4bbef14189604470147910f6f254cfe04bff7638346a2c66f0acc61b8a612d05ceddda4f2dd9ce79a7f36597bc74797d3d28d6cc7")); + testCases.put( + "0x4566e04fe531b85ad7103ac1d234e36fcc4c80c7", + Bytes.fromHexString( + "0xe0a1f6a2b34ed7cabe5829e4a0fb68989c8b520cb69376f4e6b754181cd02c4a000000000000000000000000000000000000000000000000000000000000001bcb22c52a26b97580036849796289293ff7e7016c13e948d99f2dfb5176d7ec01441aad675e9119fb30019f6c73adcdc4bcecb077c9164026230b5bf71cbbcbb2")); + testCases.put( + "0xe22dc594d5a836902a398fef392e4acae4eb64d8", + Bytes.fromHexString( + "0x925023d3dde43d2691bacaa0202dad390a73acd5c67dbc3b73c8667696103cb2000000000000000000000000000000000000000000000000000000000000001c61cb8f8271a58b25ac3fe24e2b1a91b613a5e0da5fea8a27c4c4f38c46c7d74901be5ad35bbf74b5f23bcd03f5cb06dca74054738411e86fad9d985ee43d6003")); + testCases.put( + "0x6825015903052024e1c39b5ec4686d8f17650623", + Bytes.fromHexString( + "0x809e822931959c627d36bf34ebc22415614f20c1b98839665187154233ab35c6000000000000000000000000000000000000000000000000000000000000001baa4df42f677f348f44151cfd059b3fc0e43468301acc0e32c68fe1175428308129eb46f79704e3169f336f7a269a026f43a316b7318198b9880fe25c069c4628")); + testCases.put( + "0xc19cb83c80aca377fe7d32114f0391c64fe5a043", + Bytes.fromHexString( + "0x3e84e7a38dd4802b3469a55ffeba8e3b09cd6f2d50c446b217ca943ed09c7143000000000000000000000000000000000000000000000000000000000000001bd10fcd30c21a2f7eae829e5445a7e8ac1f4d64ebb5e007c087b64e369e502a25101bbc6e6e3c2b8a0a7b0cc936be004570de3c58e6dcfa460507861aac2d7675")); + testCases.put( + "0x5f8e0630b06762a24670bd407f79bceee4ec0841", + Bytes.fromHexString( + "0x4c6dcfab6ae4a6f8b9f812d361d7064ca6802a6d391a5e936c7e80b53723f172000000000000000000000000000000000000000000000000000000000000001ce680d9f9b0fbb6a7edba040c9e03415530b7d954910790ecda3892ab881a7a8a2ffa92fcb1824d6098f4ab4704630fac4f0f34dcc36795af6984f9302551fcfd")); + testCases.put( + "0x4caad3e55d7c8e67c3a9c0397d743b8cf207ce2f", + Bytes.fromHexString( + "0x0c77a6a08a98cc812e7a5275421336d78cd6063747a3fa90385391df9f17d32f000000000000000000000000000000000000000000000000000000000000001bfa375b6bd93d3a73787ded81e2d470f511db2e127f950d63308d23a34d2eafc5594a8c4cb868f796a37b2a1c55eaea2d9fe6aa77d41c9f9b01a0ce240d605c1c")); + testCases.put( + "0x763f039273833269c26cfd79fe4713da5d74a45b", + Bytes.fromHexString( + "0x131d7ad7d9ef2b50c379b4cc5d84df851d652d6012cbc612e600a7f99455b241000000000000000000000000000000000000000000000000000000000000001c90e090540445c5533d4391e7bf4e5b11d6985105bdb7944abdcee09753a4b3e0697d19c3b03c7433672132d175a991111be1ecae5ea0d236eb751355e628beeb")); + testCases.put( + "0x014f31c9e429c69c270f4ccff594508abd520420", + Bytes.fromHexString( + "0x8370b9d2e6dd2d7ab1a0adf391a4f8380229de45fb017f812091b4226d7ebefc000000000000000000000000000000000000000000000000000000000000001ca7184b28a17f1fcb25953de968f5bf5c4b67ca115155f00cb4ee7c7a838d82cd44b55aa67acfd3fc8939b607eec5fe256f8098ab65db1c3db04c0efffff4c34c")); + testCases.put( + "0x6bafa3e7d355788ade4f5c3ce4ab865a490118da", + Bytes.fromHexString( + "0xc9d7002487ee5026fadffeed13893e827378acfca9171b89817c53dee584d289000000000000000000000000000000000000000000000000000000000000001bb5a3c506e8c38cd916bf20c237906befc29ae91d5474700c66ed47263222a487116fc65be6ad78140feb2df974d4568cc5aade5bf78ce14ec0df274b0983aafa")); + testCases.put( + "0xc7d1544579c6a0002966ca562923c5cfcb5e21d0", + Bytes.fromHexString( + "0x8dac2bb0d2e8ba5923577b2b12a0b9eb6b1af5c35ac6ec381ecf8ace2de84172000000000000000000000000000000000000000000000000000000000000001c549c2c7d6f644a5a9df73dfb88cbf1902fb6ad2ce7de27b18560f58d11c1de6658ba07f35e5676c33e71c6fbabfa30c7654f997394a8c713f7eedd2da78b25d1")); + testCases.put( + "0xf18c3dbf2aca83afc71b520e8ac3d4d016fa9ec1", + Bytes.fromHexString( + "0xfd7bdacc8bf6f0901fbb76d18dd3a9580b88cbbe8c5c667feb497ab2ec1aaf60000000000000000000000000000000000000000000000000000000000000001b01fb675ce7c18d34abf4d21993a36bd3b213fbd29f5077d178a84f6f5dbf7c4422f1d63423dc3bb682eed2f3c96c9ecbde516f1e26364556ad9950e431217240")); + testCases.put( + "0x22a09a6e7578d42f9af290f6417d2bc04ce3380f", + Bytes.fromHexString( + "0xe24beed8117992ce468610a4c7ea3b8bbce67831d5459993ad80ef75ff74399f000000000000000000000000000000000000000000000000000000000000001c65d5763121e91655fa84d7ae74b422d61db272cc6584622673e9993af10f5d7f5181a54f089809da91d008fca5fb6d7af9bb41d064b839f7643881a70c124bae")); + testCases.put( + "0x0431be799b7f179e4431ae1cb629c17edabdf917", + Bytes.fromHexString( + "0xd0490e2210e00722e024000245b28c5cb699c1597881a6e0dff13adfd7f00b7b000000000000000000000000000000000000000000000000000000000000001bc95aa8a187ed486f3f4a2c4fbc58b4f1e8fac5f6aad373ebce0d5e91d8e8bea67008db4c559da979b5b07a60890fd4cbe8db164d0102e395de7ea27aa5224fab")); + testCases.put( + "0x1ef26cd19e0b83e4f56c88b68293c1cd9444c684", + Bytes.fromHexString( + "0x96a49e2d7833c3dee1b5ba8da56088b3fc900ba28b80e1120341796271bbc8c7000000000000000000000000000000000000000000000000000000000000001b488f5bf61a104009d5b1c2102454199afb712742c4d563ce3dc6a1aaf5e177d7605652e31020e876ce65c1fd3f75ddbb163cb636065639b1f03e7b90c256e2f9")); + testCases.put( + "0xe04d0368b19ef078d6040abc1eac64869a510e8d", + Bytes.fromHexString( + "0x5f764e0f288b12167977651452f233de59ed6163eb6b17796195c96c603e4313000000000000000000000000000000000000000000000000000000000000001b5bb97625154686b77f4c3480fa06e314798503d157c5db85a15218f076d19239052a96f028d44331020106277591db48c0b07e7c501c181a842ccdd20b3089a6")); + testCases.put( + "0x730594bd0a7389acc19aad47741533abd0f19e81", + Bytes.fromHexString( + "0x5d811d11af03c52f95907d5f8fe1cf9ca6d25e44031588a08673ee39fc720c29000000000000000000000000000000000000000000000000000000000000001c963a39edda9392c83b390b7540b6b901bf1bf0f678c59603c0b8ec02f41633945ce49973a3e15591eebe3ff1b677696c1609509e547ba84ad711e13aa229c5e3")); + testCases.put( + "0x150e6c28a10d4b01ef1c5c733a2e5831fd75f684", + Bytes.fromHexString( + "0xed6b74c00def739b829b1d11f44190c075804414bcf78c30b6ea781d5f842b5d000000000000000000000000000000000000000000000000000000000000001c115e46eac1f6abaa48f4ed42713e8a10eb748d638331e83ab1f5b1aa672c3faa7f5892be39cfa345c785a369dd147d5c8bd79e37d4fc392782495231d52752aa")); + testCases.put( + "0xffb0f15492e9bb8dc8a8b3caf74cf30fbff51add", + Bytes.fromHexString( + "0xbc80fc2f142d3c139a6bdddccfb8d793be4bfff086904e4016ef5fdf4f552186000000000000000000000000000000000000000000000000000000000000001b8b5fc96d3cd453c51bf480ca1f564c6a88e3310bd938993acd6f4d2e1fa30857640660bb208f15a9cbc3bb2c1de892dea23628040c84cd48bf035cf1440e6ff2")); + testCases.put( + "0x5cba0a3e82a42466cbdd0cef06165f3936be541f", + Bytes.fromHexString( + "0xd14c00d0637bd1f80b8a29695375c4c4fbc25abeb0215190b937ac5d77138389000000000000000000000000000000000000000000000000000000000000001ceb7236075f80b65a43318e377fce6b4403a9fdf37e9d5e4563942625cba9603a67e8aae700ac3a877381cdcc71ddda0fbbf16a807e9f89ada558fef5b89c5eb5")); + testCases.put( + "0xfc7eaab26c1dfbb2a112d34794e0ec67ce76d471", + Bytes.fromHexString( + "0x964f1ec157e2214d09985d8d96997cedf59d6c75c1e01f9b6038d841f9a02f41000000000000000000000000000000000000000000000000000000000000001b61154b748a60ab1171413ad6d8cf8bf3d21c5c8da5c5025385565cc685519ff45358e7cb911a227fc36ce4d14bb11144735e90ad80d074f59b453bf2d8273b6e")); + testCases.put( + "0xe157b225a52436ac28043a4940a300bca589d0d9", + Bytes.fromHexString( + "0xd98b755dd654a52b968830f43c01f7b312c87b210c614bb13b27f3a1c3be430a000000000000000000000000000000000000000000000000000000000000001b8d0eb91bf9a3e3c7dd67e1703acf6f7d558e8e4407b30bc8db31b8b3c29ef907188c479e1285d9d5e74ca4e863114e70de6cd66f381e0adb1b387829aca1191d")); + testCases.put( + "0x726871df1a80253abcdc39b8efbb019485f0aa92", + Bytes.fromHexString( + "0xae7c9444d3777ab5966ce98a996cc590bd0560e5b7b4cf7c603c294e5f83ef64000000000000000000000000000000000000000000000000000000000000001b4462a10e115f9beb9a1ae7e1f9bc135ba18c3cb47d4562b63f34a2ffc3f0e104454e9de9b8f86ef018f185f6131cea90967c13377be39162fd70326cba74e088")); + testCases.put( + "0xb70a82e0b8d80c113f31797bef325f9894e33d53", + Bytes.fromHexString( + "0x59d4a98ff7238c392d366f4e1b59c0e0f062b8069d6aa7217d4271e6e06ea1b7000000000000000000000000000000000000000000000000000000000000001c180b92c72691caa41d149d3c8c4b02d8e637d447fbf702f80353e1c89aade51b27d59ae0d0bad8148134e17744de8a1ed126a381b2ba0039336b815b093e8178")); + testCases.put( + "0x6f8763efc3d08828982d41e37a9be12d795d81db", + Bytes.fromHexString( + "0x1d651cc72be8cafc2f831a5030188dc23bce6648be7045ff9eb3dad7f0d0458b000000000000000000000000000000000000000000000000000000000000001c15b9fcdba84fb454a47cbf830705a7fbb03bb8547cde5695338bab38213048505363b8bf99f730d497983ab0eb3986f9bb7750a98e2db08fc24f8e094c23f8e1")); + testCases.put( + "0x85f54483bb76aaf73fa1ee8313de109f309aaf33", + Bytes.fromHexString( + "0xeb3558fc388e8d245f892684fe0bd166bf5e1ec061f778436c36f7ba27fb5e88000000000000000000000000000000000000000000000000000000000000001cda01d3af46bfeb57e495ff722d0612132b66a3e2f7358e2d6a210ffa36a91c4671a5a1eeeb5f03f9b97fbd4076266a3aec7c2c64c13cf533298ea440e54aac04")); + testCases.put( + "0xf1383ccac546c49072c73fb3a0a4da4ca54d4b30", + Bytes.fromHexString( + "0x85543dcd0a1c590cfe63cc1c6e732a124b2138d4ebc7aa257ce4ff5ab7838a67000000000000000000000000000000000000000000000000000000000000001b737c920964ae5e15f3be8548774dd965f5b5af522f3e811cad247bda80c13e753bc58cb3f973fb67b3856a3a6f5aca1847ed06711ed722f11f8124c025adac1e")); + testCases.put( + "0xeaef2c85d19516bb3434a8bc364ecd270fba994c", + Bytes.fromHexString( + "0x334ea2be8566052b9c0f52fac3005b8fa96950dc17a2998f4ccc8a68b6f483a9000000000000000000000000000000000000000000000000000000000000001b5bb08f9a15c2deb532774b0e29d9782f7be619f57d15467d4282148eacf114d943c430c811c5979351ce3e77d1843e7677a1eeca350e3952958323ee5c5406e8")); + testCases.put( + "0x7a3177965811818903f69d2202464de03d43b6c7", + Bytes.fromHexString( + "0x9797b28b78d1a41f655e4670e797c4b4054b7aefa4c0b7cfabecfdedba772ab5000000000000000000000000000000000000000000000000000000000000001b8c69b0dc1f4fa557d658d9f2a2ae2a87abba4dc30a918c2249cc0df2cd520aed3f5012f755ad6320af14746a7531a70503200e5818a243e7d9d7389dcd47db08")); + testCases.put( + "0xc07d2a4f05c1617f3314e29e3dd98c083b9cc55c", + Bytes.fromHexString( + "0x185faa83fbab6980289744d05f6fbac7a9eea9078ed82af38b2f542922a57355000000000000000000000000000000000000000000000000000000000000001b345a728c2c87c11adc137d19d1c7a3acc2195b7591fb7449b3fd9ef476b32a005df1738096a09ec334cbbc43bfbc42be19777d6583f82ea499f59f8ac652a879")); + testCases.put( + "0x6722fa2ba638738b50b9cb45f4f7722ff8264b62", + Bytes.fromHexString( + "0xc281aefd2405635d3229c7bd155abf3ae22abd2a6b60b9f6358aa3b349fe76de000000000000000000000000000000000000000000000000000000000000001b5bc6959194476096e223df55cefc3ca991e5886fe80751a5ad40b1ad9999d6045426b00332eceed4152c733e8dbeb04987718a458e4369bfc6c30e538a95641f")); + testCases.put( + "0x2c3bc458c2aa4e62ba5c4300cfcbc344da9ee93e", + Bytes.fromHexString( + "0x53fdbd4b17fa328ed653476b7ce5beaa9f6b99affe3e64cf6fd99dc440379878000000000000000000000000000000000000000000000000000000000000001b0960d87cebc136087ed15f005349b20dcef74ea4f234d1ce9e10fb9e5fb0e4ee28d0755d8a6c66eb49eddb6b3ea8061a4265b83052d5e4ef9c7b6a3cccbd0441")); + testCases.put( + "0xff6e669dee405c6dc021a7e1ba2f5feb96c97adf", + Bytes.fromHexString( + "0x6edc1c049d2a86ca8fe892bf24a48dd3c5b630b03adb2a3b2855c1f7935264b9000000000000000000000000000000000000000000000000000000000000001b9a2f685a2089728baaf03c379703097d412504fd3399c2f79a18e1d13c07ee945c5da9bc00581bf2b1977dd5809683ec4e06a9a4a7a32561ec7aabbd54b04dbc")); + testCases.put( + "0xba0093215db426d68708d1e95156ef0aaf90b588", + Bytes.fromHexString( + "0x65f6ec58597df636a59d070d48b29db68fc229801db026a4dce11e59ca6d23b1000000000000000000000000000000000000000000000000000000000000001b5bee25353248c9d12df421c3db9eb3141918e2a69f766d7f11edc1ba66852d205ca06336f49919bb3f45e81a463d96b0dd5071bf7edb7663e20e3fbc505e232c")); + testCases.put( + "0x130dc34dc7b806a3e7aa2a2b2db8cd9dec66fd89", + Bytes.fromHexString( + "0x3546335f92dbc0883248693660061db1cb8283d2dd1969f0260915983d7ce30b000000000000000000000000000000000000000000000000000000000000001c27b51e23abfab6a82bf3bf83c23b222a01ecfdadda3587b58d965eebfab7dc5a7b3006e95e02b19c2fdfcb85794bad59cd2708b43cf658e4696b292c95cb6fc8")); + testCases.put( + "0xd50240c7d2ae4a7c30ebd3948460581f72385732", + Bytes.fromHexString( + "0x237d94f90f917d6eaf1987353f5907950ed6c8136112f029494e0f769ccddbcf000000000000000000000000000000000000000000000000000000000000001b14919b0374173a158b04213c718d74573c438891cca416f9e198704d56320daf7ab172688fdf770b1553fd7ec4e27a9bb57a84374562734904b8ade0f31fdb41")); + testCases.put( + "0x674fadf0fcf26febc6a21a70d27dbf2219d374dd", + Bytes.fromHexString( + "0xf2c26852616ca8ca4fbefad89111e5326f2c78158e609488461ab8fe3bc6573c000000000000000000000000000000000000000000000000000000000000001c0ed26622b205d658331ccea6286cf5d623687047e61b81c7cccae5181eb1c4b827312bb9af5c55c23f75cc72b20ff10a301ac3023f5823757c0fc9c4b9f827a2")); + testCases.put( + "0x8e76a1cd7db91aff5c8ed95f17148f9a8d4c81f6", + Bytes.fromHexString( + "0xd238468a4cf3eb5939950c0dfd1ed56f13f61784ea1dcc4ec472470370f8e4fd000000000000000000000000000000000000000000000000000000000000001b059cc3c246d17f6b044b3b15ee1f3bffc59865701703c2b6e9a9e282d65e3771788c55359b3f9879245ede61f801a4bcaa18bd6a90216b952e06815a407bc7ef")); + testCases.put( + "0xeb10e6f82e42a18ad05f623ed291f7bba26c1166", + Bytes.fromHexString( + "0x5dafec9564fbff6371b45399a361407b8e0f11ae8b62b784e121974957db9ef9000000000000000000000000000000000000000000000000000000000000001c2a71af5be39a199bb3b668994f28be40de1c0f5d59fa7b193cb72d4d357073f42e21a423a8b3bc8443ec9a05af6f2bf709f23c98c2c6c3a4d728873000d0b3c3")); + testCases.put( + "0x6ed176182fdb30cc2d9f553179603ba45fadbc4f", + Bytes.fromHexString( + "0x8eef9ad23caf2ddfb868faa610cee0de186722d20c8d8bd15d8258fd278f4b81000000000000000000000000000000000000000000000000000000000000001b890ae7c25d8c93d9b232d664f46357bfc21b529b427d9f3c84fe1e24cb5eabe515146ea64479f18acfebad6f556437d826833650fab32f940f5eeeeff0865aea")); + testCases.put( + "0x45505cf5182b9bfaee12c1b5b3e3d09377567b5c", + Bytes.fromHexString( + "0x7e38048ef47052bc73329abe12d51de302b690ec6e5c612a6dc545a16e578bdc000000000000000000000000000000000000000000000000000000000000001c1879fbfaeec45b117adfd62abc9fdc3ad575f1d7f09b388f02a2ad5ec37287504761f9cee67e6b6d75c6b53ddc966939df3f5f605083e8c93c06a64812b08ab7")); + testCases.put( + "0xcb69ddd0bf6c51348567444a93d8a3f9d995f363", + Bytes.fromHexString( + "0x9981e530d595012980ad4f1cd860f6d524a2f34f6aa132932796cd4be96d6e5d000000000000000000000000000000000000000000000000000000000000001ce08be9670177846e05696271da3960eb617869935456a14f634c3f604543dff36f1b05d985d111ae7cdaf679f75e9151030e09f0c8148c6ce3e02c1847415002")); + testCases.put( + "0xc97af81301f96ad50d9b7c64e322ef1527702278", + Bytes.fromHexString( + "0xcb7f1bf45f76e3dca564764290cbdaa64a7622fac589799a70199845682566b2000000000000000000000000000000000000000000000000000000000000001be6c9c8dc4b408518b89e5a048d36ad1426b3ace96b8518a5a9e88f286103758e0cd9a5ddac0f848eefb204dd403bffb063a718c8e1fca4c4ec94155269370b77")); + testCases.put( + "0xf00f8df597663bf073bcbf43f75d0e5b6caae7cb", + Bytes.fromHexString( + "0x21e69437899f6a37302b239fc0261c7ffabb970e8a48096475e998d2871f5bd2000000000000000000000000000000000000000000000000000000000000001b89501dd1567e56253ba097ffc663718fac90818e56ca6b393b69e9925162ce5a7262088cff050243662adfb2aac50143bf5aff60f904f2279d6f6cce5adbebdb")); + testCases.put( + "0x532f5d1695f4305a7193eecf7f17c4ae7fbd5c1c", + Bytes.fromHexString( + "0xf524d92f0d374b4d104786fb521265f6034cb6e2e6370d9d83464aaf8c87b0a6000000000000000000000000000000000000000000000000000000000000001b94332385b44da4cb31cc83c8d1caa85c99a85b58a812f9d3b8ab62e32c9dfc7e17f2b4d58e52bccb42bc069e8e6445a87deed25e094fe1cdce663623493c21c8")); + testCases.put( + "0x0b67296d0486d16d83f4f3ddb8e07a0a57c36631", + Bytes.fromHexString( + "0x739c5a643ca04c7bf21ea78cc89270a2d66662f1441879f6f0246a3b71416996000000000000000000000000000000000000000000000000000000000000001ba6f422a6fec65ac04fe923c8e7e92cd65a26b914f06124276dfdfb7ad396eb9b7613f03ab9c71d48af2c93d430a805cb9600991d92e76b504b63d55d7dd187a3")); + testCases.put( + "0xe5c7698dc89c75475d5d067e124696b81a0d53f5", + Bytes.fromHexString( + "0x33693f2a0c99ea981b5b11acd2c6bfbd58e43170c5a31f79b5a8eb3321858e71000000000000000000000000000000000000000000000000000000000000001b5b33ddf363736a3abd5a356eb610d2f9fd09ef6125fdcd4ff4c7775b39e87349225b33e5afebde52fe30eb987d72318e9cf095d892e7fbdcd9e5892786f49d1c")); + testCases.put( + "0x988cfd3652a9bacc3debc441f02a8bac7913e048", + Bytes.fromHexString( + "0xdb9ffb31945e1cbe86910f30bf7129e276f0ed9d7cd623f7b74a245324ce9c82000000000000000000000000000000000000000000000000000000000000001c8b9f853439623cc3af1f15ba21c639bfb3d8ba8302fa9d1603587a537b32fcd1308adf297dde649d208fc0b323f3c36e9404ba6dc8a74510d4082c867fbe1205")); + testCases.put( + "0xfcbbfb74050fee34c54f3b18a50d61a679f5f320", + Bytes.fromHexString( + "0x3930cff06ebe66193b61bd2d099c001a4f1c8597276b6324ced78b401746ed82000000000000000000000000000000000000000000000000000000000000001be2f6e9aa05b5af82987c65c31c131c152e4fa58f6b52a140519b11654c3cc8970472559ab09821cfb51b6d0c96ca9e5421f78f98af0d4aa601c49a6ceb9d4a78")); + testCases.put( + "0xe21d622e34869e656a1e28f278a6b8226082d153", + Bytes.fromHexString( + "0xadf263dddf4ad5f323822773b76e64abc06230aec4bde5d8b7be5ea1193f2b6d000000000000000000000000000000000000000000000000000000000000001c8caf0f4834f493ade134f733cd97752b4b1f0a5c8ffee47b6ec05f46857557bf20de09970e1c57404cf7ca7efbcaa95c47d99a2eba76aa72bd1b44bb0486e368")); + testCases.put( + "0x7bbba2e9fca9f2ade01d6c9c0f63a12307e3fcfd", + Bytes.fromHexString( + "0x9b3ef1d284641e6c3be8dddfcf29844b393729155edb1d146dd6023dd336dc46000000000000000000000000000000000000000000000000000000000000001ba08e0795bbf5850b36b4326bb104aa14a49d44eb18e31b034b1694c5bbbcfd9732580cd88ea1277b202c6d3a575e45fbb6b2e0a489b74343035bdeef5c32863a")); + testCases.put( + "0x6df661c685e9433e2f85961d15c1a1c3f2121417", + Bytes.fromHexString( + "0x7eed0e79c71b7baf9b2598a7a53bcdbaffb985ec48e1560bf963aa631d5d8c92000000000000000000000000000000000000000000000000000000000000001b21a8126ccf776ed394576e3c50e10e489951886b7e8b1a9d640b5ab4c63253737f76e9955dc860d49295a3782130cabe694eb2ee34ef0dc3367b07b3efe9f3ac")); + testCases.put( + "0xbf14cdbb0f88457c9e6225c0b87b0b0b3d38e953", + Bytes.fromHexString( + "0xead4ef63f6bd001593e8088cdd8ab3c0c35ba808bebb091f43240ecbd81db3b9000000000000000000000000000000000000000000000000000000000000001b30d5d51ab3a1987baf4fb41ad5a2467b4a4a1000c909d51caf389e191441634135d94ea50996b6db1b1182a2c28162058ae53c3ef52695e5cc6b17018039d90e")); + testCases.put( + "0xcd6eb47247a12aea535d6fd96cad1f4c7bcb409c", + Bytes.fromHexString( + "0x0c24abcfa29ff1f068a19f2f1db51b6da6ab042ac0ea3d74c87465b2075377ff000000000000000000000000000000000000000000000000000000000000001b18e975c578187caeda96b6029a7ec7aa037757cfd182b5f8d71f872233c2264a6adbb4465a68fbf4a574071cc4973f5fd5e7b721c86cb7e0f47f595222e37289")); + testCases.put( + "0x9765c8a57ade562c30166b7e18aef179a22da185", + Bytes.fromHexString( + "0xda13687f911cf8ede5e0a4317d8b9bf691b56bc2f3f4e463c8c2eb1f61a54469000000000000000000000000000000000000000000000000000000000000001bf6e5df315197d9fe994fae7e05e33be4bd090f9533f36c6285b80478cd21c38533928bb06d48795a86c12f5ccb95758e891d8b1b2d62106e85ae36cb8414d56b")); + + final SECP256K1 signatureAlgorithm = new SECP256K1(); + if (attemptNative != null && (!attemptNative || !signatureAlgorithm.maybeEnableNative())) { + signatureAlgorithm.disableNative(); + } + output.println(signatureAlgorithm.isNative() ? "Native secp256k1" : "Java secp256k1"); + + final ECRECPrecompiledContract contract = + new ECRECPrecompiledContract(gasCalculatorForFork(fork), signatureAlgorithm); + + warmup = warmup / testCases.size(); + iterations = iterations / testCases.size(); + double execTime = Double.MIN_VALUE; // a way to dodge divide by zero + long gasCost = 0; + for (final Map.Entry testCase : testCases.entrySet()) { + execTime += runPrecompileBenchmark(testCase.getValue(), contract); + gasCost += contract.gasRequirement(testCase.getValue()); + } + execTime /= testCases.size(); + gasCost /= testCases.size(); + output.printf( + "ecrecover %,6d gas @%,7.1f µs /%,8.1f MGps%n", + gasCost, execTime * 1_000_000, gasCost / execTime / 1_000_000); + } +} diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/ModExpBenchmark.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/ModExpBenchmark.java new file mode 100644 index 00000000000..452fd407626 --- /dev/null +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/ModExpBenchmark.java @@ -0,0 +1,164 @@ +/* + * Copyright contributors to Hyperledger Besu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evmtool.benchmarks; + +import org.hyperledger.besu.evm.precompile.BigIntegerModularExponentiationPrecompiledContract; + +import java.io.PrintStream; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.tuweni.bytes.Bytes; + +/** Benchmark Modular Exponentiation */ +public class ModExpBenchmark extends BenchmarkExecutor { + + /** Benchmark with default math warmups and iterations */ + public ModExpBenchmark() { + super(MATH_WARMUP, MATH_ITERATIONS); + } + + @Override + public void runBenchmark( + final PrintStream output, final Boolean attemptNative, final String fork) { + final Map testcases = new LinkedHashMap<>(); + testcases.put( + "eip_example1", + Bytes.fromHexString( + "0000000000000000000000000000000000000000000000000000000000000001" + + "0000000000000000000000000000000000000000000000000000000000000020" + + "0000000000000000000000000000000000000000000000000000000000000020" + + "03" + + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e" + + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f")); + testcases.put( + "eip_example2", + Bytes.fromHexString( + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000020" + + "0000000000000000000000000000000000000000000000000000000000000020" + + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e" + + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f")); + testcases.put( + "even-modulus-1", + Bytes.fromHexString( + "0000000000000000000000000000000000000000000000000000000000000003" + + "0000000000000000000000000000000000000000000000000000000000000001" + + "00000000000000000000000000000000000000000000000000000000000003c2" + + "040160" + + "02" + + "4518968061546464452029984405379963244433254832348165045983839181603600983245188119082741180552472823434126339186042653363989253518144015007104659260895861906540664936284389736130979465984263224400655133820675791338815252163142936101184074977707018635613728563507946963514079867296353079585444179075183175315953500862929638853495671020263166123912364061541662955981749424030252416330220564030645929402440479045589943839631409636357644094127401186503107365632233122371688639562179885062893961510897259834525401728081797411184820573804096446362924176080926052008070342876591822173915634645231182811305568049542955744148010693635112077769594038286419007643605441221736768092092706367136248982357930831050114862462054469804238839007660797444001134145988063087013657265067255538916788266246587774231646489345179567885975873995767749906187041937713976494258573504873269320274358396975658022816526738914029788471066595929777423497242252763504644221066495966982158816143636722736200299105017320500139589998102103536908651755056175006587609525845133254470473698921229697550145309121304642224273213418856615560961843245211567388930209839462064588566503446549415643465733541976019955544090933949692508519895293721888001835024288589127818157262958206047538648802179821901844091151603223229973835165715768557428338775055435040494382003663260090655173262271219880999454966135210800173588881197223814096778846598765822161982688788574265773201009190341430440400154076998270731076034021917712825351270109621323258567738829791704547404897555410847468529100600344699859551947494210268509149049419749744679372826553895949980386864014015247047775654329663958663391477680679444996526407026021137970100258833584773507489900747148344826790699325870056679710341571267983857125765234149331990149745571500943300684008078036054281629105618499442731182983775330888524074001975745730722737461725166625564316976464879780901853271273641654911641084141502464")); + testcases.put( + "even-modulus-2", + Bytes.fromHexString( + "0000000000000000000000000000000000000000000000000000000000000010" + + "00000000000000000000000000000000000000000000000000000000000000d8" + + "0000000000000000000000000000000000000000000000000000000000000010" + + "e0060000a921212121212121ff000021" + + "2b212121ffff1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f00feffff212121212121ffffffff1fe1e0e0e01e1f1f169f1f1f1f490afcefffffffffffffffff82828282828282828282828282828282828282828200ffff28ff2b212121ffff1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1fffffffffff0afceffffff7ffffffffff7c8282828282a1828282828282828282828282828200ffff28ff2b212121ffff1f1f1f1f1f1fd11f1f1f1f1f1f1f1f1f1f1fffffffffffffffff21212121212121fb2121212121ffff1f1f1f1f1f1f1f1fffaf82828282828200ff" + + "ff28ff2b218282000000000000000000")); + testcases.put( + "even-modulus-3", + Bytes.fromHexString( + "0000000000000000000000000000000000000000000000000000000000000002" + + "0000000000000000000000000000000000000000000000000000000000000001" + + "000000000000000000000000000000000000000000000000000000000000031f" + + "9ce0" + + "02" + + "4BC7569FD25D6FDAC9A0AB948FA20EE025AC8E9465351384E619B417B0A9E88ECDE2503875E7F9E06D9E3167E5763CDAE0938BF63F2E026AED3494BA85D03A215C9B804779632B6DFC08585FA39C2491B7A63DD819E9F0E8D818CA0DA4C5DDF34AF225FC90F0047B88F39A708AE2529DE01B2AFEE12B5F7D9420CB6ACFAC048BCF7E99411E1D7ECDDA8625278FEFC2765D3E2EFD5255554E2C381FFAA3D9BF01A9941CBEFAF96EBA1B40C9C8A3CCFAA181DED264214233AA7B71D1D1DEDCE61F7C96FB056BAEE8D0481E0F95E14583AEB53D36D4FC70AE26E0578018F5E73C8A85A8F0047050C70D2BE3FEB6DEA8A63F47051286E1151430B0EC410081D0A223313DF2D2C6BF5CE28C32DEA4F3EF79F0BE51460DC6E4733265E122BB074CE6578D906D77D8C7BBAA4EAEB1EDD1D52805284E310A493B865739A30C33E5366B3AF1F6A27E3001499EEA600B4FA22A2E6E15FCED013D1717A3E2FCB06C971B2CAFECA7D85A7D98921F49730364A7703AF47F3894346D683070F38B1C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")); + testcases.put( + "nagydani-1-square", + Bytes.fromHexString( + "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb502fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b")); + testcases.put( + "nagydani-1-qube", + Bytes.fromHexString( + "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb503fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b")); + testcases.put( + "nagydani-1-pow0x10001", + Bytes.fromHexString( + "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5010001fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b")); + testcases.put( + "nagydani-2-square", + Bytes.fromHexString( + "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf5102e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087")); + testcases.put( + "nagydani-2-qube", + Bytes.fromHexString( + "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf5103e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087")); + testcases.put( + "nagydani-2-pow0x10001", + Bytes.fromHexString( + "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51010001e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087")); + testcases.put( + "nagydani-3-square", + Bytes.fromHexString( + "000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb02d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d")); + testcases.put( + "nagydani-3-qube", + Bytes.fromHexString( + "000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb03d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d")); + testcases.put( + "nagydani-3-pow0x10001", + Bytes.fromHexString( + "000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb010001d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d")); + testcases.put( + "nagydani-4-square", + Bytes.fromHexString( + "000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b8102df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f")); + testcases.put( + "nagydani-4-qube", + Bytes.fromHexString( + "000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b8103df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f")); + testcases.put( + "nagydani-4-pow0x10001", + Bytes.fromHexString( + "000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81010001df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f")); + testcases.put( + "nagydani-5-square", + Bytes.fromHexString( + "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf02e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad")); + testcases.put( + "nagydani-5-qube", + Bytes.fromHexString( + "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf03e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad")); + testcases.put( + "nagydani-5-pow0x10001", + Bytes.fromHexString( + "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf010001e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad")); + + final BigIntegerModularExponentiationPrecompiledContract contract = + new BigIntegerModularExponentiationPrecompiledContract(gasCalculatorForFork(fork)); + + if (attemptNative != null + && (!attemptNative + || !BigIntegerModularExponentiationPrecompiledContract.maybeEnableNative())) { + BigIntegerModularExponentiationPrecompiledContract.disableNative(); + } + output.println( + BigIntegerModularExponentiationPrecompiledContract.isNative() + ? "Native ModExp" + : "Java modExp"); + + for (final Map.Entry testCase : testcases.entrySet()) { + final double execTime = runPrecompileBenchmark(testCase.getValue(), contract); + + long gasCost = contract.gasRequirement(testCase.getValue()); + output.printf( + "ModEXP %-22s %,6d gas @%,7.1f µs /%,8.1f MGps%n", + testCase.getKey(), gasCost, execTime * 1_000_000, gasCost / execTime / 1_000_000); + } + } +} diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/Secp256k1Benchmark.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/Secp256k1Benchmark.java new file mode 100644 index 00000000000..fad5d5013c8 --- /dev/null +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/Secp256k1Benchmark.java @@ -0,0 +1,72 @@ +/* + * Copyright contributors to Hyperledger Besu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evmtool.benchmarks; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.hyperledger.besu.crypto.Hash.keccak256; + +import org.hyperledger.besu.crypto.KeyPair; +import org.hyperledger.besu.crypto.SECP256K1; +import org.hyperledger.besu.crypto.SECPPrivateKey; +import org.hyperledger.besu.crypto.SECPSignature; + +import java.io.PrintStream; +import java.math.BigInteger; +import java.util.concurrent.TimeUnit; + +import com.google.common.base.Stopwatch; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; + +/** Benchmark secp256k1 public key extraction */ +public class Secp256k1Benchmark extends BenchmarkExecutor { + + /** secp256k1 benchmark using default math warmup and iterations */ + public Secp256k1Benchmark() { + super(MATH_WARMUP, MATH_ITERATIONS); + } + + @Override + public void runBenchmark( + final PrintStream output, final Boolean attemptNative, final String fork) { + final SECP256K1 signatureAlgorithm = new SECP256K1(); + if (attemptNative != null && (!attemptNative || !signatureAlgorithm.maybeEnableNative())) { + signatureAlgorithm.disableNative(); + } + output.println(signatureAlgorithm.isNative() ? "Native secp256k1" : "Java secp256k1"); + + final SECPPrivateKey privateKey = + signatureAlgorithm.createPrivateKey( + new BigInteger("c85ef7d79691fe79573b1a7064c19c1a9819ebdbd1faaab1a8ec92344438aaf4", 16)); + final KeyPair keyPair = signatureAlgorithm.createKeyPair(privateKey); + + final Bytes data = Bytes.wrap("This is an example of a signed message.".getBytes(UTF_8)); + final Bytes32 dataHash = keccak256(data); + final SECPSignature signature = signatureAlgorithm.sign(dataHash, keyPair); + for (int i = 0; i < warmup; i++) { + signatureAlgorithm.recoverPublicKeyFromSignature(dataHash, signature); + } + final Stopwatch timer = Stopwatch.createStarted(); + for (int i = 0; i < iterations; i++) { + signatureAlgorithm.recoverPublicKeyFromSignature(dataHash, signature); + } + timer.stop(); + + final double elapsed = timer.elapsed(TimeUnit.NANOSECONDS) / 1.0e9D; + final double perCall = elapsed / MATH_ITERATIONS; + + output.printf("secp256k1 signature recovery for %,.1f µs%n", perCall * 1_000_000); + } +} diff --git a/ethereum/evmtool/src/test/java/org/hyperledger/besu/evmtool/CodeValidationSubCommandTest.java b/ethereum/evmtool/src/test/java/org/hyperledger/besu/evmtool/CodeValidationSubCommandTest.java index 8d83a3c32af..f98256324a7 100644 --- a/ethereum/evmtool/src/test/java/org/hyperledger/besu/evmtool/CodeValidationSubCommandTest.java +++ b/ethereum/evmtool/src/test/java/org/hyperledger/besu/evmtool/CodeValidationSubCommandTest.java @@ -21,7 +21,7 @@ import java.io.ByteArrayOutputStream; import java.io.PrintStream; -import org.junit.Test; +import org.junit.jupiter.api.Test; import picocli.CommandLine; public class CodeValidationSubCommandTest { diff --git a/ethereum/evmtool/src/test/java/org/hyperledger/besu/evmtool/StateTestSubCommandTest.java b/ethereum/evmtool/src/test/java/org/hyperledger/besu/evmtool/StateTestSubCommandTest.java index 8b88ab78339..3a893898884 100644 --- a/ethereum/evmtool/src/test/java/org/hyperledger/besu/evmtool/StateTestSubCommandTest.java +++ b/ethereum/evmtool/src/test/java/org/hyperledger/besu/evmtool/StateTestSubCommandTest.java @@ -24,7 +24,7 @@ import java.io.ByteArrayOutputStream; import java.io.PrintWriter; -import org.junit.Test; +import org.junit.jupiter.api.Test; import picocli.CommandLine; public class StateTestSubCommandTest { diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-calculate-difficulty.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-calculate-difficulty.json index 3de9d7ed247..1a3c7a178c6 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-calculate-difficulty.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-calculate-difficulty.json @@ -51,7 +51,7 @@ "parentDifficulty": "131072", "parentGasUsed": "50000000000000000", "parentGasLimit": "100000000000000000", - "parentTimstamp": "0", + "parentTimestamp": "0", "blockHashes": { "0": "0x87c5fa7cef8b99fc333b662c1a4306c7d41d9d43a23414b15aa25b3e093ae88f" }, diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-example-yul.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-example-yul.json index 3de9d7ed247..1a3c7a178c6 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-example-yul.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-example-yul.json @@ -51,7 +51,7 @@ "parentDifficulty": "131072", "parentGasUsed": "50000000000000000", "parentGasLimit": "100000000000000000", - "parentTimstamp": "0", + "parentTimestamp": "0", "blockHashes": { "0": "0x87c5fa7cef8b99fc333b662c1a4306c7d41d9d43a23414b15aa25b3e093ae88f" }, diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-sweep.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-sweep.json new file mode 100644 index 00000000000..bc7d113ec79 --- /dev/null +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-sweep.json @@ -0,0 +1,116 @@ +{ + "cli": [ + "t8n", + "--input.alloc=stdin", + "--input.txs=stdin", + "--input.env=stdin", + "--output.result=stdout", + "--output.alloc=stdout", + "--output.body=stdout", + "--state.fork=Cancun", + "--state.chainid=1", + "--state.reward=0" + ], + "stdin": { + "alloc": { + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "nonce": "0x00", + "balance": "0x3635c9adc5dea00000", + "code": "0x", + "storage": {} + }, + "0x1111111111111111111111111111111111111111": { + "nonce": "0x00", + "balance": "0x01", + "code": "0x60015f555fff", + "storage": {} + } + }, + "txs": [ + { + "type": "0x0", + "chainId": "0x1", + "nonce": "0x0", + "gasPrice": "0xa", + "gas": "0x5f5e100", + "value": "0x0", + "input": "0x", + "to": "0x1111111111111111111111111111111111111111", + "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "v": "0x1b", + "r": "0x7529278ba20a00f86b3659cd9f48285243075a63d7d3083f0f8977da3fc43a6f", + "s": "0x3745796d09090fa3b1aea76626aa0a3153b496f937f5a08b974309858d30e91d" + } + ], + "env": { + "currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentGasLimit": "10000000000", + "currentNumber": "1", + "currentTimestamp": "1000", + "currentRandom": "0", + "currentDifficulty": "0", + "parentDifficulty": "0", + "parentBaseFee": "7", + "parentGasUsed": "0", + "parentGasLimit": "10000000000", + "parentTimestamp": "0", + "blockHashes": { + "0": "0xb9a3dd3d2865b4f8d6c701d6610a99800ad7e4ace851fb4e8d4e26fc1b7ad8dc" + }, + "ommers": [], + "withdrawals": [], + "parentUncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "parentBlobGasUsed": "0", + "parentExcessBlobGas": "0" + } + }, + "stdout": { + "alloc": { + "0x0000000000000000000000000000000000000000": { + "balance": "0x1" + }, + "0x1111111111111111111111111111111111111111": { + "code": "0x60015f555fff", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + "balance": "0x0" + }, + "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": { + "balance": "0x37731" + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x3635c9adc5de9472b2", + "nonce": "0x1" + } + }, + "body": "0xf863f861800a8405f5e10094111111111111111111111111111111111111111180801ba07529278ba20a00f86b3659cd9f48285243075a63d7d3083f0f8977da3fc43a6fa03745796d09090fa3b1aea76626aa0a3153b496f937f5a08b974309858d30e91d", + "result": { + "stateRoot": "0x3a0e532de836d767cae901aba671040fedc07557d277f7203066f640ed95f78d", + "txRoot": "0x60ae0f99c255ecf6436fdf1b503dbce0b7c84573fd5ed17bbfc7850c444f7bc3", + "receiptsRoot": "0x6b0b401f0a222e669b278b3a0ea50264b2771b63a3ad88f3892b507e4d8dfb2e", + "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "receipts": [ + { + "root": "0x", + "status": "0x1", + "cumulativeGasUsed": "0x127bb", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "logs": null, + "transactionHash": "0x2b992759a7ca56e96a5d44f118f0edb740a27c6f49482367799918c1e65b673e", + "contractAddress": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x127bb", + "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "transactionIndex": "0x0" + } + ], + "currentDifficulty": null, + "gasUsed": "0x127bb", + "currentBaseFee": "0x7", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "blobGasUsed": "0x0", + "currentExcessBlobGas": "0x0" + } + } +} \ No newline at end of file diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-to-self.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-to-self.json new file mode 100644 index 00000000000..7d8907d9bfb --- /dev/null +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-to-self.json @@ -0,0 +1,115 @@ +{ + "cli": [ + "t8n", + "--input.alloc=stdin", + "--input.txs=stdin", + "--input.env=stdin", + "--output.result=stdout", + "--output.alloc=stdout", + "--output.body=stdout", + "--state.fork=Cancun", + "--state.chainid=1", + "--state.reward=0" + ], + "stdin": { + "alloc": { + "0x095e7baea6a6c7c4c2dfeb977efac326af552d87": { + "balance": "0x0de0b6b3a7640000", + "code": "0x3060005530ff00", + "nonce": "0x00", + "storage": { + } + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x0de0b6b3a7640000", + "code": "0x", + "nonce": "0x00", + "storage": { + } + } + }, + "txs": [ + { + "type": "0x0", + "chainId": "0x1", + "nonce": "0x0", + "gasPrice": "0xa", + "gas": "0x0f4240", + "value": "0x0186a0", + "input": "0x", + "to": "0x095e7baea6a6c7c4c2dfeb977efac326af552d87", + "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "v": "0x1c", + "r": "0x7bb4986663aec020c016ea3db37ba36e62e9c7d355dc8ed8566b20ce7452b600", + "s": "0x7da62397d8a969f674442837f419001f2671df0f19a45586ed3acfd93e819d82" + } + ], + "env": { + "currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentGasLimit": "10000000000", + "currentNumber": "1", + "currentTimestamp": "1000", + "currentRandom": "0", + "currentDifficulty": "0", + "parentDifficulty": "0", + "parentBaseFee": "7", + "parentGasUsed": "0", + "parentGasLimit": "10000000000", + "parentTimestamp": "0", + "blockHashes": { + "0": "0xb9a3dd3d2865b4f8d6c701d6610a99800ad7e4ace851fb4e8d4e26fc1b7ad8dc" + }, + "ommers": [], + "withdrawals": [], + "parentUncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "parentBlobGasUsed": "0", + "parentExcessBlobGas": "0" + } + }, + "stdout": { + "alloc": { + "0x095e7baea6a6c7c4c2dfeb977efac326af552d87": { + "code": "0x3060005530ff00", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000095e7baea6a6c7c4c2dfeb977efac326af552d87" + }, + "balance": "0xde0b6b3a76586a0" + }, + "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": { + "balance": "0x233c1" + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0xde0b6b3a75b2232", + "nonce": "0x1" + } + }, + "body": "0xf865f863800a830f424094095e7baea6a6c7c4c2dfeb977efac326af552d87830186a0801ca07bb4986663aec020c016ea3db37ba36e62e9c7d355dc8ed8566b20ce7452b600a07da62397d8a969f674442837f419001f2671df0f19a45586ed3acfd93e819d82", + "result": { + "stateRoot": "0xddd3a541e86e2dd0293959736de63e1fad74ae95149f34740b1173378e82527a", + "txRoot": "0x0cbd46498d79551ba2f4237443d408194f7493f1fd567dbeaf1d53b41b41485a", + "receiptsRoot": "0xbc67bed8ee77b1d9dd8eb6d6e55abd11e49c50e16832f0c350ae07027c859f19", + "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "receipts": [ + { + "root": "0x", + "status": "0x1", + "cumulativeGasUsed": "0xbbeb", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "logs": null, + "transactionHash": "0xa87c1a093fe07f3d38db9cde21d05b407f527e88f7c698c9008b6138119d2487", + "contractAddress": "0x0000000000000000000000000000000000000000", + "gasUsed": "0xbbeb", + "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "transactionIndex": "0x0" + } + ], + "currentDifficulty": null, + "gasUsed": "0xbbeb", + "currentBaseFee": "0x7", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "blobGasUsed": "0x0", + "currentExcessBlobGas": "0x0" + } + } +} \ No newline at end of file diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-transient.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-transient.json new file mode 100644 index 00000000000..1860990b0f7 --- /dev/null +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-transient.json @@ -0,0 +1,100 @@ +{ + "cli": [ + "t8n", + "--input.alloc=stdin", + "--input.txs=stdin", + "--input.env=stdin", + "--output.result=stdout", + "--output.alloc=stdout", + "--output.body=stdout", + "--state.fork=Cancun", + "--state.chainid=1", + "--state.reward=0" + ], + "stdin": { + "alloc": { + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "nonce": "0x00", + "balance": "0x3635c9adc5dea00000", + "code": "0x", + "storage": {} + } + }, + "txs": [ + { + "type": "0x0", + "chainId": "0x0", + "nonce": "0x0", + "gasPrice": "0xa", + "gas": "0x5f5e100", + "value": "0x0", + "input": "0x600d8060175f39805f80f05f805f805f855af1505ffffe600280600b5f39805ff3fe5fff", + "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "v": "0x1b", + "r": "0xf2bb558b73cfb96466c41785fdd0f1e367b4703d49653e617cffdb7316a01e87", + "s": "0x11e0423aeea027a1e48dc3adffe2b27652d8154599f10b6f552d51b1fcb632ae" + } + ], + "env": { + "currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentGasLimit": "10000000000", + "currentNumber": "1", + "currentTimestamp": "1000", + "currentRandom": "0", + "currentDifficulty": "0", + "parentDifficulty": "0", + "parentBaseFee": "7", + "parentGasUsed": "0", + "parentGasLimit": "10000000000", + "parentTimestamp": "0", + "blockHashes": { + "0": "0xc5d4b3d67827b580c95a2a0980670255c15bfb964e8c4183d18971659bd5b6a8" + }, + "ommers": [], + "withdrawals": [], + "parentUncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "parentBlobGasUsed": "0", + "parentExcessBlobGas": "0" + } + }, + "stdout": { + "alloc": { + "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": { + "balance": "0x48552" + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x3635c9adc5de90ee44", + "nonce": "0x1" + } + }, + "body": "0xf873f871800a8405f5e1008080a4600d8060175f39805f80f05f805f805f855af1505ffffe600280600b5f39805ff3fe5fff1ba0f2bb558b73cfb96466c41785fdd0f1e367b4703d49653e617cffdb7316a01e87a011e0423aeea027a1e48dc3adffe2b27652d8154599f10b6f552d51b1fcb632ae", + "result": { + "stateRoot": "0xe8a9461dcfdbaa48bbddca4f4baa439e45f1489827e5deeb2797363323e34769", + "txRoot": "0x35ab0ce85af281d6e600d467fb3ed12063994cc9e105cbdb4eb1ba65ed9edddf", + "receiptsRoot": "0xdf87447856d3a36db48c7ec997ff29845eeb513cb49aaa20547290f64f3710d1", + "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "receipts": [ + { + "root": "0x", + "status": "0x1", + "cumulativeGasUsed": "0x181c6", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "logs": null, + "transactionHash": "0xd954e10ebf0b55b71512b53a6ebae09372ccc6b2bf87b199e8aa8a5c4f757430", + "contractAddress": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f", + "gasUsed": "0x181c6", + "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "transactionIndex": "0x0" + } + ], + "currentDifficulty": null, + "gasUsed": "0x181c6", + "currentBaseFee": "0x7", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "blobGasUsed": "0x0", + "currentExcessBlobGas": "0x0" + } + } +} \ No newline at end of file diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-blobs-per-tx.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-blobs-per-tx.json new file mode 100644 index 00000000000..b2ed324b3d6 --- /dev/null +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-blobs-per-tx.json @@ -0,0 +1,117 @@ +{ + "cli": [ + "t8n", + "--input.alloc=stdin", + "--input.txs=stdin", + "--input.env=stdin", + "--output.result=stdout", + "--output.alloc=stdout", + "--output.body=txs.rlp", + "--state.fork=Cancun", + "--state.chainid=1", + "--state.reward=0" + ], + "stdin": { + "alloc": { + "0x0000000000000000000000000000000000000200": { + "balance": "0x1" + }, + "0x8a0a19589531694250d570040a0c4b74576919b8": { + "balance": "0x3b908bc7", + "nonce": "0x1" + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x43e39" + } + }, + "txs": [ + { + "type": "0x3", + "chainId": "0x1", + "nonce": "0x0", + "maxPriorityFeePerGas": "0x0", + "maxFeePerGas": "0x7", + "gas": "0x5208", + "value": "0x1", + "input": "0x", + "to": "0x0000000000000000000000000000000000000100", + "accessList": [], + "maxFeePerBlobGas": "0x1", + "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "blobVersionedHashes": [ + "0x0100000000000000000000000000000000000000000000000000000000000000" + ], + "v": "0x1", + "r": "0xa8f4757869fbb831ba4ed3a7c8f868b0e2e0c1eda97937aab035560fffdedf3c", + "s": "0x19d9b041540e3d6f5f56dc29deb8834a08171e92037cf567b922357e70f8e54a" + } + ], + "env": { + "currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentGasLimit": "100000000000000000", + "currentNumber": "2", + "currentTimestamp": "24", + "currentRandom": "0", + "currentDifficulty": "0", + "parentDifficulty": "0", + "parentBaseFee": "7", + "parentGasUsed": "21000", + "parentGasLimit": "100000000000000000", + "parentTimestamp": "12", + "blockHashes": { + "0": "0x7801ae59edc1754a571e2eb418e8e8a44079b1e7ce3cd032cd3169973deb6be9", + "1": "0xe67fa9e2865de83bcff54ca002c4b9dcde6cd094367ed4e85f28c1298fdb23a5" + }, + "ommers": [], + "withdrawals": [], + "parentUncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "currentExcessBlobGas": "0", + "currentBlobGasUsed": "0" + } + }, + "stdout": { + "alloc": { + "0x0000000000000000000000000000000000000100": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000200": { + "balance": "0x1" + }, + "0x8a0a19589531694250d570040a0c4b74576919b8": { + "balance": "0x3b908bc7", + "nonce": "0x1" + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x0", + "nonce": "0x1" + } + }, + "result": { + "stateRoot": "0xd29f5a8dd1a63e0a299009f546bdf447fb61f1604d95e737bd8eb3c089d78060", + "txRoot": "0xda80a6acad2089c995d9df6604f54f2102eb7a3bc73b001957ef851ee3606902", + "receiptsRoot": "0xeaa8c40899a61ae59615cf9985f5e2194f8fd2b57d273be63bde6733e89b12ab", + "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "receipts": [ + { + "root": "0x", + "status": "0x1", + "cumulativeGasUsed": "0x5208", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "logs": null, + "transactionHash": "0x2f68a5bb6b843147e9ef8628047b6c5d5a0df834dc572007af7d4fce8e644c20", + "contractAddress": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x5208", + "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "transactionIndex": "0x0" + } + ], + "currentDifficulty": null, + "gasUsed": "0x5208", + "currentBaseFee": "0x7", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "blobGasUsed": "0x0", + "currentExcessBlobGas": "0x0" + } + } +} \ No newline at end of file diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/istanbul-cumulative-gas.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/istanbul-cumulative-gas.json index 7146666176f..d3dd7021df7 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/istanbul-cumulative-gas.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/istanbul-cumulative-gas.json @@ -366,7 +366,7 @@ "parentDifficulty": "131072", "parentGasUsed": "50000000000000000", "parentGasLimit": "100000000000000000", - "parentTimstamp": "0", + "parentTimestamp": "0", "blockHashes": { "0": "0xa2886eb8890eda7143a5d6bcb16949db9f3871f4c2dcc8618ab62c0632a23ab7" }, diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/london-env-no-basefee.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/london-env-no-basefee.json index dcfe6a32b82..052ebb5260b 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/london-env-no-basefee.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/london-env-no-basefee.json @@ -52,7 +52,7 @@ "parentBaseFee": "7", "parentGasUsed": "50000000000000000", "parentGasLimit": "100000000000000000", - "parentTimstamp": "0", + "parentTimestamp": "0", "blockHashes": { "0": "0xe3c84688fa32c20955c535c7d25b5b4b196079e40a9c47c9cb1edb5e58b3dce5" }, diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-blockhash.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-blockhash.json index c393d1cef2b..e1c331206d2 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-blockhash.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-blockhash.json @@ -51,7 +51,7 @@ "parentDifficulty": "0", "parentGasUsed": "0", "parentGasLimit": "100000000000000000", - "parentTimstamp": "12", + "parentTimestamp": "12", "blockHashes": { "0": "0x651666d6d8727a6478a750dc8406c1bda0be85abc99094dca694807fa772f83c", "1": "0x0275fc82fe832100726ec7c26078ffb1c1dbff14a3b52d93dc359768fc8c7baa" diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-init-code.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-init-code.json index 3c398c92de6..d536a6a7260 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-init-code.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-init-code.json @@ -29,11 +29,10 @@ "gas": "0x989680", "value": "0x0", "input": "0x610001600081600b8239f30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "protected": true, "secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "v": "0x0", - "r": "0x0", - "s": "0x0" + "v": "0x26", + "r": "0xb8ba45e0ef29fa4dae53b530d498e9b320adcd8723772d76b57dfb7f1b640d3d", + "s": "0x675ee050b02d95a683235846a39fdc01854f680d98f8723222d339e5a15b30cc" } ], "env": { @@ -47,7 +46,7 @@ "parentBaseFee": "7", "parentGasUsed": "0", "parentGasLimit": "100000000000000000", - "parentTimstamp": "0", + "parentTimestamp": "0", "blockHashes": { "0": "0xea2d7e0192d890c222f0302d972a02db0bf0c6d08257d73aa1210d08d24f30c3" }, diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-no-nonce.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-no-nonce.json index d967e398ef6..86cefab468f 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-no-nonce.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-no-nonce.json @@ -28,11 +28,9 @@ "value": "0x0", "input": "0x", "to": "0x0000000000000000000000000000000000000100", - "protected": true, - "secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "v": "0x0", - "r": "0x0", - "s": "0x0" + "v": "0x26", + "r": "0xe319535da2cae2d72ddb352054535d000c23acdc7cad9d828891253f3850d0d2", + "s": "0x32fe4444149b609e2ffa621e23e179b12028309fdb8cb0a5c1bbc58135299af1" } ], "env": { @@ -45,7 +43,7 @@ "parentDifficulty": "0", "parentGasUsed": "0", "parentGasLimit": "100000000000000000", - "parentTimstamp": "12", + "parentTimestamp": "12", "blockHashes": { "0": "0x651666d6d8727a6478a750dc8406c1bda0be85abc99094dca694807fa772f83c", "1": "0x0275fc82fe832100726ec7c26078ffb1c1dbff14a3b52d93dc359768fc8c7baa" diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-overflow.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-overflow.json index ca3eed9f676..8f8b29b7525 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-overflow.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-overflow.json @@ -38,7 +38,7 @@ "parentBaseFee": "7", "parentGasUsed": "0", "parentGasLimit": "100000000000000000", - "parentTimstamp": "0", + "parentTimestamp": "0", "blockHashes": { "0": "0xfc63c00c7fe67bcc6ae52ea4eed5ff00b8673b1afb581d090c34b5fa6eca9467" }, diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals.json index 6e3769bef22..5a4efc2eea0 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals.json @@ -23,11 +23,9 @@ "value": "0x0", "input": "0x", "to": "0x0000000000000000000000000000000000000100", - "protected": true, - "secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "v": "0x0", - "r": "0x0", - "s": "0x0" + "v": "0x26", + "r": "0xe319535da2cae2d72ddb352054535d000c23acdc7cad9d828891253f3850d0d2", + "s": "0x32fe4444149b609e2ffa621e23e179b12028309fdb8cb0a5c1bbc58135299af1" } ], "env": { @@ -41,7 +39,7 @@ "parentBaseFee": "7", "parentGasUsed": "0", "parentGasLimit": "100000000000000000", - "parentTimstamp": "0", + "parentTimestamp": "0", "blockHashes": { "0": "0x651666d6d8727a6478a750dc8406c1bda0be85abc99094dca694807fa772f83c" }, diff --git a/ethereum/evmtool/txs.rlp b/ethereum/evmtool/txs.rlp new file mode 100644 index 00000000000..e9d09685c31 --- /dev/null +++ b/ethereum/evmtool/txs.rlp @@ -0,0 +1 @@ +0xf90620f860800a8307a12094000000000000000000000000000000000000010080801ca0f73b923883495dc2174285c8fa4176de3d45accfb11cc8034ea1dd09831a4ddfa01c6bccbcd655b4022bcc27de4b9d5cee9ce999cdb8459b0afec4f5054ea02243f860010a8307a12094000000000000000000000000000000000000010180801ba0bffca3f433f61c957d822af37f2b49c57700ff338588d51ea82dc9f720c91d9da0168bb65cc72d586384383f8ceef3a6a60e54b7f4aaa978a6dad271ced54b2ebff860020a8307a12094000000000000000000000000000000000000010280801ba03d9f110bcf0c44be552d4d0ec8387b705604f7d3bb3794dcef4004c38963103ea013bda734f3b5987b8c855f6aab046754506266ff32352ba0898c4eba4acaec8bf860030a8307a12094000000000000000000000000000000000000010380801ba0ecb276d2486664ea779813e599b6f07b7b0df746626d7fdddf60ea425efcb324a0739841682e79a8302dc2e146dfd1eecbdc611d386d42287bcdd94a39bf536020f860040a8307a12094000000000000000000000000000000000000010480801ba002866b5c5fa5dbfa3d88b71a49b82a779c2d508cda631893176782dbcd7435aaa003c380a9af9bfdb3503abcfd5037d3c66f39bb7a19011a3291712d22292c5236f860050a8307a12094000000000000000000000000000000000000010580801ca0c70d2e000e503933d0f1a9a923dc647924811a912adf77692ff7d8f6808d5617a04ad82c92b980580a4a67e4c405e83d560a14201c3fd4b3a42d34dcc19336479af860060a8307a12094000000000000000000000000000000000000010680801ca07f2527f8cbe14e021d270dd214a1820355c7af128001889f57b7f9bba46a6c5da03033308de0d39b9d1b47d28f81df39ceaff330349298c65deb836efe8bce273ff860070a8307a12094000000000000000000000000000000000000010780801ba0ecb720a8764f8967b95dc66e961c6261fceb392c0e90461d7d66113d3c8bbd12a02655e28b751cc2e03a835aa817d884b540765dba12968bc53f53737b4234ee21f860080a8307a12094000000000000000000000000000000000000010880801ba095a2e27c0b296679141c0ad61be112f689b134c04d1773814ddae67fefb2dfbda02955f126d57d8b9777f47c520ffe4285890ca2dd1189e67b3407d6369997e7ecf860090a8307a12094000000000000000000000000000000000000010980801ca02468a120d0ee8c57caac354f56842a1db10813169a328f9f852279668b573907a03971f4c2e6bc0aa666812712719199df6fe37c0e1e122131cdb47d6c0c77b371f8600a0a8307a12094000000000000000000000000000000000000010a80801ba0a3a2018ab0bc2695b94bb85d710f4d07132a94f8c3e0f385824da5fee11899a5a00d2dfe430ea5aaff3de8bbb9339e7485474c8e4e34636f787124a7a91e4d6d6af8600b0a8307a12094000000000000000000000000000000000000010b80801ba0b91968fdb3aecea26094ec30649daa4de81a875bcb1a123e732b8f3f112ce232a02ef8cd85969d8bcef5f4ee1f5d20783b8d9b7466726c15ebf911565825187665f8600c0a8307a12094000000000000000000000000000000000000010c80801ca0dd27e75aa990793205805c22265b04be8299b208fad4f37a7f652ecf32b67390a05aa8cda18521548ff8f95e88f49f309d05cab32de28a0942b8a7a824c50df459f8600d0a8307a12094000000000000000000000000000000000000010d80801ba0fad07ce7139dd4e00266194e6a51c048f74eaba3c0a1b03ece378a810abfaa63a04fec880dafaa5382797b4f88b16138b1f0c4e084817072c77ff9bf17ddd4ac26f8600e0a8307a12094000000000000000000000000000000000000010e80801ca0208b22ab245221bdc5cae6586d2ef019a2c37be41166e04b8abe354c41a8f5b6a032d5d6ef07731cd1684531c775c1727ef6ba75de18cda96d998aaa0c1db0bd68f8600f0a8307a12094000000000000000000000000000000000000010f80801ba0055225ffd3d8b2d19c32aa68cb46e7b52c1d99844fb8b7a53b922ea1649e9c5ba06ae2a1e3b9712354b706d0f4da6ea76ed2f8f75277a51a14a3e0ccf25b85c626 \ No newline at end of file diff --git a/ethereum/mock-p2p/build.gradle b/ethereum/mock-p2p/build.gradle index b73c0a051fd..373e25be3cf 100644 --- a/ethereum/mock-p2p/build.gradle +++ b/ethereum/mock-p2p/build.gradle @@ -35,11 +35,8 @@ dependencies { implementation project(':util') implementation 'io.vertx:vertx-core' - implementation 'org.apache.tuweni:tuweni-bytes' + implementation 'io.tmio:tuweni-bytes' - testImplementation 'junit:junit' testImplementation 'org.assertj:assertj-core' testImplementation 'org.junit.jupiter:junit-jupiter' - - testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' } diff --git a/ethereum/mock-p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/testing/MockNetworkTest.java b/ethereum/mock-p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/testing/MockNetworkTest.java index 3596012019e..ff2be0171e7 100644 --- a/ethereum/mock-p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/testing/MockNetworkTest.java +++ b/ethereum/mock-p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/testing/MockNetworkTest.java @@ -33,7 +33,7 @@ import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** Tests for {@link MockNetwork}. */ public final class MockNetworkTest { diff --git a/ethereum/p2p/build.gradle b/ethereum/p2p/build.gradle index 6d36dfd1c74..dccbe0fb877 100644 --- a/ethereum/p2p/build.gradle +++ b/ethereum/p2p/build.gradle @@ -45,24 +45,30 @@ dependencies { implementation 'io.prometheus:simpleclient' implementation 'io.vertx:vertx-core' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-crypto' - implementation('org.apache.tuweni:tuweni-devp2p') { + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-crypto' + implementation('io.tmio:tuweni-devp2p') { exclude group:'ch.qos.logback', module:'logback-classic' } - implementation('org.apache.tuweni:tuweni-dns-discovery'){ + implementation('io.tmio:tuweni-dns-discovery'){ exclude group:'ch.qos.logback', module:'logback-classic' } - implementation 'org.apache.tuweni:tuweni-io' - implementation 'org.apache.tuweni:tuweni-rlp' - implementation 'org.apache.tuweni:tuweni-units' + implementation 'io.tmio:tuweni-io' + implementation 'io.tmio:tuweni-rlp' + implementation 'io.tmio:tuweni-units' implementation 'org.jetbrains.kotlin:kotlin-stdlib' implementation 'org.owasp.encoder:encoder' implementation 'org.xerial.snappy:snappy-java' annotationProcessor "org.immutables:value" implementation "org.immutables:value-annotations" - implementation 'tech.pegasys.discovery:discovery' + implementation('tech.pegasys.discovery:discovery') { + // version conflicts, prefer ours + exclude group: 'org.apache.tuweni', module:'tuweni-bytes' + exclude group: 'org.apache.tuweni', module:'tuweni-crypto' + exclude group: 'org.apache.tuweni', module:'tuweni-rlp' + exclude group: 'org.apache.tuweni', module:'tuweni-units' + } // test dependencies. testImplementation project(path: ':ethereum:core', configuration: 'testArtifacts') @@ -77,11 +83,9 @@ dependencies { } testImplementation 'io.vertx:vertx-codegen' testImplementation 'io.vertx:vertx-unit' - testImplementation 'junit:junit' testImplementation 'org.assertj:assertj-core' testImplementation 'org.awaitility:awaitility' testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.mockito:mockito-core' - - testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' + testImplementation 'org.mockito:mockito-junit-jupiter' } diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/VertxPeerDiscoveryAgent.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/VertxPeerDiscoveryAgent.java index b76d5758cf2..27a2be8beb3 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/VertxPeerDiscoveryAgent.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/VertxPeerDiscoveryAgent.java @@ -53,6 +53,7 @@ import io.vertx.core.datagram.DatagramPacket; import io.vertx.core.datagram.DatagramSocket; import io.vertx.core.datagram.DatagramSocketOptions; +import org.ethereum.beacon.discovery.util.DecodeException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -262,7 +263,7 @@ protected void handleOutgoingPacketError( * @param exception the exception that was raised */ private void handleException(final Throwable exception) { - if (exception instanceof IOException) { + if (exception instanceof IOException || exception instanceof DecodeException) { LOG.debug("Packet handler exception", exception); } else { LOG.error("Packet handler exception", exception); @@ -296,7 +297,8 @@ private void handlePacket(final DatagramPacket datagram) { final Endpoint endpoint = new Endpoint(host, port, Optional.empty()); handleIncomingPacket(endpoint, event.result()); } else { - if (event.cause() instanceof PeerDiscoveryPacketDecodingException) { + if (event.cause() instanceof PeerDiscoveryPacketDecodingException + || event.cause() instanceof DecodeException) { LOG.debug( "Discarding invalid peer discovery packet: {}, {}", event.cause().getMessage(), diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java index 427093cb599..ec65934b297 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java @@ -145,6 +145,7 @@ public class DefaultP2PNetwork implements P2PNetwork { private final AtomicBoolean stopped = new AtomicBoolean(false); private final CountDownLatch shutdownLatch = new CountDownLatch(2); private final Duration shutdownTimeout = Duration.ofSeconds(15); + private final Vertx vertx; private DNSDaemon dnsDaemon; /** @@ -163,6 +164,7 @@ public class DefaultP2PNetwork implements P2PNetwork { * @param maintainedPeers A collection of peers for which we are expected to maintain connections * @param reputationManager An object that inspect disconnections for misbehaving peers that can * then be blacklisted. + * @param vertx the Vert.x instance managing network resources */ DefaultP2PNetwork( final MutableLocalNode localNode, @@ -173,7 +175,8 @@ public class DefaultP2PNetwork implements P2PNetwork { final PeerPermissions peerPermissions, final NatService natService, final MaintainedPeers maintainedPeers, - final PeerDenylistManager reputationManager) { + final PeerDenylistManager reputationManager, + final Vertx vertx) { this.localNode = localNode; this.peerDiscoveryAgent = peerDiscoveryAgent; this.rlpxAgent = rlpxAgent; @@ -183,6 +186,7 @@ public class DefaultP2PNetwork implements P2PNetwork { this.nodeId = nodeKey.getPublicKey().getEncodedBytes(); this.peerPermissions = peerPermissions; + this.vertx = vertx; // set the requirement here that the number of peers be greater than the lower bound final int peerLowerBound = rlpxAgent.getPeerLowerBound(); @@ -229,7 +233,8 @@ public void start() { createDaemonListener(), 0L, 600000L, - config.getDnsDiscoveryServerOverride().orElse(null)); + config.getDnsDiscoveryServerOverride().orElse(null), + vertx); dnsDaemon.start(); }); @@ -535,7 +540,8 @@ private P2PNetwork doBuild() { peerPermissions, natService, maintainedPeers, - reputationManager); + reputationManager, + vertx); } private void validate() { diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/config/DiscoveryConfigurationTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/config/DiscoveryConfigurationTest.java index 305cd9e3763..24d35d33b13 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/config/DiscoveryConfigurationTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/config/DiscoveryConfigurationTest.java @@ -22,7 +22,7 @@ import java.util.Collections; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class DiscoveryConfigurationTest { diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryAgentTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryAgentTest.java index 7c2eb09e2cd..97d167a26fb 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryAgentTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryAgentTest.java @@ -54,7 +54,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.ethereum.beacon.discovery.schema.NodeRecord; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PeerDiscoveryAgentTest { diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryBondingTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryBondingTest.java index 662123e7dcc..898a415d8a3 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryBondingTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryBondingTest.java @@ -29,7 +29,7 @@ import java.util.Optional; import java.util.stream.Collectors; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PeerDiscoveryBondingTest { private final PeerDiscoveryTestHelper helper = new PeerDiscoveryTestHelper(); diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryBootstrappingTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryBootstrappingTest.java index 5fb45e04317..77ef52c8d7b 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryBootstrappingTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryBootstrappingTest.java @@ -30,7 +30,7 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PeerDiscoveryBootstrappingTest { diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryPacketPcapSedesTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryPacketPcapSedesTest.java index 3704eff438d..22ef659b1f8 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryPacketPcapSedesTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryPacketPcapSedesTest.java @@ -33,7 +33,7 @@ import org.apache.tuweni.units.bigints.UInt64; import org.assertj.core.api.Condition; import org.bouncycastle.util.encoders.Hex; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PeerDiscoveryPacketPcapSedesTest { private static final String pingHexData = diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryPacketSedesTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryPacketSedesTest.java index 36773080ae4..e24084348f9 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryPacketSedesTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryPacketSedesTest.java @@ -35,7 +35,7 @@ import io.vertx.core.buffer.Buffer; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.MutableBytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PeerDiscoveryPacketSedesTest { private final PeerDiscoveryTestHelper helper = new PeerDiscoveryTestHelper(); diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryTimestampsTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryTimestampsTest.java index f0f5fc173bd..90ee8b422cd 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryTimestampsTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryTimestampsTest.java @@ -23,7 +23,7 @@ import java.util.Collections; import java.util.concurrent.atomic.AtomicLong; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PeerDiscoveryTimestampsTest { private final PeerDiscoveryTestHelper helper = new PeerDiscoveryTestHelper(); diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/BucketTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/BucketTest.java index c8ce9876910..f2d5f88daeb 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/BucketTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/BucketTest.java @@ -14,9 +14,9 @@ */ package org.hyperledger.besu.ethereum.p2p.discovery.internal; -import static junit.framework.TestCase.assertFalse; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertFalse; import org.hyperledger.besu.ethereum.p2p.discovery.DiscoveryPeer; import org.hyperledger.besu.ethereum.p2p.discovery.PeerDiscoveryTestHelper; @@ -24,7 +24,7 @@ import java.util.List; import java.util.Optional; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class BucketTest { private final PeerDiscoveryTestHelper helper = new PeerDiscoveryTestHelper(); diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/ENRRequestPacketDataTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/ENRRequestPacketDataTest.java index e2892299d98..ef28ce2fd2e 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/ENRRequestPacketDataTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/ENRRequestPacketDataTest.java @@ -22,7 +22,7 @@ import java.time.Instant; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class ENRRequestPacketDataTest { @Test diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/ENRResponsePacketDataTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/ENRResponsePacketDataTest.java index d12a05373c2..72bb407d162 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/ENRResponsePacketDataTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/ENRResponsePacketDataTest.java @@ -26,7 +26,7 @@ import org.ethereum.beacon.discovery.schema.NodeRecord; import org.ethereum.beacon.discovery.schema.NodeRecordFactory; import org.ethereum.beacon.discovery.util.Functions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class ENRResponsePacketDataTest { @Test diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/FindNeighborsPacketDataTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/FindNeighborsPacketDataTest.java index 5183b39a6f9..dc491ad7f15 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/FindNeighborsPacketDataTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/FindNeighborsPacketDataTest.java @@ -23,7 +23,7 @@ import java.time.Instant; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class FindNeighborsPacketDataTest { @Test diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/NeighborsPacketDataTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/NeighborsPacketDataTest.java index ae2cd27d3ef..6dfbbc604e2 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/NeighborsPacketDataTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/NeighborsPacketDataTest.java @@ -26,7 +26,7 @@ import java.util.List; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class NeighborsPacketDataTest { diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PacketTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PacketTest.java index eeef2d4ddb9..fcbebf1c684 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PacketTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PacketTest.java @@ -26,7 +26,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt64; import org.bouncycastle.util.encoders.Hex; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PacketTest { diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PacketTypeTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PacketTypeTest.java index baaff5bfc75..bcf8647214a 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PacketTypeTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PacketTypeTest.java @@ -16,7 +16,7 @@ import static org.assertj.core.api.Assertions.assertThat; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PacketTypeTest { diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryControllerDistanceCalculatorTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryControllerDistanceCalculatorTest.java index f4634c15ea7..a14260f3242 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryControllerDistanceCalculatorTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryControllerDistanceCalculatorTest.java @@ -21,7 +21,7 @@ import java.util.Random; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PeerDiscoveryControllerDistanceCalculatorTest { diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryControllerTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryControllerTest.java index bce73cdc66f..182366ac03a 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryControllerTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryControllerTest.java @@ -78,9 +78,9 @@ import org.ethereum.beacon.discovery.schema.NodeRecord; import org.ethereum.beacon.discovery.schema.NodeRecordFactory; import org.jetbrains.annotations.NotNull; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; public class PeerDiscoveryControllerTest { @@ -103,7 +103,7 @@ private static Long shortDelayFunction(final Long prev) { return Math.max(100, prev * 2); } - @Before + @BeforeEach public void initializeMocks() { final List nodeKeys = PeerDiscoveryTestHelper.generateNodeKeys(1); localNodeKey = nodeKeys.get(0); @@ -111,7 +111,7 @@ public void initializeMocks() { peerTable = new PeerTable(localPeer.getId()); } - @After + @AfterEach public void stopTable() { if (controller != null) { controller.stop().join(); diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryTableRefreshTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryTableRefreshTest.java index d607d4d5023..949b318906b 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryTableRefreshTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryTableRefreshTest.java @@ -41,7 +41,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt64; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; public class PeerDiscoveryTableRefreshTest { diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerRequirementCombineTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerRequirementCombineTest.java index e869b97b4b1..5c7a140dc64 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerRequirementCombineTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerRequirementCombineTest.java @@ -18,17 +18,14 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Stream; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public class PeerRequirementCombineTest { private static final PeerRequirement fulfilled = () -> true; private static final PeerRequirement notFulfilled = () -> false; @@ -36,37 +33,28 @@ public class PeerRequirementCombineTest { private static final AtomicBoolean configurableIsFulfilled = new AtomicBoolean(true); private static final PeerRequirement configurable = configurableIsFulfilled::get; - private final List requirements; - private final boolean expectedResult; - - public PeerRequirementCombineTest( - final List requirements, final boolean expectedResult) { - this.requirements = requirements; - this.expectedResult = expectedResult; + public static Stream data() { + return Stream.of( + new Object[] {Collections.emptyList(), true}, + new Object[] {Arrays.asList(fulfilled), true}, + new Object[] {Arrays.asList(notFulfilled), false}, + new Object[] {Arrays.asList(notFulfilled, notFulfilled), false}, + new Object[] {Arrays.asList(notFulfilled, fulfilled), false}, + new Object[] {Arrays.asList(fulfilled, notFulfilled), false}, + new Object[] {Arrays.asList(fulfilled, fulfilled), true}); } - @Parameters - public static Collection data() { - return Arrays.asList( - new Object[][] { - {Collections.emptyList(), true}, - {Arrays.asList(fulfilled), true}, - {Arrays.asList(notFulfilled), false}, - {Arrays.asList(notFulfilled, notFulfilled), false}, - {Arrays.asList(notFulfilled, fulfilled), false}, - {Arrays.asList(fulfilled, notFulfilled), false}, - {Arrays.asList(fulfilled, fulfilled), true} - }); - } - - @Test - public void combine() { + @ParameterizedTest + @MethodSource("data") + public void combine(final List requirements, final boolean expectedResult) { PeerRequirement combined = PeerRequirement.combine(requirements); assertThat(combined.hasSufficientPeers()).isEqualTo(expectedResult); } - @Test - public void combineAndModify() { + @ParameterizedTest + @MethodSource("data") + public void combineAndModify( + final List requirements, final boolean expectedResult) { List modifiableRequirements = new ArrayList<>(requirements); modifiableRequirements.add(configurable); @@ -82,7 +70,8 @@ public void combineAndModify() { assertThat(combined.hasSufficientPeers()).isEqualTo(expectedResult); } - @Test + @ParameterizedTest + @MethodSource("data") public void combine_withOn() { PeerRequirement combined = PeerRequirement.combine(Collections.emptyList()); assertThat(combined.hasSufficientPeers()).isTrue(); diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerTableTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerTableTest.java index f3283d35f51..c0909a9b8b4 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerTableTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerTableTest.java @@ -33,7 +33,7 @@ import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PeerTableTest { diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PingPacketDataTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PingPacketDataTest.java index 89afd235a35..85c61c1471c 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PingPacketDataTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PingPacketDataTest.java @@ -26,7 +26,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt64; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PingPacketDataTest { diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PongPacketDataTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PongPacketDataTest.java index 0d13604a57d..bf7302eb5c8 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PongPacketDataTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PongPacketDataTest.java @@ -26,7 +26,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt64; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PongPacketDataTest { diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/RecursivePeerRefreshStateTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/RecursivePeerRefreshStateTest.java index 31525ac5b22..e79abb883dd 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/RecursivePeerRefreshStateTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/RecursivePeerRefreshStateTest.java @@ -35,8 +35,8 @@ import java.util.List; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class RecursivePeerRefreshStateTest { private static final Bytes TARGET = createId(0); @@ -62,7 +62,7 @@ public class RecursivePeerRefreshStateTest { 5, 100); - @Before + @BeforeEach public void setup() { // Default peerPermissions to be permissive when(peerPermissions.isAllowedInPeerTable(any())).thenReturn(true); diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetworkTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetworkTest.java index ffc1c84431b..a54c9038b8e 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetworkTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetworkTest.java @@ -58,18 +58,21 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import io.vertx.core.Context; +import io.vertx.core.Vertx; +import io.vertx.core.dns.DnsClient; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.crypto.SECP256K1; import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.StrictStubs.class) +@ExtendWith(MockitoExtension.class) public final class DefaultP2PNetworkTest { final MaintainedPeers maintainedPeers = new MaintainedPeers(); final SECP256K1.SecretKey mockKey = @@ -89,7 +92,7 @@ public final class DefaultP2PNetworkTest { .setBindPort(0) .setSupportedProtocols(MockSubProtocol.create())); - @Before + @BeforeEach public void before() { lenient().when(rlpxAgent.start()).thenReturn(CompletableFuture.completedFuture(30303)); lenient().when(rlpxAgent.stop()).thenReturn(CompletableFuture.completedFuture(null)); @@ -348,8 +351,13 @@ public void shouldStartDnsDiscoveryWhenDnsURLIsConfigured() { final NetworkingConfiguration dnsConfig = when(spy(config).getDiscovery()).thenReturn(disco).getMock(); + Vertx vertx = mock(Vertx.class); + when(vertx.createDnsClient(any())).thenReturn(mock(DnsClient.class)); + when(vertx.getOrCreateContext()).thenReturn(mock(Context.class)); + // spy on DefaultP2PNetwork - final DefaultP2PNetwork testClass = (DefaultP2PNetwork) builder().config(dnsConfig).build(); + final DefaultP2PNetwork testClass = + (DefaultP2PNetwork) builder().vertx(vertx).config(dnsConfig).build(); testClass.start(); assertThat(testClass.getDnsDaemon()).isPresent(); @@ -366,7 +374,12 @@ public void shouldUseDnsServerOverrideIfPresent() { doReturn(disco).when(dnsConfig).getDiscovery(); doReturn(Optional.of("localhost")).when(dnsConfig).getDnsDiscoveryServerOverride(); - final DefaultP2PNetwork testClass = (DefaultP2PNetwork) builder().config(dnsConfig).build(); + Vertx vertx = mock(Vertx.class); + when(vertx.createDnsClient(any())).thenReturn(mock(DnsClient.class)); + when(vertx.getOrCreateContext()).thenReturn(mock(Context.class)); + + final DefaultP2PNetwork testClass = + (DefaultP2PNetwork) builder().config(dnsConfig).vertx(vertx).build(); testClass.start(); // ensure we used the dns server override config when building DNSDaemon: diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/NetworkingServiceLifecycleTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/NetworkingServiceLifecycleTest.java index 97d897c52b3..e0069c0069d 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/NetworkingServiceLifecycleTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/NetworkingServiceLifecycleTest.java @@ -17,9 +17,8 @@ import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.hamcrest.Matchers.startsWith; import static org.hyperledger.besu.ethereum.p2p.NetworkingTestHelper.configWithRandomPorts; -import static org.junit.Assume.assumeThat; +import static org.junit.jupiter.api.Assumptions.assumingThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -44,8 +43,8 @@ import io.vertx.core.Vertx; import org.assertj.core.api.Assertions; import org.jetbrains.annotations.NotNull; -import org.junit.After; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; public class NetworkingServiceLifecycleTest { @@ -53,7 +52,7 @@ public class NetworkingServiceLifecycleTest { private final NodeKey nodeKey = NodeKeyUtils.generate(); private final NetworkingConfiguration config = configWithRandomPorts(); - @After + @AfterEach public void closeVertx() { vertx.close(); } @@ -92,7 +91,7 @@ private DefaultP2PNetwork.Builder getP2PNetworkBuilder() { } @Test - public void createP2PNetwork_NullHost() throws IOException { + public void createP2PNetwork_NullHost() { final NetworkingConfiguration config = NetworkingConfiguration.create() .setDiscovery(DiscoveryConfiguration.create().setBindHost(null)); @@ -107,7 +106,7 @@ public void createP2PNetwork_NullHost() throws IOException { } @Test - public void createP2PNetwork_InvalidHost() throws IOException { + public void createP2PNetwork_InvalidHost() { final NetworkingConfiguration config = NetworkingConfiguration.create() .setDiscovery(DiscoveryConfiguration.create().setBindHost("fake.fake.fake")); @@ -122,7 +121,7 @@ public void createP2PNetwork_InvalidHost() throws IOException { } @Test - public void createP2PNetwork_InvalidPort() throws IOException { + public void createP2PNetwork_InvalidPort() { final NetworkingConfiguration config = NetworkingConfiguration.create() .setDiscovery(DiscoveryConfiguration.create().setBindPort(-1)); @@ -137,7 +136,7 @@ public void createP2PNetwork_InvalidPort() throws IOException { } @Test - public void createP2PNetwork_NullKeyPair() throws IOException { + public void createP2PNetwork_NullKeyPair() { final DefaultP2PNetwork.Builder p2pNetworkBuilder = builder().config(config); assertThatThrownBy(() -> p2pNetworkBuilder.nodeKey(null)) .isInstanceOf(NullPointerException.class); @@ -163,33 +162,33 @@ public void startDiscoveryAgentBackToBack() throws IOException { } @Test - public void startDiscoveryPortInUse() throws IOException { - assumeThat( - "Ignored if system language is not English", - System.getProperty("user.language"), - startsWith("en")); - try (final P2PNetwork service1 = getP2PNetworkBuilder().config(config).build()) { - service1.start(); - final NetworkingConfiguration config = configWithRandomPorts(); - final int usedPort = service1.getLocalEnode().get().getDiscoveryPortOrZero(); - assertThat(usedPort).isNotZero(); - config.getDiscovery().setBindPort(usedPort); - try (final P2PNetwork service2 = getP2PNetworkBuilder().config(config).build()) { - try { - service2.start(); - } catch (final Exception e) { - assertThat(e).hasCauseExactlyInstanceOf(PeerDiscoveryServiceException.class); - assertThat(e) - .hasMessageStartingWith( - "org.hyperledger.besu.ethereum.p2p.discovery." - + "PeerDiscoveryServiceException: Failed to bind Ethereum UDP discovery listener to 0.0.0.0:"); - assertThat(e).hasMessageContaining("Address already in use"); - } finally { - service1.stop(); - service2.stop(); - } - } - } + public void startDiscoveryPortInUse() { + assumingThat( + System.getProperty("user.language").startsWith("en"), + () -> { + try (final P2PNetwork service1 = getP2PNetworkBuilder().config(config).build()) { + service1.start(); + final NetworkingConfiguration config = configWithRandomPorts(); + final int usedPort = service1.getLocalEnode().get().getDiscoveryPortOrZero(); + assertThat(usedPort).isNotZero(); + config.getDiscovery().setBindPort(usedPort); + try (final P2PNetwork service2 = getP2PNetworkBuilder().config(config).build()) { + try { + service2.start(); + } catch (final Exception e) { + assertThat(e).hasCauseExactlyInstanceOf(PeerDiscoveryServiceException.class); + assertThat(e) + .hasMessageStartingWith( + "org.hyperledger.besu.ethereum.p2p.discovery." + + "PeerDiscoveryServiceException: Failed to bind Ethereum UDP discovery listener to 0.0.0.0:"); + assertThat(e).hasMessageContaining("Address already in use"); + } finally { + service1.stop(); + service2.stop(); + } + } + } + }); } @Test diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/P2PNetworkTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/P2PNetworkTest.java index 399f92c3c20..9f95ee4a451 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/P2PNetworkTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/P2PNetworkTest.java @@ -54,12 +54,12 @@ import io.vertx.core.Vertx; import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Assertions; -import org.junit.After; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.StrictStubs.class) +@ExtendWith(MockitoExtension.class) public class P2PNetworkTest { private final Vertx vertx = Vertx.vertx(); private final NetworkingConfiguration config = @@ -70,7 +70,7 @@ public class P2PNetworkTest { .setBindPort(0) .setSupportedProtocols(MockSubProtocol.create())); - @After + @AfterEach public void closeVertx() { vertx.close(); } diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/P2PPlainNetworkTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/P2PPlainNetworkTest.java index fab939e8cb4..32cf99635ff 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/P2PPlainNetworkTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/P2PPlainNetworkTest.java @@ -64,12 +64,12 @@ import io.vertx.core.Vertx; import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Assertions; -import org.junit.After; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.StrictStubs.class) +@ExtendWith(MockitoExtension.class) public class P2PPlainNetworkTest { // See ethereum/p2p/src/test/resources/keys/README.md for certificates setup. private final Vertx vertx = Vertx.vertx(); @@ -81,7 +81,7 @@ public class P2PPlainNetworkTest { .setBindPort(0) .setSupportedProtocols(MockSubProtocol.create())); - @After + @AfterEach public void closeVertx() { vertx.close(); } diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/PeerDenylistManagerTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/PeerDenylistManagerTest.java index 38435d9d53c..db526cfc3f2 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/PeerDenylistManagerTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/PeerDenylistManagerTest.java @@ -29,7 +29,7 @@ import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PeerDenylistManagerTest { private final Peer localNode = generatePeer(); diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/peers/DefaultLocalNodeTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/peers/DefaultLocalNodeTest.java index aaecffda2be..9ff49590a3a 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/peers/DefaultLocalNodeTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/peers/DefaultLocalNodeTest.java @@ -26,7 +26,7 @@ import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class DefaultLocalNodeTest { private final String clientId = "test client"; diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURLImplTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURLImplTest.java index c6ebfe77a48..b7cc2a06327 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURLImplTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURLImplTest.java @@ -31,7 +31,7 @@ import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.ThrowableAssert; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; public class EnodeURLImplTest { diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/peers/MaintainedPeersTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/peers/MaintainedPeersTest.java index 407ec23bf5b..7ddc221f414 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/peers/MaintainedPeersTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/peers/MaintainedPeersTest.java @@ -22,7 +22,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class MaintainedPeersTest { diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/peers/PeerTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/peers/PeerTest.java index 42a61d0936a..14fe3eee1e6 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/peers/PeerTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/peers/PeerTest.java @@ -17,13 +17,14 @@ import static org.apache.tuweni.bytes.Bytes.fromHexString; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertThrows; import org.hyperledger.besu.ethereum.p2p.discovery.DiscoveryPeer; import org.hyperledger.besu.ethereum.p2p.discovery.PeerDiscoveryStatus; import com.google.common.net.InetAddresses; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PeerTest { @@ -112,20 +113,24 @@ public void createFromIpv6URI() { assertThat(peer.getEnodeURL().getDiscoveryPortOrZero()).isEqualTo(30403); } - @Test(expected = IllegalArgumentException.class) + @Test public void createFromURIFailsForWrongScheme() { - DefaultPeer.fromURI("http://user@foo:80"); + assertThrows(IllegalArgumentException.class, () -> DefaultPeer.fromURI("http://user@foo:80")); } - @Test(expected = IllegalArgumentException.class) + @Test public void createFromURIFailsForMissingId() { - DefaultPeer.fromURI("enode://172.20.0.4:30303"); + assertThrows( + IllegalArgumentException.class, () -> DefaultPeer.fromURI("enode://172.20.0.4:30303")); } - @Test(expected = IllegalArgumentException.class) + @Test public void createFromURIFailsForMissingHost() { - DefaultPeer.fromURI( - "enode://c7849b663d12a2b5bf05b1ebf5810364f4870d5f1053fbd7500d38bc54c705b453d7511ca8a4a86003d34d4c8ee0bbfcd387aa724f5b240b3ab4bbb994a1e09b@:30303"); + assertThrows( + IllegalArgumentException.class, + () -> + DefaultPeer.fromURI( + "enode://c7849b663d12a2b5bf05b1ebf5810364f4870d5f1053fbd7500d38bc54c705b453d7511ca8a4a86003d34d4c8ee0bbfcd387aa724f5b240b3ab4bbb994a1e09b@:30303")); } @Test diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/permissions/PeerPermissionsDenylistTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/permissions/PeerPermissionsDenylistTest.java index 34e2e9ac447..2ef2c20a6ca 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/permissions/PeerPermissionsDenylistTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/permissions/PeerPermissionsDenylistTest.java @@ -27,7 +27,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PeerPermissionsDenylistTest { diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/permissions/PeerPermissionsTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/permissions/PeerPermissionsTest.java index 2ef2deffe44..a2f35d57dd5 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/permissions/PeerPermissionsTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/permissions/PeerPermissionsTest.java @@ -28,7 +28,7 @@ import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class PeerPermissionsTest { final Peer localPeer = createPeer(); diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/plain/MessageHandlerTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/plain/MessageHandlerTest.java index d550ddb5ecd..fba1bbdf2f3 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/plain/MessageHandlerTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/plain/MessageHandlerTest.java @@ -18,7 +18,7 @@ import io.netty.buffer.Unpooled; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class MessageHandlerTest { @@ -33,7 +33,7 @@ public class MessageHandlerTest { private static final int DATA_CODE = 1000; @Test - public void buildPingMessage() throws Exception { + public void buildPingMessage() { Bytes message = MessageHandler.buildMessage(MessageType.PING, PING_DATA); assertThat(message).isNotNull(); PlainMessage parsed = MessageHandler.parseMessage(Unpooled.wrappedBuffer(message.toArray())); @@ -43,7 +43,7 @@ public void buildPingMessage() throws Exception { } @Test - public void buildPongMessage() throws Exception { + public void buildPongMessage() { Bytes message = MessageHandler.buildMessage(MessageType.PONG, PONG_DATA); assertThat(message).isNotNull(); PlainMessage parsed = MessageHandler.parseMessage(Unpooled.wrappedBuffer(message.toArray())); @@ -53,7 +53,7 @@ public void buildPongMessage() throws Exception { } @Test - public void buildDataMessage() throws Exception { + public void buildDataMessage() { Bytes message = MessageHandler.buildMessage(MessageType.DATA, DATA_CODE, MESSAGE); assertThat(message).isNotNull(); PlainMessage parsed = MessageHandler.parseMessage(Unpooled.wrappedBuffer(message.toArray())); diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgentTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgentTest.java index 6898ce0fef4..d2fdf8c76a6 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgentTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgentTest.java @@ -64,9 +64,9 @@ import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class RlpxAgentTest { private static final KeyPair KEY_PAIR = SignatureAlgorithmFactory.getInstance().generateKeyPair(); @@ -83,14 +83,14 @@ public class RlpxAgentTest { private final Supplier> allActiveConnectionsSupplier = Stream::empty; private RlpxAgent agent = agent(); - @Before + @BeforeEach public void setup() { // Set basic defaults when(peerPrivileges.canExceedConnectionLimits(any())).thenReturn(false); agent.subscribeConnectRequest((a, b) -> true); } - @After + @AfterEach public void after() { connections = Collections.emptyList(); } diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/AbstractPeerConnectionTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/AbstractPeerConnectionTest.java index 412accc5ef1..b11e4245120 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/AbstractPeerConnectionTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/AbstractPeerConnectionTest.java @@ -40,8 +40,8 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class AbstractPeerConnectionTest { private final String connectionId = "1"; @@ -53,7 +53,7 @@ public class AbstractPeerConnectionTest { private TestPeerConnection connection; - @Before + @BeforeEach public void setUp() { connection = new TestPeerConnection( diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramerTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramerTest.java index 271dbc31dbf..dfafb002f49 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramerTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramerTest.java @@ -72,8 +72,8 @@ import io.netty.handler.codec.DecoderException; import io.netty.util.concurrent.ScheduledFuture; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; public class DeFramerTest { @@ -105,7 +105,7 @@ public class DeFramerTest { private final DeFramer deFramer = createDeFramer(null); - @Before + @BeforeEach @SuppressWarnings("unchecked") public void setup() { when(ctx.channel()).thenReturn(channel); diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/NettyTLSConnectionInitializerTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/NettyTLSConnectionInitializerTest.java index dd5f0080c04..d4637952b63 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/NettyTLSConnectionInitializerTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/NettyTLSConnectionInitializerTest.java @@ -44,13 +44,16 @@ import io.netty.handler.codec.compression.SnappyFrameEncoder; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslHandler; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class NettyTLSConnectionInitializerTest { private static final String PEER_HOST = "hyperledger.org"; @@ -69,7 +72,7 @@ public class NettyTLSConnectionInitializerTest { private NettyTLSConnectionInitializer nettyTLSConnectionInitializer; - @Before + @BeforeEach public void before() throws Exception { nettyTLSConnectionInitializer = createNettyTLSConnectionInitializer(false); diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/TLSContextFactoryTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/TLSContextFactoryTest.java index d89d319b87b..45d228cb40f 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/TLSContextFactoryTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/TLSContextFactoryTest.java @@ -46,9 +46,9 @@ import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslHandler; -import org.junit.Assume; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.condition.DisabledOnOs; import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -225,11 +225,6 @@ private static KeyStoreWrapper getHardwareKeyStoreWrapper( try { return new HardwareKeyStoreWrapper(keystorePassword, toPath(config), toPath(crlLocation)); } catch (final Exception e) { - if (OS.MAC.isCurrentOs()) { - // nss3 is difficult to setup on mac correctly, don't let it break unit tests for dev - // machines. - Assume.assumeNoException("Failed to initialize hardware keystore", e); - } // Not a mac, probably a production build. Full failure. throw new PkiException("Failed to initialize hardware keystore", e); } @@ -253,6 +248,7 @@ private static KeyStoreWrapper getSoftwareKeyStoreWrapper( @ParameterizedTest(name = "{index}: {0}") @MethodSource("softwareKeysData") + @DisabledOnOs(OS.MAC) void testConnectionSoftwareKeys( final String ignoredTestDescription, final boolean testSuccess, @@ -271,6 +267,7 @@ void testConnectionSoftwareKeys( @ParameterizedTest(name = "{index}: {0}") @MethodSource("hardwareKeysData") + @DisabledOnOs(OS.MAC) void testConnectionHardwareKeys( final String ignoredTestDescription, final boolean testSuccess, diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/framing/FramerTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/framing/FramerTest.java index 16ead4fcce0..403a0d48cc9 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/framing/FramerTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/framing/FramerTest.java @@ -39,7 +39,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.xerial.snappy.Snappy; public class FramerTest { diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/framing/SnappyCompressorTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/framing/SnappyCompressorTest.java index 9356efa7af4..235bbaf4161 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/framing/SnappyCompressorTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/framing/SnappyCompressorTest.java @@ -21,7 +21,7 @@ import java.nio.charset.StandardCharsets; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class SnappyCompressorTest { diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/handshake/ecies/ECIESHandshakeTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/handshake/ecies/ECIESHandshakeTest.java index d9edbac9f59..25c10954bef 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/handshake/ecies/ECIESHandshakeTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/handshake/ecies/ECIESHandshakeTest.java @@ -28,10 +28,9 @@ import com.google.common.base.Suppliers; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import junit.framework.AssertionFailedError; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** Test vectors taken from https://gist.github.com/fjl/3a78780d17c755d22df2 */ public class ECIESHandshakeTest { @@ -147,7 +146,7 @@ public void authPlainTextWithEncryption() { final ByteBuf responderRp = responder .handleMessage(initiatorRq) - .orElseThrow(() -> new AssertionFailedError("Expected responder message")); + .orElseThrow(() -> new AssertionError("Expected responder message")); assertThat(responder.getPartyEphPubKey()).isEqualTo(initiator.getEphKeyPair().getPublicKey()); assertThat(responder.getInitiatorNonce()).isEqualTo(initiator.getInitiatorNonce()); assertThat(responder.partyPubKey()).isEqualTo(initiator.getNodeKey().getPublicKey()); diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/handshake/ecies/EncryptedMessageTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/handshake/ecies/EncryptedMessageTest.java index 7be227ab2cd..dbd4e69a9e1 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/handshake/ecies/EncryptedMessageTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/handshake/ecies/EncryptedMessageTest.java @@ -23,7 +23,7 @@ import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Assertions; import org.bouncycastle.crypto.InvalidCipherTextException; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** Tests for {@link EncryptedMessage}. */ public final class EncryptedMessageTest { diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/handshake/ecies/InitiatorHandshakeMessageV4Test.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/handshake/ecies/InitiatorHandshakeMessageV4Test.java index f795fe8aff2..4ab7b1ee4fd 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/handshake/ecies/InitiatorHandshakeMessageV4Test.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/handshake/ecies/InitiatorHandshakeMessageV4Test.java @@ -26,7 +26,7 @@ import com.google.common.io.Resources; import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** Tests for {@link InitiatorHandshakeMessageV4}. */ public final class InitiatorHandshakeMessageV4Test { diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/wire/CapabilityMultiplexerTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/wire/CapabilityMultiplexerTest.java index a4f29156f1e..7597106b473 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/wire/CapabilityMultiplexerTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/wire/CapabilityMultiplexerTest.java @@ -24,7 +24,7 @@ import java.util.Set; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class CapabilityMultiplexerTest { diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/wire/WireMessagesSedesTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/wire/WireMessagesSedesTest.java index 0fb8e353064..e2332e6077a 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/wire/WireMessagesSedesTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/wire/WireMessagesSedesTest.java @@ -21,7 +21,7 @@ import org.hyperledger.besu.ethereum.rlp.RLP; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class WireMessagesSedesTest { diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/wire/messages/DisconnectMessageTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/wire/messages/DisconnectMessageTest.java index 8dbc3bca45a..26a49e00105 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/wire/messages/DisconnectMessageTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/wire/messages/DisconnectMessageTest.java @@ -22,7 +22,7 @@ import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class DisconnectMessageTest { diff --git a/ethereum/permissioning/build.gradle b/ethereum/permissioning/build.gradle index 5b10e216ecf..eaf36c8fda6 100644 --- a/ethereum/permissioning/build.gradle +++ b/ethereum/permissioning/build.gradle @@ -41,9 +41,9 @@ dependencies { implementation 'com.fasterxml.jackson.core:jackson-databind' implementation 'com.google.guava:guava' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-toml' - implementation 'org.apache.tuweni:tuweni-units' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-toml' + implementation 'io.tmio:tuweni-units' implementation 'org.web3j:abi' testImplementation project(':config') @@ -52,10 +52,8 @@ dependencies { testImplementation project(':testutil') testImplementation 'io.vertx:vertx-core' - testImplementation 'junit:junit' testImplementation 'org.assertj:assertj-core' testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.mockito:mockito-core' - - testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' + testImplementation 'org.mockito:mockito-junit-jupiter' } diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/GoQuorumPermissioningConfiguration.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/GoQuorumPermissioningConfiguration.java deleted file mode 100644 index 4e66a6c0723..00000000000 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/GoQuorumPermissioningConfiguration.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.ethereum.permissioning; - -public class GoQuorumPermissioningConfiguration { - - public static final long QIP714_DEFAULT_BLOCK = 0; - - private final long qip714Block; - private final boolean enabled; - - public GoQuorumPermissioningConfiguration(final long qip714Block, final boolean enabled) { - this.qip714Block = qip714Block; - this.enabled = enabled; - } - - public static GoQuorumPermissioningConfiguration enabled(final long qip714Block) { - return new GoQuorumPermissioningConfiguration(qip714Block, true); - } - - public static GoQuorumPermissioningConfiguration disabled() { - return new GoQuorumPermissioningConfiguration(QIP714_DEFAULT_BLOCK, false); - } - - public long getQip714Block() { - return qip714Block; - } - - public boolean isEnabled() { - return enabled; - } -} diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/GoQuorumQip714Gate.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/GoQuorumQip714Gate.java deleted file mode 100644 index 7958cf3b5aa..00000000000 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/GoQuorumQip714Gate.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.ethereum.permissioning; - -import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; -import org.hyperledger.besu.ethereum.chain.Blockchain; - -import java.util.concurrent.atomic.AtomicLong; - -import com.google.common.annotations.VisibleForTesting; - -public class GoQuorumQip714Gate { - - private static GoQuorumQip714Gate SINGLE_INSTANCE = null; - - private final long qip714Block; - private final AtomicLong latestBlock = new AtomicLong(0L); - - @VisibleForTesting - GoQuorumQip714Gate(final long qip714Block, final Blockchain blockchain) { - this.qip714Block = qip714Block; - - blockchain.observeBlockAdded(this::checkChainHeight); - } - - // this is only called during start-up, synchronized access won't hurt performance - public static synchronized GoQuorumQip714Gate getInstance( - final long qip714Block, final Blockchain blockchain) { - if (SINGLE_INSTANCE == null) { - SINGLE_INSTANCE = new GoQuorumQip714Gate(qip714Block, blockchain); - } else { - if (SINGLE_INSTANCE.qip714Block != qip714Block) { - throw new IllegalStateException( - "Tried to create Quorum QIP-714 gate with different block config from already instantiated gate block config"); - } - } - - return SINGLE_INSTANCE; - } - - public boolean shouldCheckPermissions() { - if (qip714Block == 0) { - return true; - } else { - return latestBlock.get() >= qip714Block; - } - } - - @VisibleForTesting - void checkChainHeight(final BlockAddedEvent event) { - if (event.isNewCanonicalHead()) { - latestBlock.set(event.getBlock().getHeader().getNumber()); - } - } - - @VisibleForTesting - long getLatestBlock() { - return latestBlock.get(); - } -} diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodePermissioningControllerFactory.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodePermissioningControllerFactory.java index 7bca3ef8dfb..be1eb703dcf 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodePermissioningControllerFactory.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodePermissioningControllerFactory.java @@ -88,21 +88,8 @@ public NodePermissioningController create( syncStatusProviderOptional = Optional.empty(); } - final Optional goQuorumQip714Gate = - permissioningConfiguration - .getQuorumPermissioningConfig() - .flatMap( - config -> { - if (config.isEnabled()) { - return Optional.of( - GoQuorumQip714Gate.getInstance(config.getQip714Block(), blockchain)); - } else { - return Optional.empty(); - } - }); - final NodePermissioningController nodePermissioningController = - new NodePermissioningController(syncStatusProviderOptional, providers, goQuorumQip714Gate); + new NodePermissioningController(syncStatusProviderOptional, providers); permissioningConfiguration .getSmartContractConfig() @@ -159,7 +146,7 @@ private void validatePermissioningContract( // eliminate the sync status and other checks, so we can just check the smart contract function final NodePermissioningController tempControllerCheckingSmartContractOnly = new NodePermissioningController( - Optional.empty(), nodePermissioningController.getProviders(), Optional.empty()); + Optional.empty(), nodePermissioningController.getProviders()); try { // the enodeURLs don't matter. We just want to check if a call to the smart contract succeeds diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/PermissioningConfiguration.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/PermissioningConfiguration.java index 402239243f6..857060a02ec 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/PermissioningConfiguration.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/PermissioningConfiguration.java @@ -20,15 +20,12 @@ public class PermissioningConfiguration { private final Optional localConfig; private final Optional smartContractConfig; - private final Optional quorumPermissioningConfig; public PermissioningConfiguration( final Optional localConfig, - final Optional smartContractConfig, - final Optional quorumPermissioningConfig) { + final Optional smartContractConfig) { this.localConfig = localConfig; this.smartContractConfig = smartContractConfig; - this.quorumPermissioningConfig = quorumPermissioningConfig; } public Optional getLocalConfig() { @@ -39,11 +36,7 @@ public Optional getSmartContractConfig( return smartContractConfig; } - public Optional getQuorumPermissioningConfig() { - return quorumPermissioningConfig; - } - public static PermissioningConfiguration createDefault() { - return new PermissioningConfiguration(Optional.empty(), Optional.empty(), Optional.empty()); + return new PermissioningConfiguration(Optional.empty(), Optional.empty()); } } diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningController.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningController.java index cc8f3236394..7bd691d024c 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningController.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningController.java @@ -18,7 +18,6 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.permissioning.AccountLocalConfigPermissioningController; -import org.hyperledger.besu.ethereum.permissioning.GoQuorumQip714Gate; import org.hyperledger.besu.ethereum.permissioning.TransactionSmartContractPermissioningController; import java.util.Optional; @@ -35,31 +34,21 @@ public class AccountPermissioningController { accountLocalConfigPermissioningController; private final Optional transactionSmartContractPermissioningController; - private final Optional goQuorumQip714Gate; public AccountPermissioningController( final Optional accountLocalConfigPermissioningController, final Optional - transactionSmartContractPermissioningController, - final Optional goQuorumQip714Gate) { + transactionSmartContractPermissioningController) { this.accountLocalConfigPermissioningController = accountLocalConfigPermissioningController; this.transactionSmartContractPermissioningController = transactionSmartContractPermissioningController; - this.goQuorumQip714Gate = goQuorumQip714Gate; } public boolean isPermitted( final Transaction transaction, final boolean includeLocalCheck, final boolean includeOnchainCheck) { - final boolean checkPermissions = - goQuorumQip714Gate.map(GoQuorumQip714Gate::shouldCheckPermissions).orElse(true); - if (!checkPermissions) { - LOG.trace("Skipping account permissioning check due to qip714block config"); - - return true; - } final Hash transactionHash = transaction.getHash(); final Address sender = transaction.getSender(); diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerFactory.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerFactory.java index bed0a42b8b5..29e513ea5cf 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerFactory.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerFactory.java @@ -18,17 +18,15 @@ import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.permissioning.AccountLocalConfigPermissioningController; -import org.hyperledger.besu.ethereum.permissioning.GoQuorumQip714Gate; import org.hyperledger.besu.ethereum.permissioning.LocalPermissioningConfiguration; import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration; import org.hyperledger.besu.ethereum.permissioning.SmartContractPermissioningConfiguration; import org.hyperledger.besu.ethereum.permissioning.TransactionSmartContractPermissioningController; import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.plugin.services.MetricsSystem; import java.util.Optional; @@ -45,8 +43,7 @@ public class AccountPermissioningControllerFactory { public static Optional create( final PermissioningConfiguration permissioningConfiguration, final TransactionSimulator transactionSimulator, - final MetricsSystem metricsSystem, - final Blockchain blockchain) { + final MetricsSystem metricsSystem) { if (permissioningConfiguration == null) { return Optional.empty(); @@ -64,24 +61,10 @@ public static Optional create( if (accountLocalConfigPermissioningController.isPresent() || transactionSmartContractPermissioningController.isPresent()) { - final Optional goQuorumQip714Gate = - permissioningConfiguration - .getQuorumPermissioningConfig() - .flatMap( - config -> { - if (config.isEnabled()) { - return Optional.of( - GoQuorumQip714Gate.getInstance(config.getQip714Block(), blockchain)); - } else { - return Optional.empty(); - } - }); - final AccountPermissioningController controller = new AccountPermissioningController( accountLocalConfigPermissioningController, - transactionSmartContractPermissioningController, - goQuorumQip714Gate); + transactionSmartContractPermissioningController); return Optional.of(controller); } else { diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/node/NodePermissioningController.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/node/NodePermissioningController.java index 2ca141e54dd..2ccb0e47c28 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/node/NodePermissioningController.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/node/NodePermissioningController.java @@ -14,7 +14,6 @@ */ package org.hyperledger.besu.ethereum.permissioning.node; -import org.hyperledger.besu.ethereum.permissioning.GoQuorumQip714Gate; import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController; import org.hyperledger.besu.ethereum.permissioning.node.provider.SyncStatusNodePermissioningProvider; import org.hyperledger.besu.plugin.data.EnodeURL; @@ -35,26 +34,16 @@ public class NodePermissioningController { private Optional insufficientPeersPermissioningProvider = Optional.empty(); private final List providers; - private final Optional goQuorumQip714Gate; private final Subscribers permissioningUpdateSubscribers = Subscribers.create(); public NodePermissioningController( final Optional syncStatusNodePermissioningProvider, - final List providers, - final Optional goQuorumQip714Gate) { + final List providers) { this.providers = providers; this.syncStatusNodePermissioningProvider = syncStatusNodePermissioningProvider; - this.goQuorumQip714Gate = goQuorumQip714Gate; } public boolean isPermitted(final EnodeURL sourceEnode, final EnodeURL destinationEnode) { - final boolean checkPermissions = - goQuorumQip714Gate.map(GoQuorumQip714Gate::shouldCheckPermissions).orElse(true); - if (!checkPermissions) { - LOG.trace("Skipping node permissioning check due to qip714block config"); - - return true; - } LOG.trace("Node permissioning: Checking {} -> {}", sourceEnode, destinationEnode); diff --git a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/AccountLocalConfigPermissioningControllerTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/AccountLocalConfigPermissioningControllerTest.java index 963d30498ab..1c823b83a83 100644 --- a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/AccountLocalConfigPermissioningControllerTest.java +++ b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/AccountLocalConfigPermissioningControllerTest.java @@ -39,13 +39,13 @@ import java.util.Arrays; import java.util.List; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class AccountLocalConfigPermissioningControllerTest { private AccountLocalConfigPermissioningController controller; @@ -56,7 +56,7 @@ public class AccountLocalConfigPermissioningControllerTest { @Mock private Counter checkPermittedCounter; @Mock private Counter checkUnpermittedCounter; - @Before + @BeforeEach public void before() { when(metricsSystem.createCounter( diff --git a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/AllowlistPersistorTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/AllowlistPersistorTest.java index 25cb91c2aa2..e44fd072790 100644 --- a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/AllowlistPersistorTest.java +++ b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/AllowlistPersistorTest.java @@ -30,9 +30,9 @@ import java.util.stream.Stream; import com.google.common.collect.Lists; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class AllowlistPersistorTest { @@ -43,7 +43,7 @@ public class AllowlistPersistorTest { private final String nodesAllowlist = String.format("%s=[%s]", ALLOWLIST_TYPE.NODES.getTomlKey(), "\"node1\",\"node2\""); - @Before + @BeforeEach public void setUp() throws IOException { List lines = Lists.newArrayList(nodesAllowlist, accountsAllowlist); tempFile = File.createTempFile("test", "test"); @@ -136,7 +136,7 @@ public void compareContentsWhenDifferent_shouldThrow() throws Exception { .isInstanceOf(AllowlistFileSyncException.class); } - @After + @AfterEach public void tearDown() { tempFile.delete(); } diff --git a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/GoQuorumQip714GateTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/GoQuorumQip714GateTest.java deleted file mode 100644 index b280e181b38..00000000000 --- a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/GoQuorumQip714GateTest.java +++ /dev/null @@ -1,109 +0,0 @@ -package org.hyperledger.besu.ethereum.permissioning; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; -import org.hyperledger.besu.ethereum.chain.Blockchain; -import org.hyperledger.besu.ethereum.core.Block; -import org.hyperledger.besu.ethereum.core.BlockDataGenerator; -import org.hyperledger.besu.ethereum.core.BlockDataGenerator.BlockOptions; - -import java.util.Collections; - -import org.junit.Before; -import org.junit.Test; - -/* - * Copyright ConsenSys AG. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -public class GoQuorumQip714GateTest { - - private Blockchain blockchain; - private GoQuorumQip714Gate gate; - - @Before - public void before() { - blockchain = mock(Blockchain.class); - } - - @Test - public void gateShouldSubscribeAsBlockAddedObserver() { - gate = new GoQuorumQip714Gate(100, blockchain); - - verify(blockchain).observeBlockAdded(any()); - } - - @Test - public void whenTargetBlockIsZeroCheckPermissionsReturnTrue() { - gate = new GoQuorumQip714Gate(0, blockchain); - - assertThat(gate.shouldCheckPermissions()).isTrue(); - } - - @Test - public void whenBelowTargetBlockCheckPermissionsReturnFalse() { - gate = new GoQuorumQip714Gate(99, blockchain); - - updateChainHead(55); - - assertThat(gate.shouldCheckPermissions()).isFalse(); - } - - @Test - public void whenAboveTargetBlockCheckPermissionsReturnTrue() { - gate = new GoQuorumQip714Gate(99, blockchain); - - updateChainHead(100); - - assertThat(gate.shouldCheckPermissions()).isTrue(); - } - - @Test - public void latestBlockCheckShouldKeepUpToChainHeight() { - gate = new GoQuorumQip714Gate(0, blockchain); - assertThat(gate.getLatestBlock()).isEqualTo(0); - - updateChainHead(1); - assertThat(gate.getLatestBlock()).isEqualTo(1); - - updateChainHead(3); - assertThat(gate.getLatestBlock()).isEqualTo(3); - - updateChainHead(2); - assertThat(gate.getLatestBlock()).isEqualTo(2); - } - - @Test - public void getInstanceForbidInstancesWithDifferentQip714BlockNumber() { - // creating singleton with qip714block = 1 - GoQuorumQip714Gate.getInstance(1L, blockchain); - - // creating new instance with qip714block != 1 should fail - assertThatThrownBy(() -> GoQuorumQip714Gate.getInstance(2L, blockchain)) - .isInstanceOf(IllegalStateException.class) - .hasMessage( - "Tried to create Quorum QIP-714 gate with different block config from already instantiated gate block config"); - } - - private void updateChainHead(final int height) { - final Block block = new BlockDataGenerator().block(new BlockOptions().setBlockNumber(height)); - gate.checkChainHeight( - BlockAddedEvent.createForHeadAdvancement( - block, Collections.emptyList(), Collections.emptyList())); - } -} diff --git a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfigurationBuilderTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfigurationBuilderTest.java index 9cf9030b1d3..c4e965513a4 100644 --- a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfigurationBuilderTest.java +++ b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfigurationBuilderTest.java @@ -30,7 +30,7 @@ import java.nio.file.Paths; import com.google.common.io.Resources; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class LocalPermissioningConfigurationBuilderTest { diff --git a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfigurationTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfigurationTest.java index 32a1f9cd694..e947d250c8d 100644 --- a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfigurationTest.java +++ b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfigurationTest.java @@ -21,7 +21,7 @@ import java.util.Arrays; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class LocalPermissioningConfigurationTest { diff --git a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/NodeLocalConfigPermissioningControllerTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/NodeLocalConfigPermissioningControllerTest.java index a579f231177..106f9c36100 100644 --- a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/NodeLocalConfigPermissioningControllerTest.java +++ b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/NodeLocalConfigPermissioningControllerTest.java @@ -49,13 +49,13 @@ import java.util.function.Consumer; import com.google.common.collect.Lists; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.StrictStubs.class) +@ExtendWith(MockitoExtension.class) public class NodeLocalConfigPermissioningControllerTest { @Mock private AllowlistPersistor allowlistPersistor; @@ -77,7 +77,7 @@ public class NodeLocalConfigPermissioningControllerTest { @Mock private Counter checkPermittedCounter; @Mock private Counter checkUnpermittedCounter; - @Before + @BeforeEach public void setUp() { bootnodesList.clear(); diff --git a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/NodeSmartContractPermissioningControllerTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/NodeSmartContractPermissioningControllerTest.java index dcfff810ead..788b4b8c01c 100644 --- a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/NodeSmartContractPermissioningControllerTest.java +++ b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/NodeSmartContractPermissioningControllerTest.java @@ -41,12 +41,12 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.io.Resources; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.StrictStubs.class) +@ExtendWith(MockitoExtension.class) public class NodeSmartContractPermissioningControllerTest { @Mock private MetricsSystem metricsSystem; @Mock private Counter checkCounter; diff --git a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/NodeSmartContractV2PermissioningControllerTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/NodeSmartContractV2PermissioningControllerTest.java index 4934dd910c4..d158d807c71 100644 --- a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/NodeSmartContractV2PermissioningControllerTest.java +++ b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/NodeSmartContractV2PermissioningControllerTest.java @@ -42,8 +42,8 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class NodeSmartContractV2PermissioningControllerTest { @@ -77,7 +77,7 @@ Payloads created using Remix to call method connectionAllowed(string, string, ui private NodeSmartContractV2PermissioningController permissioningController; - @Before + @BeforeEach public void beforeEach() { permissioningController = new NodeSmartContractV2PermissioningController( diff --git a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/TransactionSmartContractPermissioningControllerTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/TransactionSmartContractPermissioningControllerTest.java index 6136448ccce..7140ba2fc82 100644 --- a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/TransactionSmartContractPermissioningControllerTest.java +++ b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/TransactionSmartContractPermissioningControllerTest.java @@ -26,6 +26,7 @@ import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.chain.GenesisState; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; @@ -35,7 +36,6 @@ import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.metrics.BesuMetricCategory; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.metrics.Counter; @@ -44,12 +44,12 @@ import com.google.common.io.Resources; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.StrictStubs.class) +@ExtendWith(MockitoExtension.class) public class TransactionSmartContractPermissioningControllerTest { @Mock private MetricsSystem metricsSystem; @Mock private Counter checkCounter; diff --git a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerFactoryTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerFactoryTest.java index 2c19f3cd37b..6e76725fb7a 100644 --- a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerFactoryTest.java +++ b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerFactoryTest.java @@ -21,7 +21,6 @@ import static org.mockito.Mockito.when; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.permissioning.LocalPermissioningConfiguration; import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration; import org.hyperledger.besu.ethereum.permissioning.SmartContractPermissioningConfiguration; @@ -35,24 +34,22 @@ import java.util.Optional; import org.assertj.core.api.Assertions; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class AccountPermissioningControllerFactoryTest { @Mock private TransactionSimulator transactionSimulator; - @Mock private Blockchain blockchain; private final MetricsSystem metricsSystem = new NoOpMetricsSystem(); @Test public void createWithNullPermissioningConfigShouldReturnEmpty() { Optional controller = - AccountPermissioningControllerFactory.create( - null, transactionSimulator, metricsSystem, blockchain); + AccountPermissioningControllerFactory.create(null, transactionSimulator, metricsSystem); Assertions.assertThat(controller).isEmpty(); } @@ -63,12 +60,11 @@ public void createLocalConfigWithAccountPermissioningDisabledShouldReturnEmpty() assertThat(localConfig.isAccountAllowlistEnabled()).isFalse(); PermissioningConfiguration permissioningConfiguration = - new PermissioningConfiguration( - Optional.of(localConfig), Optional.empty(), Optional.empty()); + new PermissioningConfiguration(Optional.of(localConfig), Optional.empty()); Optional controller = AccountPermissioningControllerFactory.create( - permissioningConfiguration, transactionSimulator, metricsSystem, blockchain); + permissioningConfiguration, transactionSimulator, metricsSystem); Assertions.assertThat(controller).isEmpty(); } @@ -79,12 +75,11 @@ public void createLocalConfigOnlyControllerShouldReturnExpectedController() { assertThat(localConfig.isAccountAllowlistEnabled()).isTrue(); PermissioningConfiguration permissioningConfiguration = - new PermissioningConfiguration( - Optional.of(localConfig), Optional.empty(), Optional.empty()); + new PermissioningConfiguration(Optional.of(localConfig), Optional.empty()); Optional controller = AccountPermissioningControllerFactory.create( - permissioningConfiguration, transactionSimulator, metricsSystem, blockchain); + permissioningConfiguration, transactionSimulator, metricsSystem); Assertions.assertThat(controller).isNotEmpty(); assertThat(controller.get().getAccountLocalConfigPermissioningController()).isNotEmpty(); @@ -98,12 +93,11 @@ public void createOnchainConfigWithAccountPermissioningDisabledShouldReturnEmpty assertThat(onchainConfig.isSmartContractAccountAllowlistEnabled()).isFalse(); PermissioningConfiguration permissioningConfiguration = - new PermissioningConfiguration( - Optional.empty(), Optional.of(onchainConfig), Optional.empty()); + new PermissioningConfiguration(Optional.empty(), Optional.of(onchainConfig)); Optional controller = AccountPermissioningControllerFactory.create( - permissioningConfiguration, transactionSimulator, metricsSystem, blockchain); + permissioningConfiguration, transactionSimulator, metricsSystem); Assertions.assertThat(controller).isEmpty(); } @@ -114,12 +108,11 @@ public void createOnchainConfigOnlyControllerShouldReturnExpectedController() { assertThat(onchainConfig.isSmartContractAccountAllowlistEnabled()).isTrue(); PermissioningConfiguration permissioningConfiguration = - new PermissioningConfiguration( - Optional.empty(), Optional.of(onchainConfig), Optional.empty()); + new PermissioningConfiguration(Optional.empty(), Optional.of(onchainConfig)); Optional controller = AccountPermissioningControllerFactory.create( - permissioningConfiguration, transactionSimulator, metricsSystem, blockchain); + permissioningConfiguration, transactionSimulator, metricsSystem); Assertions.assertThat(controller).isNotEmpty(); assertThat(controller.get().getAccountLocalConfigPermissioningController()).isEmpty(); @@ -132,8 +125,7 @@ public void createOnchainShouldFailIfValidationFails() { assertThat(onchainConfig.isSmartContractAccountAllowlistEnabled()).isTrue(); PermissioningConfiguration permissioningConfiguration = - new PermissioningConfiguration( - Optional.empty(), Optional.of(onchainConfig), Optional.empty()); + new PermissioningConfiguration(Optional.empty(), Optional.of(onchainConfig)); when(transactionSimulator.processAtHead(any())).thenThrow(new RuntimeException()); @@ -141,7 +133,7 @@ public void createOnchainShouldFailIfValidationFails() { catchThrowable( () -> AccountPermissioningControllerFactory.create( - permissioningConfiguration, transactionSimulator, metricsSystem, blockchain)); + permissioningConfiguration, transactionSimulator, metricsSystem)); assertThat(thrown) .isInstanceOf(IllegalStateException.class) @@ -157,12 +149,11 @@ public void createLocalAndOnchainControllerShouldReturnExpectedControllers() { assertThat(onchainConfig.isSmartContractAccountAllowlistEnabled()).isTrue(); PermissioningConfiguration permissioningConfiguration = - new PermissioningConfiguration( - Optional.of(localConfig), Optional.of(onchainConfig), Optional.empty()); + new PermissioningConfiguration(Optional.of(localConfig), Optional.of(onchainConfig)); Optional controller = AccountPermissioningControllerFactory.create( - permissioningConfiguration, transactionSimulator, metricsSystem, blockchain); + permissioningConfiguration, transactionSimulator, metricsSystem); Assertions.assertThat(controller).isNotEmpty(); assertThat(controller.get().getAccountLocalConfigPermissioningController()).isNotEmpty(); diff --git a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerTest.java index b125138a18b..4e2e7b5e869 100644 --- a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerTest.java +++ b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerTest.java @@ -23,33 +23,29 @@ import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.permissioning.AccountLocalConfigPermissioningController; -import org.hyperledger.besu.ethereum.permissioning.GoQuorumQip714Gate; import org.hyperledger.besu.ethereum.permissioning.TransactionSmartContractPermissioningController; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class AccountPermissioningControllerTest { private AccountPermissioningController permissioningController; @Mock private AccountLocalConfigPermissioningController localConfigController; @Mock private TransactionSmartContractPermissioningController smartContractController; - @Mock private GoQuorumQip714Gate goQuorumQip714Gate; - @Before + @BeforeEach public void before() { permissioningController = new AccountPermissioningController( - Optional.of(localConfigController), - Optional.of(smartContractController), - Optional.empty()); + Optional.of(localConfigController), Optional.of(smartContractController)); } @Test @@ -89,49 +85,4 @@ public void shouldReturnFalseIfOneControllerPermitsAndTheOtherDoesNot() { verify(localConfigController).isPermitted(any()); verify(smartContractController).isPermitted(any()); } - - @Test - public void whenQuorumQip714GateIsEmptyShouldDelegateToProviders() { - this.permissioningController = - new AccountPermissioningController( - Optional.of(localConfigController), - Optional.of(smartContractController), - Optional.empty()); - - permissioningController.isPermitted(mock(Transaction.class), true, false); - - verify(localConfigController).isPermitted(any()); - } - - @Test - public void whenQuorumQip714GateIsNotActiveShouldBypassProviders() { - this.permissioningController = - new AccountPermissioningController( - Optional.of(localConfigController), - Optional.of(smartContractController), - Optional.of(goQuorumQip714Gate)); - - when(goQuorumQip714Gate.shouldCheckPermissions()).thenReturn(false); - - boolean isPermitted = permissioningController.isPermitted(mock(Transaction.class), true, false); - assertThat(isPermitted).isTrue(); - - verifyNoInteractions(localConfigController); - verifyNoInteractions(smartContractController); - } - - @Test - public void whenQuorumQip714GateIsActiveActiveShouldDelegateToProviders() { - this.permissioningController = - new AccountPermissioningController( - Optional.of(localConfigController), - Optional.of(smartContractController), - Optional.of(goQuorumQip714Gate)); - - when(goQuorumQip714Gate.shouldCheckPermissions()).thenReturn(true); - - permissioningController.isPermitted(mock(Transaction.class), true, false); - - verify(localConfigController).isPermitted(any()); - } } diff --git a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/InsufficientPeersPermissioningProviderTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/InsufficientPeersPermissioningProviderTest.java index fc0be831506..3c2f6e99da2 100644 --- a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/InsufficientPeersPermissioningProviderTest.java +++ b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/InsufficientPeersPermissioningProviderTest.java @@ -32,14 +32,17 @@ import java.util.Collections; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class InsufficientPeersPermissioningProviderTest { @Mock private P2PNetwork p2pNetwork; private final EnodeURL SELF_ENODE = @@ -58,7 +61,7 @@ public class InsufficientPeersPermissioningProviderTest { EnodeURLImpl.fromString( "enode://00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005@192.168.0.5:30303"); - @Before + @BeforeEach public void setup() { when(p2pNetwork.getLocalEnode()).thenReturn(Optional.of(SELF_ENODE)); } diff --git a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/NodePermissioningControllerFactoryTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/NodePermissioningControllerFactoryTest.java index a313c4a60ed..b6b310ea324 100644 --- a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/NodePermissioningControllerFactoryTest.java +++ b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/NodePermissioningControllerFactoryTest.java @@ -39,13 +39,16 @@ import java.util.List; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) public class NodePermissioningControllerFactoryTest { @Mock private Synchronizer synchronizer; @@ -60,14 +63,14 @@ public class NodePermissioningControllerFactoryTest { SmartContractPermissioningConfiguration smartContractPermissioningConfiguration; PermissioningConfiguration config; - @Before + @BeforeEach public void before() { when(transactionSimulator.doesAddressExistAtHead(any())).thenReturn(Optional.of(true)); } @Test public void testCreateWithNeitherPermissioningEnabled() { - config = new PermissioningConfiguration(Optional.empty(), Optional.empty(), Optional.empty()); + config = new PermissioningConfiguration(Optional.empty(), Optional.empty()); NodePermissioningControllerFactory factory = new NodePermissioningControllerFactory(); NodePermissioningController controller = factory.create( @@ -93,9 +96,7 @@ public void testCreateWithSmartContractNodePermissioningEnabledOnly() { smartContractPermissioningConfiguration.setSmartContractNodeAllowlistEnabled(true); config = new PermissioningConfiguration( - Optional.empty(), - Optional.of(smartContractPermissioningConfiguration), - Optional.empty()); + Optional.empty(), Optional.of(smartContractPermissioningConfiguration)); NodePermissioningControllerFactory factory = new NodePermissioningControllerFactory(); NodePermissioningController controller = @@ -123,8 +124,7 @@ public void testCreateWithLocalNodePermissioningEnabledOnly() { localPermissioningConfig.setNodeAllowlist(Collections.emptyList()); localPermissioningConfig.setNodePermissioningConfigFilePath("fake-file-path"); config = - new PermissioningConfiguration( - Optional.of(localPermissioningConfig), Optional.empty(), Optional.empty()); + new PermissioningConfiguration(Optional.of(localPermissioningConfig), Optional.empty()); NodePermissioningControllerFactory factory = new NodePermissioningControllerFactory(); NodePermissioningController controller = @@ -160,8 +160,7 @@ public void testCreateWithLocalNodePermissioningEnabledOnly() { config = new PermissioningConfiguration( Optional.of(localPermissioningConfig), - Optional.of(smartContractPermissioningConfiguration), - Optional.empty()); + Optional.of(smartContractPermissioningConfiguration)); NodePermissioningControllerFactory factory = new NodePermissioningControllerFactory(); NodePermissioningController controller = @@ -196,8 +195,7 @@ public void testCreateWithLocalNodeAndSmartContractPermissioningEnabled() { config = new PermissioningConfiguration( Optional.of(localPermissioningConfig), - Optional.of(smartContractPermissioningConfiguration), - Optional.empty()); + Optional.of(smartContractPermissioningConfiguration)); NodePermissioningControllerFactory factory = new NodePermissioningControllerFactory(); NodePermissioningController controller = @@ -235,9 +233,7 @@ public void testCreateWithSmartContractNodePermissioningEnabledOnlyAndBootnode() smartContractPermissioningConfiguration.setSmartContractNodeAllowlistEnabled(true); config = new PermissioningConfiguration( - Optional.empty(), - Optional.of(smartContractPermissioningConfiguration), - Optional.empty()); + Optional.empty(), Optional.of(smartContractPermissioningConfiguration)); NodePermissioningControllerFactory factory = new NodePermissioningControllerFactory(); NodePermissioningController controller = @@ -262,9 +258,7 @@ public void createOnchainShouldFailIfValidationFails() { smartContractPermissioningConfiguration.setSmartContractNodeAllowlistEnabled(true); config = new PermissioningConfiguration( - Optional.empty(), - Optional.of(smartContractPermissioningConfiguration), - Optional.empty()); + Optional.empty(), Optional.of(smartContractPermissioningConfiguration)); when(transactionSimulator.processAtHead(any())).thenThrow(new RuntimeException()); diff --git a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/NodePermissioningControllerTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/NodePermissioningControllerTest.java index 77743814d9b..35062f71694 100644 --- a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/NodePermissioningControllerTest.java +++ b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/NodePermissioningControllerTest.java @@ -21,28 +21,25 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl; -import org.hyperledger.besu.ethereum.permissioning.GoQuorumQip714Gate; import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController; import org.hyperledger.besu.ethereum.permissioning.node.provider.SyncStatusNodePermissioningProvider; import org.hyperledger.besu.plugin.data.EnodeURL; import org.hyperledger.besu.plugin.services.permissioning.NodeConnectionPermissioningProvider; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class NodePermissioningControllerTest { private static final EnodeURL enode1 = @@ -56,17 +53,16 @@ public class NodePermissioningControllerTest { Optional syncStatusNodePermissioningProviderOptional; @Mock private NodeLocalConfigPermissioningController localConfigNodePermissioningProvider; @Mock private NodeConnectionPermissioningProvider otherPermissioningProvider; - @Mock private GoQuorumQip714Gate goQuorumQip714Gate; private NodePermissioningController controller; - @Before + @BeforeEach public void before() { syncStatusNodePermissioningProviderOptional = Optional.of(syncStatusNodePermissioningProvider); List emptyProviders = new ArrayList<>(); this.controller = new NodePermissioningController( - syncStatusNodePermissioningProviderOptional, emptyProviders, Optional.empty()); + syncStatusNodePermissioningProviderOptional, emptyProviders); } @Test @@ -81,8 +77,7 @@ public void isPermittedShouldDelegateToSyncStatusProvider() { public void whenNoSyncStatusProviderWeShouldDelegateToLocalConfigNodePermissioningProvider() { List providers = new ArrayList<>(); providers.add(localConfigNodePermissioningProvider); - this.controller = - new NodePermissioningController(Optional.empty(), providers, Optional.empty()); + this.controller = new NodePermissioningController(Optional.empty(), providers); controller.isPermitted(enode1, enode2); @@ -94,8 +89,7 @@ public void whenNoSyncStatusProviderWeShouldDelegateToLocalConfigNodePermissioni whenInSyncWeShouldDelegateToAnyOtherNodePermissioningProviderAndIsPermittedIfAllPermitted() { List providers = getNodePermissioningProviders(); this.controller = - new NodePermissioningController( - syncStatusNodePermissioningProviderOptional, providers, Optional.empty()); + new NodePermissioningController(syncStatusNodePermissioningProviderOptional, providers); when(syncStatusNodePermissioningProvider.isConnectionPermitted(eq(enode1), eq(enode2))) .thenReturn(true); @@ -124,8 +118,7 @@ private List getNodePermissioningProviders( List providers = getNodePermissioningProviders(); this.controller = - new NodePermissioningController( - syncStatusNodePermissioningProviderOptional, providers, Optional.empty()); + new NodePermissioningController(syncStatusNodePermissioningProviderOptional, providers); when(syncStatusNodePermissioningProvider.isConnectionPermitted(eq(enode1), eq(enode2))) .thenReturn(true); @@ -147,8 +140,7 @@ public void shouldStopAtInsufficientPeersWhenInsufficientAndBootnode() { final List providers = getNodePermissioningProviders(); this.controller = - new NodePermissioningController( - syncStatusNodePermissioningProviderOptional, providers, Optional.empty()); + new NodePermissioningController(syncStatusNodePermissioningProviderOptional, providers); final ContextualNodePermissioningProvider insufficientPeersPermissioningProvider = mock(ContextualNodePermissioningProvider.class); @@ -170,8 +162,7 @@ public void doesntStopAtInsufficientPeersWhenNoAnswer() { final List providers = getNodePermissioningProviders(); this.controller = - new NodePermissioningController( - syncStatusNodePermissioningProviderOptional, providers, Optional.empty()); + new NodePermissioningController(syncStatusNodePermissioningProviderOptional, providers); final ContextualNodePermissioningProvider insufficientPeersPermissioningProvider = mock(ContextualNodePermissioningProvider.class); @@ -191,47 +182,4 @@ public void doesntStopAtInsufficientPeersWhenNoAnswer() { verify(insufficientPeersPermissioningProvider, times(1)).isPermitted(any(), any()); providers.forEach(p -> verify(p, times(1)).isConnectionPermitted(any(), any())); } - - @Test - public void whenQuorumQip714GateIsEmptyShouldDelegateToProviders() { - this.controller = - new NodePermissioningController( - syncStatusNodePermissioningProviderOptional, Collections.emptyList(), Optional.empty()); - - controller.isPermitted(enode1, enode2); - - verify(syncStatusNodePermissioningProvider, atLeast(1)) - .isConnectionPermitted(eq(enode1), eq(enode2)); - } - - @Test - public void whenQuorumQip714GateIsNotActiveShouldBypassProviders() { - this.controller = - new NodePermissioningController( - syncStatusNodePermissioningProviderOptional, - Collections.emptyList(), - Optional.of(goQuorumQip714Gate)); - - when(goQuorumQip714Gate.shouldCheckPermissions()).thenReturn(false); - - assertThat(controller.isPermitted(enode1, enode2)).isTrue(); - - verifyNoInteractions(syncStatusNodePermissioningProvider); - } - - @Test - public void whenQuorumQip714GateIsActiveShouldDelegateToProviders() { - this.controller = - new NodePermissioningController( - syncStatusNodePermissioningProviderOptional, - Collections.emptyList(), - Optional.of(goQuorumQip714Gate)); - - when(goQuorumQip714Gate.shouldCheckPermissions()).thenReturn(true); - - controller.isPermitted(enode1, enode2); - - verify(syncStatusNodePermissioningProvider, atLeast(1)) - .isConnectionPermitted(eq(enode1), eq(enode2)); - } } diff --git a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/PeerPermissionsAdapterTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/PeerPermissionsAdapterTest.java index 90d434f0163..c1312754394 100644 --- a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/PeerPermissionsAdapterTest.java +++ b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/PeerPermissionsAdapterTest.java @@ -34,7 +34,7 @@ import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatchers; public class PeerPermissionsAdapterTest { diff --git a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/provider/SyncStatusNodePermissioningProviderTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/provider/SyncStatusNodePermissioningProviderTest.java index a261fb18ab0..a41bf3e405e 100644 --- a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/provider/SyncStatusNodePermissioningProviderTest.java +++ b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/provider/SyncStatusNodePermissioningProviderTest.java @@ -37,14 +37,14 @@ import java.util.function.IntSupplier; import com.google.common.collect.Lists; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class SyncStatusNodePermissioningProviderTest { @Mock private MetricsSystem metricsSystem; @Mock private Counter checkCounter; @@ -67,7 +67,7 @@ public class SyncStatusNodePermissioningProviderTest { private SyncStatusNodePermissioningProvider provider; private InSyncListener inSyncListener; - @Before + @BeforeEach public void before() { final ArgumentCaptor inSyncSubscriberCaptor = ArgumentCaptor.forClass(InSyncListener.class); diff --git a/ethereum/referencetests/build.gradle b/ethereum/referencetests/build.gradle index 49dc6109074..2be5393103a 100644 --- a/ethereum/referencetests/build.gradle +++ b/ethereum/referencetests/build.gradle @@ -138,8 +138,8 @@ dependencies { referenceTestImplementation 'ethereum:execution-spec-tests:0.2.3:fixtures@tar.gz' referenceTestImplementation 'com.fasterxml.jackson.core:jackson-databind' referenceTestImplementation 'com.google.guava:guava' - referenceTestImplementation 'org.apache.tuweni:tuweni-bytes' - referenceTestImplementation 'org.apache.tuweni:tuweni-units' + referenceTestImplementation 'io.tmio:tuweni-bytes' + referenceTestImplementation 'io.tmio:tuweni-units' referenceTestImplementation 'org.assertj:assertj-core' referenceTestImplementation 'org.junit.jupiter:junit-jupiter-api' referenceTestImplementation 'org.junit.jupiter:junit-jupiter-params' @@ -163,7 +163,7 @@ tasks.register('validateReferenceTestSubmodule') { description = "Checks that the reference tests submodule is not accidentally changed" doLast { def result = new ByteArrayOutputStream() - def expectedHash = '04f338a6e673a6b4d906ec9d6d2bc939309357a5' + def expectedHash = '06e276776bc87817c38f6efb492bf6f4527fa904' def submodulePath = java.nio.file.Path.of("${rootProject.projectDir}", "ethereum/referencetests/src/reference-test/external-resources").toAbsolutePath() try { exec { @@ -189,9 +189,10 @@ Full git output : ${result} If this is accidental you can correct the reference test versions with the following commands: pushd ${submodulePath} + git fetch git checkout ${expectedHash} cd .. - git add resources + git add ${submodulePath} popd""") } } diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BlockchainReferenceTestCaseSpec.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BlockchainReferenceTestCaseSpec.java index 0cdb6854853..d48355e12d7 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BlockchainReferenceTestCaseSpec.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BlockchainReferenceTestCaseSpec.java @@ -18,7 +18,7 @@ import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryWorldStateArchive; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.DataGas; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; @@ -164,7 +164,10 @@ public ReferenceTestBlockHeader( @JsonProperty("nonce") final String nonce, @JsonProperty("withdrawalsRoot") final String withdrawalsRoot, @JsonProperty("depositsRoot") final String depositsRoot, + @JsonProperty("dataGasUsed") final String dataGasUsed, @JsonProperty("excessDataGas") final String excessDataGas, + @JsonProperty("blobGasUsed") final String blobGasUsed, + @JsonProperty("excessBlobGas") final String excessBlobGas, @JsonProperty("hash") final String hash) { super( Hash.fromHexString(parentHash), // parentHash @@ -188,7 +191,12 @@ public ReferenceTestBlockHeader( Hash.fromHexString(mixHash), // mixHash Bytes.fromHexStringLenient(nonce).toLong(), withdrawalsRoot != null ? Hash.fromHexString(withdrawalsRoot) : null, - excessDataGas != null ? DataGas.fromHexString(excessDataGas) : null, + dataGasUsed != null + ? Long.decode(dataGasUsed) + : blobGasUsed != null ? Long.decode(blobGasUsed) : 0, + excessDataGas != null + ? BlobGas.fromHexString(excessDataGas) + : excessBlobGas != null ? BlobGas.fromHexString(excessBlobGas) : null, depositsRoot != null ? Hash.fromHexString(depositsRoot) : null, new BlockHeaderFunctions() { @Override @@ -205,6 +213,10 @@ public ParsedExtraData parseExtraData(final BlockHeader header) { } @JsonIgnoreProperties({ + "blocknumber", + "chainname", + "chainnetwork", + "expectException", "expectExceptionByzantium", "expectExceptionConstantinople", "expectExceptionConstantinopleFix", @@ -213,11 +225,8 @@ public ParsedExtraData parseExtraData(final BlockHeader header) { "expectExceptionEIP158", "expectExceptionFrontier", "expectExceptionHomestead", - "expectException", - "blocknumber", - "chainname", "expectExceptionALL", - "chainnetwork", + "hasBigInt", "transactionSequence" }) public static class CandidateBlock { diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestEnv.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestEnv.java index 7898960c384..7f8dfb1e76f 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestEnv.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestEnv.java @@ -19,6 +19,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.GWei; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; @@ -39,7 +40,6 @@ import java.util.stream.Collectors; import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.base.Strings; import org.apache.tuweni.bytes.Bytes; @@ -47,7 +47,6 @@ import org.apache.tuweni.units.bigints.UInt64; /** A memory holder for testing. */ -@JsonIgnoreProperties(ignoreUnknown = true) public class ReferenceTestEnv extends BlockHeader { public record EnvWithdrawal( @@ -79,6 +78,12 @@ Withdrawal asWithdrawal() { private final Map blockHashes; + private final String parentExcessBlobGas; + + private final String parentBlobGasUsed; + + private final Hash beaconRoot; + /** * Public constructor. * @@ -105,8 +110,15 @@ public ReferenceTestEnv( @JsonProperty("parentGasUsed") final String parentGasUsed, @JsonProperty("parentGasLimit") final String parentGasLimit, @JsonProperty("parentTimestamp") final String parentTimestamp, + @JsonProperty("ommers") final List _ommers, + @JsonProperty("parentUncleHash") final String _parentUncleHash, @JsonProperty("withdrawals") final List withdrawals, - @JsonProperty("blockHashes") final Map blockHashes) { + @JsonProperty("blockHashes") final Map blockHashes, + @JsonProperty("currentExcessBlobGas") final String currentExcessBlobGas, + @JsonProperty("currentBlobGasUsed") final String currentBlobGasUsed, + @JsonProperty("parentExcessBlobGas") final String parentExcessBlobGas, + @JsonProperty("parentBlobGasUsed") final String parentBlobGasUsed, + @JsonProperty("beaconRoot") final String beaconRoot) { super( generateTestBlockHash(previousHash, number), Hash.EMPTY_LIST_HASH, // ommersHash @@ -125,14 +137,17 @@ public ReferenceTestEnv( Optional.ofNullable(random).map(Difficulty::fromHexString).orElse(Difficulty.ZERO), 0L, null, // withdrawalsRoot + currentBlobGasUsed == null ? null : Long.decode(currentBlobGasUsed), + currentExcessBlobGas == null ? null : BlobGas.fromHexString(currentExcessBlobGas), null, // depositsRoot - null, new MainnetBlockHeaderFunctions()); this.parentDifficulty = parentDifficulty; this.parentBaseFee = parentBaseFee; this.parentGasUsed = parentGasUsed; this.parentGasLimit = parentGasLimit; this.parentTimestamp = parentTimestamp; + this.parentExcessBlobGas = parentExcessBlobGas; + this.parentBlobGasUsed = parentBlobGasUsed; this.withdrawals = withdrawals == null ? List.of() @@ -146,6 +161,7 @@ public ReferenceTestEnv( Map.entry( Long.decode(entry.getKey()), Hash.fromHexString(entry.getValue()))) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + this.beaconRoot = beaconRoot == null ? null : Hash.fromHexString(beaconRoot); } @Override @@ -195,6 +211,14 @@ public BlockHeader updateFromParentValues(final ProtocolSpec protocolSpec) { .buildBlockHeader(), null))); } + if (excessBlobGas.isEmpty() && parentExcessBlobGas != null && parentBlobGasUsed != null) { + builder.excessBlobGas( + BlobGas.of( + protocolSpec + .getGasCalculator() + .computeExcessBlobGas( + Long.decode(parentExcessBlobGas), Long.decode(parentGasUsed)))); + } return builder.buildBlockHeader(); } @@ -217,7 +241,10 @@ public boolean equals(final Object o) { && Objects.equals(parentGasUsed, that.parentGasUsed) && Objects.equals(parentGasLimit, that.parentGasLimit) && Objects.equals(parentTimestamp, that.parentTimestamp) - && Objects.equals(withdrawals, that.withdrawals); + && Objects.equals(parentBlobGasUsed, that.parentBlobGasUsed) + && Objects.equals(parentExcessBlobGas, that.parentExcessBlobGas) + && Objects.equals(withdrawals, that.withdrawals) + && Objects.equals(beaconRoot, that.beaconRoot); } @Override @@ -229,6 +256,9 @@ public int hashCode() { parentGasUsed, parentGasLimit, parentTimestamp, - withdrawals); + parentBlobGasUsed, + parentExcessBlobGas, + withdrawals, + beaconRoot); } } diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java index 0ec30b0959f..3c5d84567ae 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java @@ -74,7 +74,12 @@ public static ReferenceTestProtocolSchedules create(final StubGenesisConfigOptio builder.put("GrayGlacier", createSchedule(genesisStub.clone().grayGlacierBlock(0))); builder.put("Merge", createSchedule(genesisStub.clone().mergeNetSplitBlock(0))); builder.put("Shanghai", createSchedule(genesisStub.clone().shanghaiTime(0))); + builder.put( + "ShanghaiToCancunAtTime15k", + createSchedule(genesisStub.clone().shanghaiTime(0).cancunTime(15000))); builder.put("Cancun", createSchedule(genesisStub.clone().cancunTime(0))); + // TODO remove this after execution-test-specs finalize + builder.put("Shanghai+6780", createSchedule(genesisStub.clone().cancunTime(0))); builder.put("Future_EIPs", createSchedule(genesisStub.clone().futureEipsTime(0))); builder.put("Experimental_EIPs", createSchedule(genesisStub.clone().experimentalEipsTime(0))); return new ReferenceTestProtocolSchedules(builder.build()); diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/StateTestVersionedTransaction.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/StateTestVersionedTransaction.java index 69ad9267536..328f8d68862 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/StateTestVersionedTransaction.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/StateTestVersionedTransaction.java @@ -19,6 +19,7 @@ import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.evm.AccessListEntry; @@ -71,6 +72,8 @@ public class StateTestVersionedTransaction { private final List values; private final List payloads; private final Optional>> maybeAccessLists; + private final Wei maxFeePerBlobGas; + private final List blobVersionedHashes; /** * Constructor for populating a mock transaction with json data. @@ -98,7 +101,9 @@ public StateTestVersionedTransaction( @JsonProperty("secretKey") final String secretKey, @JsonProperty("data") final String[] data, @JsonDeserialize(using = StateTestAccessListDeserializer.class) @JsonProperty("accessLists") - final List> maybeAccessLists) { + final List> maybeAccessLists, + @JsonProperty("maxFeePerBlobGas") final String maxFeePerBlobGas, + @JsonProperty("blobVersionedHashes") final List blobVersionedHashes) { this.nonce = Bytes.fromHexStringLenient(nonce).toLong(); this.gasPrice = Optional.ofNullable(gasPrice).map(Wei::fromHexString).orElse(null); @@ -116,9 +121,16 @@ public StateTestVersionedTransaction( this.values = parseArray(value, Wei::fromHexString); this.payloads = parseArray(data, Bytes::fromHexString); this.maybeAccessLists = Optional.ofNullable(maybeAccessLists); + this.maxFeePerBlobGas = + Optional.ofNullable(maxFeePerBlobGas).map(Wei::fromHexString).orElse(null); + this.blobVersionedHashes = blobVersionedHashes; } private static List parseArray(final String[] array, final Function parseFct) { + if (array == null) { + return null; + } + final List res = new ArrayList<>(array.length); for (final String str : array) { try { @@ -148,6 +160,8 @@ public Transaction get(final GeneralStateTestCaseSpec.Indexes indexes) { Optional.ofNullable(maxPriorityFeePerGas).ifPresent(transactionBuilder::maxPriorityFeePerGas); maybeAccessLists.ifPresent( accessLists -> transactionBuilder.accessList(accessLists.get(indexes.data))); + Optional.ofNullable(maxFeePerBlobGas).ifPresent(transactionBuilder::maxFeePerBlobGas); + transactionBuilder.versionedHashes(blobVersionedHashes); transactionBuilder.guessType(); if (transactionBuilder.getTransactionType().requiresChainId()) { diff --git a/ethereum/referencetests/src/reference-test/external-resources b/ethereum/referencetests/src/reference-test/external-resources index 04f338a6e67..661356317ac 160000 --- a/ethereum/referencetests/src/reference-test/external-resources +++ b/ethereum/referencetests/src/reference-test/external-resources @@ -1 +1 @@ -Subproject commit 04f338a6e673a6b4d906ec9d6d2bc939309357a5 +Subproject commit 661356317ac6df52208d54187e692472a25a01f8 diff --git a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/core/TransactionTest.java b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/core/TransactionTest.java index 3cc53650024..d36a0b6a87d 100644 --- a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/core/TransactionTest.java +++ b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/core/TransactionTest.java @@ -17,7 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionValidator; +import org.hyperledger.besu.ethereum.mainnet.TransactionValidator; import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.referencetests.ReferenceTestProtocolSchedules; @@ -50,11 +50,11 @@ public class TransactionTest { private static final ReferenceTestProtocolSchedules REFERENCE_TEST_PROTOCOL_SCHEDULES = ReferenceTestProtocolSchedules.create(); - private static MainnetTransactionValidator transactionValidator(final String name) { + private static TransactionValidator transactionValidator(final String name) { return REFERENCE_TEST_PROTOCOL_SCHEDULES .getByName(name) .getByBlockHeader(BlockHeaderBuilder.createDefault().buildBlockHeader()) - .getTransactionValidator(); + .getTransactionValidatorFactory().get(); } private static final String TEST_CONFIG_FILE_DIR_PATH = "TransactionTests/"; diff --git a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/GeneralStateReferenceTestTools.java b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/GeneralStateReferenceTestTools.java index 41dffe2b5bf..58e36c1c58e 100644 --- a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/GeneralStateReferenceTestTools.java +++ b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/GeneralStateReferenceTestTools.java @@ -16,7 +16,7 @@ import static org.assertj.core.api.Assertions.assertThat; -import org.hyperledger.besu.datatypes.DataGas; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -52,14 +52,13 @@ public class GeneralStateReferenceTestTools { Arrays.asList("Frontier", "Homestead", "EIP150"); private static MainnetTransactionProcessor transactionProcessor(final String name) { - return protocolSpec(name) - .getTransactionProcessor(); + return protocolSpec(name).getTransactionProcessor(); } private static ProtocolSpec protocolSpec(final String name) { return REFERENCE_TEST_PROTOCOL_SCHEDULES - .getByName(name) - .getByBlockHeader(BlockHeaderBuilder.createDefault().buildBlockHeader()); + .getByName(name) + .getByBlockHeader(BlockHeaderBuilder.createDefault().buildBlockHeader()); } private static final List EIPS_TO_RUN; @@ -146,8 +145,10 @@ public static void executeTest(final GeneralStateTestCaseEipSpec spec) { final MainnetTransactionProcessor processor = transactionProcessor(spec.getFork()); final WorldUpdater worldStateUpdater = worldState.updater(); final ReferenceTestBlockchain blockchain = new ReferenceTestBlockchain(blockHeader.getNumber()); - // Todo: EIP-4844 use the excessDataGas of the parent instead of DataGas.ZERO - final Wei dataGasPrice = protocolSpec(spec.getFork()).getFeeMarket().dataPrice(DataGas.ZERO); + final Wei blobGasPrice = + protocolSpec(spec.getFork()) + .getFeeMarket() + .blobGasPricePerGas(blockHeader.getExcessBlobGas().orElse(BlobGas.ZERO)); final TransactionProcessingResult result = processor.processTransaction( blockchain, @@ -158,7 +159,7 @@ public static void executeTest(final GeneralStateTestCaseEipSpec spec) { new CachingBlockHashLookup(blockHeader, blockchain), false, TransactionValidationParams.processingBlock(), - dataGasPrice); + blobGasPrice); if (result.isInvalid()) { assertThat(spec.getExpectException()).isNotNull(); return; diff --git a/ethereum/retesteth/build.gradle b/ethereum/retesteth/build.gradle index 08d06932905..10b978b1534 100644 --- a/ethereum/retesteth/build.gradle +++ b/ethereum/retesteth/build.gradle @@ -47,13 +47,10 @@ dependencies { implementation 'io.vertx:vertx-core' implementation 'io.vertx:vertx-web' implementation 'com.fasterxml.jackson.core:jackson-databind' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-units' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-units' - testImplementation 'junit:junit' testImplementation 'org.assertj:assertj-core' testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.mockito:mockito-core' - - testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' } diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/NoRewardProtocolScheduleWrapper.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/NoRewardProtocolScheduleWrapper.java index 09f99f16281..f4ad7774058 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/NoRewardProtocolScheduleWrapper.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/NoRewardProtocolScheduleWrapper.java @@ -19,8 +19,8 @@ import org.hyperledger.besu.ethereum.MainnetBlockValidator; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockImporter; +import org.hyperledger.besu.ethereum.core.PermissionTransactionFilter; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; -import org.hyperledger.besu.ethereum.core.TransactionFilter; import org.hyperledger.besu.ethereum.mainnet.BlockProcessor; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockImporter; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockProcessor; @@ -62,7 +62,7 @@ public ProtocolSpec getByBlockHeader(final ProcessableBlockHeader blockHeader) { return new ProtocolSpec( original.getName(), original.getEvm(), - original.getTransactionValidator(), + original.getTransactionValidatorFactory(), original.getTransactionProcessor(), original.getPrivateTransactionProcessor(), original.getBlockHeaderValidator(), @@ -86,7 +86,8 @@ public ProtocolSpec getByBlockHeader(final ProcessableBlockHeader blockHeader) { original.getWithdrawalsValidator(), original.getWithdrawalsProcessor(), original.getDepositsValidator(), - original.isPoS()); + original.isPoS(), + original.isReplayProtectionSupported()); } @Override @@ -114,14 +115,21 @@ public void putTimestampMilestone(final long timestamp, final ProtocolSpec proto delegate.putTimestampMilestone(timestamp, protocolSpec); } + @Override + public Optional hardforkFor( + final Predicate predicate) { + return delegate.hardforkFor(predicate); + } + @Override public String listMilestones() { return delegate.listMilestones(); } @Override - public void setTransactionFilter(final TransactionFilter transactionFilter) { - delegate.setTransactionFilter(transactionFilter); + public void setPermissionTransactionFilter( + final PermissionTransactionFilter permissionTransactionFilter) { + delegate.setPermissionTransactionFilter(permissionTransactionFilter); } @Override diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java index 95cb744ace4..52cc2a3ce04 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java @@ -41,7 +41,6 @@ import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolFactory; @@ -306,10 +305,6 @@ public TransactionPool getTransactionPool() { return transactionPool; } - PendingTransactions getPendingTransactions() { - return transactionPool.getPendingTransactions(); - } - public Address getCoinbase() { return coinbase; } diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethService.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethService.java index 6bc6d1ef138..ceca8ebc11e 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethService.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethService.java @@ -80,7 +80,7 @@ public RetestethService( new EthGetBlockByHash(retestethContext::getBlockchainQueries, blockResult, true), new EthGetCode(retestethContext::getBlockchainQueries), new EthGetTransactionCount( - retestethContext::getBlockchainQueries, retestethContext::getPendingTransactions), + retestethContext::getBlockchainQueries, retestethContext::getTransactionPool), new DebugStorageRangeAt( retestethContext::getBlockchainQueries, retestethContext::getBlockReplay, true), new TestModifyTimestamp(retestethContext), diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestGetLogHash.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestGetLogHash.java index 637110b74a5..a0790c9fcdb 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestGetLogHash.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestGetLogHash.java @@ -43,7 +43,9 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { final Hash txHash = requestContext.getRequiredParameter(0, Hash.class); final Optional receipt = - context.getBlockchainQueries().transactionReceiptByTransactionHash(txHash); + context + .getBlockchainQueries() + .transactionReceiptByTransactionHash(txHash, context.getProtocolSchedule()); return new JsonRpcSuccessResponse( requestContext.getRequest().getId(), receipt.map(this::calculateLogHash).orElse(Hash.EMPTY_LIST_HASH).toString()); diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestImportRawBlock.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestImportRawBlock.java index 32430eb4169..0652b92cdbf 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestImportRawBlock.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestImportRawBlock.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockImporter; import org.hyperledger.besu.ethereum.mainnet.BlockImportResult; @@ -62,7 +62,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { } catch (final RLPException | IllegalArgumentException e) { LOG.debug("Failed to parse block RLP", e); return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.BLOCK_RLP_IMPORT_ERROR); + requestContext.getRequest().getId(), RpcErrorType.BLOCK_RLP_IMPORT_ERROR); } // retesteth expects test_rawImportBlock to not only import the block, but append it to head @@ -89,7 +89,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { if (!result.isImported()) { LOG.debug("Failed to import block."); return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.BLOCK_IMPORT_ERROR); + requestContext.getRequest().getId(), RpcErrorType.BLOCK_IMPORT_ERROR); } } // return success on append or import diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java index 59ac6df2401..f802ee73e4b 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java @@ -67,7 +67,7 @@ private boolean mineNewBlock() { context.getCoinbase(), () -> Optional.of(blockchain.getChainHeadHeader().getGasLimit()), header -> context.getExtraData(), - context.getTransactionPool().getPendingTransactions(), + context.getTransactionPool(), protocolContext, protocolSchedule, context.getEthHashSolver(), diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParams.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParams.java index d55fbe9dd12..1059f02c200 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParams.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParams.java @@ -16,10 +16,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.retesteth.RetestethContext; import java.util.Iterator; @@ -67,7 +67,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { } catch (final Exception e) { LOG.error("Unhandled error", e); return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); + requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); } } diff --git a/ethereum/retesteth/src/test/java/org/hyperledger/besu/ethereum/retesteth/methods/TestImportRawBlockTest.java b/ethereum/retesteth/src/test/java/org/hyperledger/besu/ethereum/retesteth/methods/TestImportRawBlockTest.java index 27fc9f28f27..e8ec55e2d61 100644 --- a/ethereum/retesteth/src/test/java/org/hyperledger/besu/ethereum/retesteth/methods/TestImportRawBlockTest.java +++ b/ethereum/retesteth/src/test/java/org/hyperledger/besu/ethereum/retesteth/methods/TestImportRawBlockTest.java @@ -20,10 +20,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponseType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.retesteth.RetestethContext; import java.io.IOException; @@ -31,15 +31,15 @@ import com.google.common.base.Charsets; import com.google.common.io.Resources; import io.vertx.core.json.JsonObject; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class TestImportRawBlockTest { private TestImportRawBlock test_importRawBlock; private TestRewindToBlock test_rewindToBlock; private RetestethContext context; - @Before + @BeforeEach public void setupClass() throws IOException { context = new RetestethContext(); test_importRawBlock = new TestImportRawBlock(context); @@ -72,8 +72,8 @@ public void testMissingParent() { final var response = test_importRawBlock.response(request); assertThat(response.getType()).isEqualTo(JsonRpcResponseType.ERROR); - assertThat(((JsonRpcErrorResponse) response).getError()) - .isEqualTo(JsonRpcError.BLOCK_IMPORT_ERROR); + assertThat(((JsonRpcErrorResponse) response).getErrorType()) + .isEqualTo(RpcErrorType.BLOCK_IMPORT_ERROR); } @Test @@ -87,8 +87,8 @@ public void testBadBlock() { final var response = test_importRawBlock.response(request); assertThat(response.getType()).isEqualTo(JsonRpcResponseType.ERROR); - assertThat(((JsonRpcErrorResponse) response).getError()) - .isEqualTo(JsonRpcError.BLOCK_RLP_IMPORT_ERROR); + assertThat(((JsonRpcErrorResponse) response).getErrorType()) + .isEqualTo(RpcErrorType.BLOCK_RLP_IMPORT_ERROR); } @Test diff --git a/ethereum/retesteth/src/test/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParamsTest.java b/ethereum/retesteth/src/test/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParamsTest.java index 107bc7a5a01..f376fa0c250 100644 --- a/ethereum/retesteth/src/test/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParamsTest.java +++ b/ethereum/retesteth/src/test/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParamsTest.java @@ -29,15 +29,15 @@ import com.google.common.io.Resources; import io.vertx.core.json.JsonObject; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; public class TestSetChainParamsTest { private static RetestethContext context; private static TestSetChainParams test_setChainParams; - @BeforeClass + @BeforeAll public static void setupClass() { context = new RetestethContext(); test_setChainParams = new TestSetChainParams(context); diff --git a/ethereum/rlp/build.gradle b/ethereum/rlp/build.gradle index 678918d7cef..682d26761bf 100644 --- a/ethereum/rlp/build.gradle +++ b/ethereum/rlp/build.gradle @@ -31,8 +31,8 @@ jar { dependencies { annotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-units' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-units' implementation 'com.google.guava:guava' @@ -41,11 +41,8 @@ dependencies { testImplementation project(':testutil') testImplementation 'com.fasterxml.jackson.core:jackson-databind' - testImplementation 'junit:junit' testImplementation 'org.assertj:assertj-core' testImplementation 'org.junit.jupiter:junit-jupiter' - - testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' } artifacts { testSupportArtifacts testSupportJar } diff --git a/ethereum/rlp/src/test/java/org/hyperledger/besu/ethereum/rlp/BytesValueRLPInputTest.java b/ethereum/rlp/src/test/java/org/hyperledger/besu/ethereum/rlp/BytesValueRLPInputTest.java index 10550e75143..05c62629250 100644 --- a/ethereum/rlp/src/test/java/org/hyperledger/besu/ethereum/rlp/BytesValueRLPInputTest.java +++ b/ethereum/rlp/src/test/java/org/hyperledger/besu/ethereum/rlp/BytesValueRLPInputTest.java @@ -23,7 +23,7 @@ import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.AssertionsForClassTypes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class BytesValueRLPInputTest { diff --git a/ethereum/rlp/src/test/java/org/hyperledger/besu/ethereum/rlp/BytesValueRLPOutputTest.java b/ethereum/rlp/src/test/java/org/hyperledger/besu/ethereum/rlp/BytesValueRLPOutputTest.java index 8dc3da30467..a155616cbc8 100644 --- a/ethereum/rlp/src/test/java/org/hyperledger/besu/ethereum/rlp/BytesValueRLPOutputTest.java +++ b/ethereum/rlp/src/test/java/org/hyperledger/besu/ethereum/rlp/BytesValueRLPOutputTest.java @@ -19,7 +19,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class BytesValueRLPOutputTest { diff --git a/ethereum/rlp/src/test/java/org/hyperledger/besu/ethereum/rlp/RLPTest.java b/ethereum/rlp/src/test/java/org/hyperledger/besu/ethereum/rlp/RLPTest.java index bc4fca1fb4a..a4389cafa98 100644 --- a/ethereum/rlp/src/test/java/org/hyperledger/besu/ethereum/rlp/RLPTest.java +++ b/ethereum/rlp/src/test/java/org/hyperledger/besu/ethereum/rlp/RLPTest.java @@ -22,7 +22,7 @@ import java.util.Random; import org.apache.tuweni.bytes.Bytes; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class RLPTest { diff --git a/ethereum/stratum/build.gradle b/ethereum/stratum/build.gradle index d462fb3f32d..5c7dfaed20d 100644 --- a/ethereum/stratum/build.gradle +++ b/ethereum/stratum/build.gradle @@ -41,8 +41,8 @@ dependencies { implementation 'com.google.guava:guava' implementation 'io.vertx:vertx-core' implementation 'com.fasterxml.jackson.core:jackson-databind' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-units' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-units' testImplementation project(path: ':metrics:core', configuration: 'testSupportArtifacts') testImplementation project(':testutil') diff --git a/ethereum/trie/build.gradle b/ethereum/trie/build.gradle index 0477841563d..e8ce5cb9b70 100644 --- a/ethereum/trie/build.gradle +++ b/ethereum/trie/build.gradle @@ -36,7 +36,7 @@ dependencies { implementation 'org.immutables:value-annotations' implementation 'com.google.guava:guava' implementation 'io.opentelemetry:opentelemetry-api' - implementation 'org.apache.tuweni:tuweni-bytes' + implementation 'io.tmio:tuweni-bytes' implementation 'org.bouncycastle:bcprov-jdk18on' annotationProcessor 'org.immutables:value' @@ -45,11 +45,9 @@ dependencies { testImplementation project(':testutil') testImplementation 'com.fasterxml.jackson.core:jackson-databind' - testImplementation 'junit:junit' - testImplementation 'org.apache.tuweni:tuweni-units' + testImplementation 'io.tmio:tuweni-units' testImplementation 'org.assertj:assertj-core' testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.mockito:mockito-core' - - testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' + testImplementation 'org.mockito:mockito-junit-jupiter' } diff --git a/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/AllNodesVisitorTest.java b/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/AllNodesVisitorTest.java index a117335318e..5bd3535756f 100644 --- a/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/AllNodesVisitorTest.java +++ b/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/AllNodesVisitorTest.java @@ -22,12 +22,12 @@ import java.util.Collections; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class AllNodesVisitorTest { @Mock private StoredNode storedNode; diff --git a/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/CompactEncodingTest.java b/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/CompactEncodingTest.java index dabc5ca56bf..f51fa449a92 100644 --- a/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/CompactEncodingTest.java +++ b/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/CompactEncodingTest.java @@ -23,7 +23,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class CompactEncodingTest { diff --git a/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/RangeStorageEntriesCollectorTest.java b/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/RangeStorageEntriesCollectorTest.java index da44b541c87..6b931d041e5 100644 --- a/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/RangeStorageEntriesCollectorTest.java +++ b/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/RangeStorageEntriesCollectorTest.java @@ -22,7 +22,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class RangeStorageEntriesCollectorTest { diff --git a/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/SnapPutVisitorTest.java b/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/SnapPutVisitorTest.java index 76381d918a7..cbedbe9a288 100644 --- a/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/SnapPutVisitorTest.java +++ b/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/SnapPutVisitorTest.java @@ -31,7 +31,7 @@ import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; @SuppressWarnings("unchecked") public class SnapPutVisitorTest { diff --git a/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/TrieIteratorTest.java b/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/TrieIteratorTest.java index b7220a3392a..3264ccffb72 100644 --- a/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/TrieIteratorTest.java +++ b/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/TrieIteratorTest.java @@ -38,7 +38,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.InOrder; public class TrieIteratorTest { diff --git a/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/TrieNodeDecoderTest.java b/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/TrieNodeDecoderTest.java index 1d654bf6d4c..f5c15dd18b6 100644 --- a/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/TrieNodeDecoderTest.java +++ b/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/TrieNodeDecoderTest.java @@ -31,7 +31,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class TrieNodeDecoderTest { diff --git a/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/patricia/AbstractMerklePatriciaTrieTest.java b/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/patricia/AbstractMerklePatriciaTrieTest.java index d843b467f36..f201d3fa4e0 100644 --- a/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/patricia/AbstractMerklePatriciaTrieTest.java +++ b/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/patricia/AbstractMerklePatriciaTrieTest.java @@ -15,9 +15,9 @@ package org.hyperledger.besu.ethereum.trie.patricia; import static java.nio.charset.StandardCharsets.UTF_8; -import static junit.framework.TestCase.assertFalse; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertFalse; import org.hyperledger.besu.ethereum.trie.CompactEncoding; import org.hyperledger.besu.ethereum.trie.KeyValueMerkleStorage; @@ -33,13 +33,13 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public abstract class AbstractMerklePatriciaTrieTest { protected MerkleTrie trie; - @Before + @BeforeEach public void setup() { trie = createTrie(); } diff --git a/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/patricia/StoredMerklePatriciaTrieTest.java b/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/patricia/StoredMerklePatriciaTrieTest.java index 40bef52fe4d..d33746b062f 100644 --- a/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/patricia/StoredMerklePatriciaTrieTest.java +++ b/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/patricia/StoredMerklePatriciaTrieTest.java @@ -28,7 +28,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class StoredMerklePatriciaTrieTest extends AbstractMerklePatriciaTrieTest { private KeyValueStorage keyValueStore; diff --git a/ethereum/verkletrie/build.gradle b/ethereum/verkletrie/build.gradle index 1d23538ed0c..166b02efe17 100644 --- a/ethereum/verkletrie/build.gradle +++ b/ethereum/verkletrie/build.gradle @@ -35,8 +35,8 @@ dependencies { implementation "org.immutables:value-annotations" implementation 'com.google.guava:guava' implementation 'io.opentelemetry:opentelemetry-api' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-units' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-units' implementation 'org.bouncycastle:bcprov-jdk18on' implementation 'org.hyperledger.besu:ipa-multipoint' @@ -47,11 +47,8 @@ dependencies { testImplementation 'com.fasterxml.jackson.core:jackson-databind' testImplementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml' - testImplementation 'junit:junit' - testImplementation 'org.apache.tuweni:tuweni-units' + testImplementation 'io.tmio:tuweni-units' testImplementation 'org.assertj:assertj-core' testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.mockito:mockito-core' - - testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' } diff --git a/ethereum/verkletrie/src/test/java/org/hyperledger/besu/ethereum/verkletrie/bandersnatch/fp/ElementTest.java b/ethereum/verkletrie/src/test/java/org/hyperledger/besu/ethereum/verkletrie/bandersnatch/fp/ElementTest.java index fe3fcb00827..d7f72dd74b2 100644 --- a/ethereum/verkletrie/src/test/java/org/hyperledger/besu/ethereum/verkletrie/bandersnatch/fp/ElementTest.java +++ b/ethereum/verkletrie/src/test/java/org/hyperledger/besu/ethereum/verkletrie/bandersnatch/fp/ElementTest.java @@ -19,7 +19,7 @@ import java.math.BigInteger; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class ElementTest { diff --git a/ethereum/verkletrie/src/test/java/org/hyperledger/besu/ethereum/verkletrie/bandersnatch/fr/ElementTest.java b/ethereum/verkletrie/src/test/java/org/hyperledger/besu/ethereum/verkletrie/bandersnatch/fr/ElementTest.java index ef7c1923327..b4046ac6ab4 100644 --- a/ethereum/verkletrie/src/test/java/org/hyperledger/besu/ethereum/verkletrie/bandersnatch/fr/ElementTest.java +++ b/ethereum/verkletrie/src/test/java/org/hyperledger/besu/ethereum/verkletrie/bandersnatch/fr/ElementTest.java @@ -19,7 +19,7 @@ import java.math.BigInteger; import org.apache.tuweni.units.bigints.UInt256; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class ElementTest { diff --git a/evm/build.gradle b/evm/build.gradle index dd8760c1079..83caaae31b1 100644 --- a/evm/build.gradle +++ b/evm/build.gradle @@ -40,8 +40,8 @@ dependencies { implementation 'com.github.ben-manes.caffeine:caffeine' implementation 'com.google.guava:guava' implementation 'net.java.dev.jna:jna' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-units' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-units' implementation 'org.hyperledger.besu:arithmetic' implementation 'org.hyperledger.besu:bls12-381' implementation 'tech.pegasys:jc-kzg-4844' diff --git a/evm/src/main/java/org/hyperledger/besu/collections/undo/UndoList.java b/evm/src/main/java/org/hyperledger/besu/collections/undo/UndoList.java new file mode 100644 index 00000000000..cda40649af6 --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/collections/undo/UndoList.java @@ -0,0 +1,317 @@ +/* + * Copyright contributors to Hyperledger Besu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ +package org.hyperledger.besu.collections.undo; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import javax.annotation.Nonnull; + +/** + * A list that supports rolling back the list to a prior state. + * + *

    To register a prior state you want to roll back to call `mark()`. Then use that value in a + * subsequent call to `undo(mark)`. Every mutation operation across all undoable collections + * increases the global mark, so a mark set in once collection is usable across all + * UndoableCollection instances. + * + * @param The type of the collection. + */ +public class UndoList implements List, UndoableCollection { + + record UndoEntry(int index, boolean set, V value, long level) { + UndoEntry(final int index, final boolean set, final V value) { + this(index, set, value, UndoableCollection.incrementMarkStatic()); + } + + @Override + public String toString() { + return "UndoEntry{" + + "index=" + + index + + ", set=" + + set + + ", value=" + + value + + ", level=" + + level + + '}'; + } + } + + static class ReadOnlyListIterator implements ListIterator { + ListIterator iterDelegate; + + public ReadOnlyListIterator(final ListIterator iterDelegate) { + this.iterDelegate = iterDelegate; + } + + @Override + public boolean hasNext() { + return iterDelegate.hasNext(); + } + + @Override + public V next() { + return iterDelegate.next(); + } + + @Override + public boolean hasPrevious() { + return iterDelegate.hasPrevious(); + } + + @Override + public V previous() { + return iterDelegate.previous(); + } + + @Override + public int nextIndex() { + return iterDelegate.nextIndex(); + } + + @Override + public int previousIndex() { + return iterDelegate.previousIndex(); + } + + @Override + public void remove() { + throw new UnsupportedOperationException( + "UndoList does not support iterator based modification"); + } + + @Override + public void set(final V v) { + throw new UnsupportedOperationException( + "UndoList does not support iterator based modification"); + } + + @Override + public void add(final V v) { + throw new UnsupportedOperationException( + "UndoList does not support iterator based modification"); + } + } + + List delegate; + List> undoLog = new ArrayList<>(); + + /** + * Create an UndoList backed by another List instance. + * + * @param delegate The List instance to use for backing storage + */ + public UndoList(final List delegate) { + this.delegate = delegate; + } + + @Override + public void undo(final long mark) { + int pos = undoLog.size() - 1; + while (pos >= 0 && undoLog.get(pos).level > mark) { + final var entry = undoLog.get(pos); + undoLog.remove(pos); + if (entry.value() == null) { + delegate.remove(entry.index); + } else if (entry.set) { + delegate.set(entry.index, entry.value()); + } else { + delegate.add(entry.index, entry.value); + } + pos--; + } + } + + @Override + public boolean add(final V v) { + undoLog.add(new UndoEntry<>(delegate.size(), false, null)); + return delegate.add(v); + } + + @SuppressWarnings({"unchecked", "SuspiciousMethodCalls"}) + @Override + public boolean remove(final Object v) { + int index = delegate.indexOf(v); + if (index >= 0) { + delegate.remove(index); + undoLog.add(new UndoEntry<>(index, false, (V) v)); + return true; + } else { + return false; + } + } + + @Override + public boolean containsAll(final @Nonnull Collection c) { + return new HashSet<>(delegate).containsAll(c); + } + + @Override + public boolean addAll(final Collection c) { + for (V v : c) { + add(v); + } + return !c.isEmpty(); + } + + @Override + public boolean addAll(final int index, final Collection c) { + int pos = index; + for (V v : c) { + add(pos++, v); + } + return !c.isEmpty(); + } + + @Override + public boolean removeAll(final @Nonnull Collection c) { + HashSet hs = new HashSet<>(c); + ListIterator iter = delegate.listIterator(); + boolean updated = false; + while (iter.hasNext()) { + V v = iter.next(); + if (hs.contains(v)) { + undoLog.add(new UndoEntry<>(iter.previousIndex(), false, v)); + iter.remove(); + updated = true; + } + } + return updated; + } + + @Override + public boolean retainAll(final @Nonnull Collection c) { + HashSet hs = new HashSet<>(c); + ListIterator iter = delegate.listIterator(); + boolean updated = false; + while (iter.hasNext()) { + V v = iter.next(); + if (!hs.contains(v)) { + undoLog.add(new UndoEntry<>(iter.previousIndex(), false, v)); + iter.remove(); + updated = true; + } + } + return updated; + } + + @Override + public void clear() { + // store in log in reverse so when we restore them we are appending + for (int i = delegate.size() - 1; i >= 0; i--) { + remove(i); + } + } + + @Override + public V set(final int index, final V element) { + V oldValue = delegate.set(index, element); + undoLog.add(new UndoEntry<>(index, true, oldValue)); + return oldValue; + } + + @Override + public void add(final int index, final V element) { + delegate.add(index, element); + undoLog.add(new UndoEntry<>(index, false, null)); + } + + @Override + public V remove(final int index) { + undoLog.add(new UndoEntry<>(index, false, delegate.get(index))); + return delegate.remove(index); + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public boolean contains(final Object o) { + return delegate.contains(o); + } + + @Override + public Iterator iterator() { + return delegate.iterator(); + } + + @Override + public Object[] toArray() { + return delegate.toArray(); + } + + @Override + public T[] toArray(final @Nonnull T[] a) { + return delegate.toArray(a); + } + + @Override + public V get(final int index) { + return delegate.get(index); + } + + @Override + public int indexOf(final Object o) { + return delegate.indexOf(o); + } + + @Override + public int lastIndexOf(final Object o) { + return delegate.lastIndexOf(o); + } + + @Override + public ListIterator listIterator() { + return new ReadOnlyListIterator<>(delegate.listIterator()); + } + + @Override + public ListIterator listIterator(final int index) { + return new ReadOnlyListIterator<>(delegate.listIterator(index)); + } + + @Override + public List subList(final int fromIndex, final int toIndex) { + return delegate.subList(fromIndex, toIndex); + } + + @Override + public String toString() { + return "UndoList{" + "delegate=" + delegate + ", undoLog=" + undoLog + '}'; + } + + @Override + public boolean equals(final Object o) { + return o instanceof UndoList && delegate.equals(o); + } + + @Override + public int hashCode() { + return delegate.hashCode() ^ 0xde1e647e; + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/collections/undo/UndoMap.java b/evm/src/main/java/org/hyperledger/besu/collections/undo/UndoMap.java new file mode 100644 index 00000000000..1a76985b5f3 --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/collections/undo/UndoMap.java @@ -0,0 +1,156 @@ +/* + * Copyright contributors to Hyperledger Besu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ +package org.hyperledger.besu.collections.undo; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import javax.annotation.Nonnull; + +/** + * A map that supports rolling back the map to a prior state. + * + *

    To register a prior state you want to roll back to call `mark()`. Then use that value in a + * subsequent call to `undo(mark)`. Every mutation operation across all undoable collections + * increases the global mark, so a mark set in once collection is usable across all + * UndoableCollection instances. + * + * @param The type of the collection. + */ +public class UndoMap implements Map, UndoableCollection { + + record UndoEntry(K key, V value, long level) { + UndoEntry(final K key, final V value) { + this(key, value, UndoableCollection.incrementMarkStatic()); + } + } + + Map delegate; + List> undoLog; + + /** + * Create an UndoMap backed by another Map instance. + * + * @param delegate The Map instance to use for backing storage + */ + public UndoMap(final Map delegate) { + this.delegate = delegate; + undoLog = new ArrayList<>(); + } + + @Override + public void undo(final long mark) { + int pos = undoLog.size() - 1; + while (pos >= 0 && undoLog.get(pos).level > mark) { + final var entry = undoLog.get(pos); + undoLog.remove(pos); + if (entry.value() == null) { + delegate.remove(entry.key()); + } else { + delegate.put(entry.key(), entry.value()); + } + pos--; + } + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public boolean containsKey(final Object key) { + return delegate.containsKey(key); + } + + @Override + public boolean containsValue(final Object value) { + return delegate.containsValue(value); + } + + @Override + public V get(final Object key) { + return delegate.get(key); + } + + @Override + public V put(final @Nonnull K key, final @Nonnull V value) { + Objects.requireNonNull(value); + final V oldValue = delegate.put(key, value); + if (!value.equals(oldValue)) { + undoLog.add(new UndoEntry<>(key, oldValue)); + } + return oldValue; + } + + @SuppressWarnings("unchecked") + @Override + public V remove(final Object key) { + final V oldValue = delegate.remove(key); + if (oldValue != null) { + undoLog.add(new UndoEntry<>((K) key, oldValue)); + } + return oldValue; + } + + @Override + public void putAll(@Nonnull final Map m) { + m.forEach(this::put); + } + + @Override + public void clear() { + delegate.forEach((k, v) -> undoLog.add(new UndoEntry<>(k, v))); + delegate.clear(); + } + + @Nonnull + @Override + public Set keySet() { + return Collections.unmodifiableSet(delegate.keySet()); + } + + @Nonnull + @Override + public Collection values() { + return Collections.unmodifiableCollection(delegate.values()); + } + + @Nonnull + @Override + public Set> entrySet() { + return Collections.unmodifiableSet(delegate.entrySet()); + } + + @Override + public boolean equals(final Object o) { + return o instanceof UndoMap && delegate.equals(o); + } + + @Override + public int hashCode() { + return delegate.hashCode() ^ 0xde1e647e; + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/collections/undo/UndoSet.java b/evm/src/main/java/org/hyperledger/besu/collections/undo/UndoSet.java new file mode 100644 index 00000000000..1ba509d3094 --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/collections/undo/UndoSet.java @@ -0,0 +1,192 @@ +/* + * Copyright contributors to Hyperledger Besu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ +package org.hyperledger.besu.collections.undo; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import javax.annotation.Nonnull; + +/** + * A set that supports rolling back the set to a prior state. + * + *

    To register a prior state you want to roll back to call `mark()`. Then use that value in a + * subsequent call to `undo(mark)`. Every mutation operation across all undoable collections + * increases the global mark, so a mark set in once collection is usable across all + * UndoableCollection instances. + * + * @param The type of the collection. + */ +public class UndoSet implements Set, UndoableCollection { + + record UndoEntry(V value, boolean add, long level) { + static UndoSet.UndoEntry add(final V value) { + return new UndoEntry<>(value, true, UndoableCollection.incrementMarkStatic()); + } + + static UndoSet.UndoEntry remove(final V value) { + return new UndoEntry<>(value, false, UndoableCollection.incrementMarkStatic()); + } + } + + Set delegate; + List> undoLog; + + /** + * Create an UndoSet backed by another Set instance. + * + * @param delegate The Set instance to use for backing storage + * @param The type of the collection. + * @return an unduable set + */ + public static UndoSet of(final Set delegate) { + return new UndoSet<>(delegate); + } + + UndoSet(final Set delegate) { + this.delegate = delegate; + undoLog = new ArrayList<>(); + } + + @Override + public void undo(final long mark) { + int pos = undoLog.size() - 1; + while (pos >= 0 && undoLog.get(pos).level > mark) { + final var entry = undoLog.get(pos); + if (entry.add) { + delegate.remove(entry.value()); + } else { + delegate.add(entry.value()); + } + undoLog.remove(pos); + pos--; + } + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public boolean contains(final Object key) { + return delegate.contains(key); + } + + @Override + public boolean add(final V key) { + final boolean added = delegate.add(key); + if (added) { + undoLog.add(UndoEntry.add(key)); + } + return added; + } + + @SuppressWarnings("unchecked") + @Override + public boolean remove(final Object key) { + final boolean removed = delegate.remove(key); + if (removed) { + undoLog.add(UndoEntry.remove((V) key)); + } + return removed; + } + + @Override + public boolean addAll(@Nonnull final Collection m) { + boolean added = false; + for (V v : m) { + // don't use short circuit, we need to evaluate all entries + // we also need undo entries for each added entry + added &= add(v); + } + return added; + } + + @Override + public boolean removeAll(@Nonnull final Collection c) { + boolean removed = false; + for (Object v : c) { + // don't use short circuit, we need to evaluate all entries + // we also need undo entries for each removed entry + removed &= remove(v); + } + return removed; + } + + @Override + public boolean retainAll(@Nonnull final Collection c) { + boolean removed = false; + HashSet hashed = new HashSet<>(c); + Iterator iter = delegate.iterator(); + while (iter.hasNext()) { + V v = iter.next(); + if (!hashed.contains(v)) { + removed = true; + undoLog.add(UndoEntry.remove(v)); + iter.remove(); + } + } + return removed; + } + + @Override + public void clear() { + delegate.forEach(v -> undoLog.add(UndoEntry.remove(v))); + delegate.clear(); + } + + @Nonnull + @Override + public Iterator iterator() { + return new ReadOnlyIterator<>(delegate.iterator()); + } + + @Nonnull + @Override + public Object[] toArray() { + return delegate.toArray(); + } + + @Nonnull + @Override + public T[] toArray(@Nonnull final T[] a) { + return delegate.toArray(a); + } + + @Override + public boolean containsAll(@Nonnull final Collection c) { + return delegate.containsAll(c); + } + + @Override + public boolean equals(final Object o) { + return o instanceof UndoSet && delegate.equals(o); + } + + @Override + public int hashCode() { + return delegate.hashCode() ^ 0xde1e647e; + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/collections/undo/UndoTable.java b/evm/src/main/java/org/hyperledger/besu/collections/undo/UndoTable.java new file mode 100644 index 00000000000..26af3225f47 --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/collections/undo/UndoTable.java @@ -0,0 +1,209 @@ +/* + * Copyright contributors to Hyperledger Besu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ +package org.hyperledger.besu.collections.undo; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import javax.annotation.CheckForNull; + +import com.google.common.collect.Table; +import com.google.errorprone.annotations.CanIgnoreReturnValue; + +/** + * A Table that supports rolling back the Table to a prior state. + * + *

    To register a prior state you want to roll back to call `mark()`. Then use that value in a + * subsequent call to `undo(mark)`. Every mutation operation across all undoable collections + * increases the global mark, so a mark set in once collection is usable across all + * UndoableCollection instances. + * + * @param The type of the collection. + */ +public class UndoTable implements Table, UndoableCollection { + + record UndoEntry(R row, C column, V value, long level) { + UndoEntry(final R row, final C column, final V value) { + this(row, column, value, UndoableCollection.incrementMarkStatic()); + } + } + + Table delegate; + List> undoLog; + + /** + * Create an UndoTable backed by another Table instance. + * + * @param table The Table instance to use for backing storage + * @param The row type + * @param The column type + * @param The value type + * @return a new undo table backed by the provided table. + */ + public static UndoTable of(final Table table) { + return new UndoTable<>(table); + } + + /** + * Protected constructor for UndoTable + * + * @param delegate the table backing the undotable. + */ + protected UndoTable(final Table delegate) { + this.delegate = delegate; + undoLog = new ArrayList<>(); + } + + @Override + public void undo(final long mark) { + int pos = undoLog.size() - 1; + while (pos >= 0 && undoLog.get(pos).level > mark) { + final var entry = undoLog.get(pos); + undoLog.remove(pos); + if (entry.value() == null) { + delegate.remove(entry.row(), entry.column()); + } else { + delegate.put(entry.row(), entry.column(), entry.value()); + } + pos--; + } + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public boolean contains(final Object rowKey, final Object columnKey) { + return delegate.contains(rowKey, columnKey); + } + + @Override + public boolean containsRow(final Object rowKey) { + return delegate.containsRow(rowKey); + } + + @Override + public boolean containsColumn(final Object columnKey) { + return delegate.containsColumn(columnKey); + } + + @Override + public boolean containsValue(final Object value) { + return delegate.containsValue(value); + } + + @Override + @CheckForNull + public V get(final Object rowKey, final Object columnKey) { + return delegate.get(rowKey, columnKey); + } + + @Override + public void clear() { + delegate.clear(); + } + + @Override + @CanIgnoreReturnValue + @CheckForNull + public V put(final R rowKey, final C columnKey, final V value) { + V oldV = delegate.put(rowKey, columnKey, value); + undoLog.add(new UndoEntry<>(rowKey, columnKey, oldV)); + return oldV; + } + + @Override + public void putAll(final Table table) { + for (var cell : table.cellSet()) { + V newV = cell.getValue(); + V oldV = delegate.put(cell.getRowKey(), cell.getColumnKey(), newV); + if (!Objects.equals(oldV, newV)) { + undoLog.add(new UndoEntry<>(cell.getRowKey(), cell.getColumnKey(), oldV)); + } + } + } + + @SuppressWarnings("unchecked") + @Override + @CanIgnoreReturnValue + @CheckForNull + public V remove(final Object rowKey, final Object columnKey) { + V oldV = delegate.remove(rowKey, columnKey); + undoLog.add(new UndoEntry<>((R) rowKey, (C) columnKey, oldV)); + return oldV; + } + + @Override + public Map row(final R rowKey) { + return Collections.unmodifiableMap(delegate.row(rowKey)); + } + + @Override + public Map column(final C columnKey) { + return Collections.unmodifiableMap(delegate.column(columnKey)); + } + + @Override + public Set> cellSet() { + return Collections.unmodifiableSet(delegate.cellSet()); + } + + @Override + public Set rowKeySet() { + return Collections.unmodifiableSet(delegate.rowKeySet()); + } + + @Override + public Set columnKeySet() { + return Collections.unmodifiableSet(delegate.columnKeySet()); + } + + @Override + public Collection values() { + return Collections.unmodifiableCollection(delegate.values()); + } + + @Override + public Map> rowMap() { + return Collections.unmodifiableMap(delegate.rowMap()); + } + + @Override + public Map> columnMap() { + return Collections.unmodifiableMap(delegate.columnMap()); + } + + @Override + public boolean equals(final Object o) { + return o instanceof UndoTable && delegate.equals(o); + } + + @Override + public int hashCode() { + return delegate.hashCode() ^ 0xde1e647e; + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/collections/undo/UndoableCollection.java b/evm/src/main/java/org/hyperledger/besu/collections/undo/UndoableCollection.java new file mode 100644 index 00000000000..25bfaa8ee50 --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/collections/undo/UndoableCollection.java @@ -0,0 +1,86 @@ +/* + * Copyright contributors to Hyperledger Besu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ +package org.hyperledger.besu.collections.undo; + +import java.util.Iterator; +import java.util.concurrent.atomic.AtomicLong; + +/** + * A manually ticked clock to determine when in execution an item was added to an undo collection. + * This allows for tracking of only one undo marker across multiple collections and rolling back + * multiple collections to a consistent point with only one number. + */ +public interface UndoableCollection { + /** The global mark clock for registering marks in undoable collections. */ + AtomicLong markState = new AtomicLong(); + + /** + * Retrieves an identifier that represents the current state of the collection. + * + *

    This marker is tracked globally so getting a mark in one Undoable collection will provide a + * mark that can be used in other UndoableCollections + * + * @return a long representing the current state. + */ + default long mark() { + return markState.get(); + } + + /** + * Advances the mark to a state greater than when it was before. + * + * @return a new mark that is guaranteed to be after the prior mark's value. + */ + static long incrementMarkStatic() { + return markState.incrementAndGet(); + } + + /** + * Returns the state of the collection to the state it was in when the mark was retrieved. + * Additions and removals are undone un reverse order until the collection state is restored. + * + * @param mark The mark to which the undo should proceed to, but not prior to + */ + void undo(long mark); + + /** + * Since we are relying on delegation, iterators should not be able to modify the collection. + * + * @param the type of the collection + */ + final class ReadOnlyIterator implements Iterator { + Iterator delegate; + + /** + * Create a read-only delegated iterator + * + * @param delegate the iterator to pass read only calls to. + */ + public ReadOnlyIterator(final Iterator delegate) { + this.delegate = delegate; + } + + @Override + public boolean hasNext() { + return delegate.hasNext(); + } + + @Override + public V next() { + return delegate.next(); + } + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/EvmSpecVersion.java b/evm/src/main/java/org/hyperledger/besu/evm/EvmSpecVersion.java index 03ea8a3b8b4..bd53ba11d2c 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/EvmSpecVersion.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/EvmSpecVersion.java @@ -79,6 +79,16 @@ public enum EvmSpecVersion { this.description = description; } + /** + * What is the "default" version of EVM that should be made. Newer versions of Besu will adjust + * this to reflect mainnet fork development. + * + * @return the current mainnet for as of the release of this version of Besu + */ + public static EvmSpecVersion defaultVersion() { + return SHANGHAI; + } + /** * Gets max eof version. * @@ -120,4 +130,19 @@ public void maybeWarnVersion() { } versionWarned = true; } + + /** + * Calculate a spec version from a text fork name. + * + * @param name The name of the fork, such as "shahghai" or "berlin" + * @return the EVM spec version for that fork, or null if no fork matched. + */ + public static EvmSpecVersion fromName(final String name) { + for (var version : EvmSpecVersion.values()) { + if (version.name().equalsIgnoreCase(name)) { + return version; + } + } + return null; + } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java b/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java index fdebbdb2de4..3aad40735d8 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.evm; +import org.hyperledger.besu.evm.gascalculator.BerlinGasCalculator; import org.hyperledger.besu.evm.gascalculator.ByzantiumGasCalculator; import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; import org.hyperledger.besu.evm.gascalculator.ConstantinopleGasCalculator; @@ -32,6 +33,7 @@ import org.hyperledger.besu.evm.operation.AndOperation; import org.hyperledger.besu.evm.operation.BalanceOperation; import org.hyperledger.besu.evm.operation.BaseFeeOperation; +import org.hyperledger.besu.evm.operation.BlobHashOperation; import org.hyperledger.besu.evm.operation.BlockHashOperation; import org.hyperledger.besu.evm.operation.ByteOperation; import org.hyperledger.besu.evm.operation.CallCodeOperation; @@ -48,7 +50,6 @@ import org.hyperledger.besu.evm.operation.CoinbaseOperation; import org.hyperledger.besu.evm.operation.Create2Operation; import org.hyperledger.besu.evm.operation.CreateOperation; -import org.hyperledger.besu.evm.operation.DataHashOperation; import org.hyperledger.besu.evm.operation.DelegateCallOperation; import org.hyperledger.besu.evm.operation.DifficultyOperation; import org.hyperledger.besu.evm.operation.DivOperation; @@ -546,7 +547,7 @@ public static EVM berlin(final EvmConfiguration evmConfiguration) { * @return the evm */ public static EVM berlin(final BigInteger chainId, final EvmConfiguration evmConfiguration) { - return berlin(new IstanbulGasCalculator(), chainId, evmConfiguration); + return berlin(new BerlinGasCalculator(), chainId, evmConfiguration); } /** @@ -843,15 +844,18 @@ public static void registerCancunOperations( final BigInteger chainID) { registerShanghaiOperations(registry, gasCalculator, chainID); - // EIP-4844 DATAHASH - registry.put(new DataHashOperation(gasCalculator)); - // EIP-1153 TSTORE/TLOAD registry.put(new TStoreOperation(gasCalculator)); registry.put(new TLoadOperation(gasCalculator)); + // EIP-4844 BLOBHASH + registry.put(new BlobHashOperation(gasCalculator)); + // EIP-5656 MCOPY registry.put(new MCopyOperation(gasCalculator)); + + // EIP-6780 nerf self destruct + registry.put(new SelfDestructOperation(gasCalculator, true)); } /** diff --git a/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java b/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java index 875b3da49db..f25d5259b96 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java @@ -36,7 +36,6 @@ import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import java.util.ArrayDeque; import java.util.Collection; import java.util.Deque; import java.util.List; @@ -345,11 +344,9 @@ public Bytes execute( public Bytes execute() { final MessageCallProcessor mcp = thisMessageCallProcessor(); final ContractCreationProcessor ccp = thisContractCreationProcessor(); - final Deque messageFrameStack = new ArrayDeque<>(); final MessageFrame initialMessageFrame = MessageFrame.builder() .type(MessageFrame.Type.MESSAGE_CALL) - .messageFrameStack(messageFrameStack) .worldUpdater(worldUpdater.updater()) .initialGas(gas) .contract(Address.ZERO) @@ -362,15 +359,14 @@ public Bytes execute() { .apparentValue(ethValue) .code(code) .blockValues(blockValues) - .depth(0) .completer(c -> {}) .miningBeneficiary(Address.ZERO) .blockHashLookup(h -> null) .accessListWarmAddresses(accessListWarmAddresses) .accessListWarmStorage(accessListWarmStorage) .build(); - messageFrameStack.add(initialMessageFrame); + final Deque messageFrameStack = initialMessageFrame.getMessageFrameStack(); while (!messageFrameStack.isEmpty()) { final MessageFrame messageFrame = messageFrameStack.peek(); if (messageFrame.getType() == MessageFrame.Type.CONTRACT_CREATION) { diff --git a/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleAccount.java b/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleAccount.java index 1d1c1c81d3d..75c86070950 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleAccount.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleAccount.java @@ -41,7 +41,7 @@ public class SimpleAccount implements EvmAccount, MutableAccount { private Address address; private final Supplier addressHash = - Suppliers.memoize(() -> address == null ? Hash.ZERO : Hash.hash(address)); + Suppliers.memoize(() -> address == null ? Hash.ZERO : address.addressHash()); private long nonce; private Wei balance; private Bytes code; diff --git a/evm/src/main/java/org/hyperledger/besu/evm/frame/BlockValues.java b/evm/src/main/java/org/hyperledger/besu/evm/frame/BlockValues.java index 74db00274a0..aade1f98437 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/frame/BlockValues.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/frame/BlockValues.java @@ -22,7 +22,7 @@ import org.apache.tuweni.bytes.Bytes32; /** - * Block Header Values used by various EVM Opcodes. This is not a complete BlocHeader, just the + * Block Header Values used by various EVM Opcodes. This is not a complete BlockHeader, just the * values that are returned or accessed by various operations. */ public interface BlockValues { diff --git a/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java b/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java index a71838e22b7..15ea57dccc5 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java @@ -17,8 +17,11 @@ import static com.google.common.base.Preconditions.checkState; import static java.util.Collections.emptySet; +import org.hyperledger.besu.collections.undo.UndoSet; +import org.hyperledger.besu.collections.undo.UndoTable; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.evm.Code; import org.hyperledger.besu.evm.code.CodeSection; @@ -31,6 +34,7 @@ import org.hyperledger.besu.evm.operation.Operation; import org.hyperledger.besu.evm.worldstate.WorldUpdater; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.HashMap; @@ -41,7 +45,9 @@ import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; +import com.google.common.base.Suppliers; import com.google.common.collect.HashBasedTable; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; @@ -55,7 +61,7 @@ * A container object for all the states associated with a message. * *

    A message corresponds to an interaction between two accounts. A Transaction spawns at least - * one message when its processed. Messages can also spawn messages depending on the code executed + * one message when it's processed. Messages can also spawn messages depending on the code executed * within a message. * *

    Note that there is no specific Message object in the code base. Instead, message executions @@ -199,58 +205,48 @@ public enum Type { // Metadata fields. private final Type type; - private State state; + private State state = State.NOT_STARTED; // Machine state fields. private long gasRemaining; - private final Function blockHashLookup; - private final int maxStackSize; private int pc; - private int section; - private final Memory memory; + private int section = 0; + private final Memory memory = new Memory(); private final OperandStack stack; - private final ReturnStack returnStack; - private Bytes output; - private Bytes returnData; + private final Supplier returnStack; + private Bytes output = Bytes.EMPTY; + private Bytes returnData = Bytes.EMPTY; private final boolean isStatic; - // Transaction substate fields. - private final List logs; - private long gasRefund; - private final Set

    selfDestructs; - private final Map refunds; - private final Set
    warmedUpAddresses; - private final Multimap warmedUpStorage; + // Transaction state fields. + private final List logs = new ArrayList<>(); + private long gasRefund = 0L; + private final Map refunds = new HashMap<>(); // Execution Environment fields. private final Address recipient; - private final Address originator; private final Address contract; - private final Wei gasPrice; private final Bytes inputData; private final Address sender; private final Wei value; private final Wei apparentValue; private final Code code; - private final BlockValues blockValues; - private final int depth; - private final MessageFrame parentMessageFrame; - private final Deque messageFrameStack; - private final Address miningBeneficiary; + private Optional revertReason; private final Map contextVariables; - private final Optional> versionedHashes; - - private final Table transientStorage = HashBasedTable.create(); - // Miscellaneous fields. private Optional exceptionalHaltReason = Optional.empty(); private Operation currentOperation; private final Consumer completer; private Optional maybeUpdatedMemory = Optional.empty(); private Optional maybeUpdatedStorage = Optional.empty(); + private final TxValues txValues; + + /** The mark of the undoable collections at the creation of this message frame */ + private final long undoMark; + /** * Builder builder. * @@ -262,86 +258,47 @@ public static Builder builder() { private MessageFrame( final Type type, - final Deque messageFrameStack, final WorldUpdater worldUpdater, final long initialGas, final Address recipient, - final Address originator, final Address contract, - final Wei gasPrice, final Bytes inputData, final Address sender, final Wei value, final Wei apparentValue, final Code code, - final BlockValues blockValues, - final int depth, final boolean isStatic, final Consumer completer, - final Address miningBeneficiary, - final Function blockHashLookup, final Map contextVariables, final Optional revertReason, - final int maxStackSize, - final Set
    accessListWarmAddresses, - final Multimap accessListWarmStorage, - final Optional> versionedHashes) { + final TxValues txValues) { + + this.txValues = txValues; this.type = type; - this.messageFrameStack = messageFrameStack; - this.parentMessageFrame = messageFrameStack.peek(); this.worldUpdater = worldUpdater; this.gasRemaining = initialGas; - this.blockHashLookup = blockHashLookup; - this.maxStackSize = maxStackSize; - this.pc = 0; - this.section = 0; - this.memory = new Memory(); - this.stack = new OperandStack(maxStackSize); - this.returnStack = new ReturnStack(); - returnStack.push(new ReturnStack.ReturnStackItem(0, 0, 0)); - pc = code.isValid() ? code.getCodeSection(0).getEntryPoint() : 0; - this.output = Bytes.EMPTY; - this.returnData = Bytes.EMPTY; - this.logs = new ArrayList<>(); - this.gasRefund = 0L; - this.selfDestructs = new HashSet<>(); - this.refunds = new HashMap<>(); + this.stack = new OperandStack(txValues.maxStackSize()); + this.returnStack = + Suppliers.memoize( + () -> { + var rStack = new ReturnStack(); + rStack.push(new ReturnStack.ReturnStackItem(0, 0, 0)); + return rStack; + }); + this.pc = code.isValid() ? code.getCodeSection(0).getEntryPoint() : 0; this.recipient = recipient; - this.originator = originator; this.contract = contract; - this.gasPrice = gasPrice; this.inputData = inputData; this.sender = sender; this.value = value; this.apparentValue = apparentValue; this.code = code; - this.blockValues = blockValues; - this.depth = depth; - this.state = State.NOT_STARTED; this.isStatic = isStatic; this.completer = completer; - this.miningBeneficiary = miningBeneficiary; this.contextVariables = contextVariables; this.revertReason = revertReason; - this.warmedUpAddresses = new HashSet<>(accessListWarmAddresses); - this.warmedUpAddresses.add(sender); - this.warmedUpAddresses.add(contract); - this.warmedUpStorage = HashMultimap.create(accessListWarmStorage); - this.versionedHashes = versionedHashes; - - // the warmed up addresses will always be a superset of the address keys in the warmed up - // storage, so we can do both warm-ups in one pass - accessListWarmAddresses.forEach( - address -> - Optional.ofNullable(worldUpdater.get(address)) - .ifPresent( - account -> - warmedUpStorage - .get(address) - .forEach( - storageKeyBytes -> - account.getStorageValue(UInt256.fromBytes(storageKeyBytes))))); + this.undoMark = txValues.transientStorage().mark(); } /** @@ -390,13 +347,14 @@ public ExceptionalHaltReason callFunction(final int calledSection) { CodeSection info = code.getCodeSection(calledSection); if (info == null) { return ExceptionalHaltReason.CODE_SECTION_MISSING; - } else if (stack.size() + info.getMaxStackHeight() > maxStackSize) { + } else if (stack.size() + info.getMaxStackHeight() > txValues.maxStackSize()) { return ExceptionalHaltReason.TOO_MANY_STACK_ITEMS; } else if (stack.size() < info.getInputs()) { return ExceptionalHaltReason.TOO_FEW_INPUTS_FOR_CODE_SECTION; } else { - returnStack.push( - new ReturnStack.ReturnStackItem(section, pc + 2, stack.size() - info.getInputs())); + returnStack + .get() + .push(new ReturnStack.ReturnStackItem(section, pc + 2, stack.size() - info.getInputs())); pc = info.getEntryPoint() - 1; // will be +1ed at end of operations loop this.section = calledSection; return null; @@ -404,10 +362,10 @@ public ExceptionalHaltReason callFunction(final int calledSection) { } /** - * Jump function exceptional halt reason. + * Execute the mechanics of the JUMPF operation. * * @param section the section - * @return the exceptional halt reason + * @return the exceptional halt reason, if the jump failed */ public ExceptionalHaltReason jumpFunction(final int section) { CodeSection info = code.getCodeSection(section); @@ -429,10 +387,11 @@ public ExceptionalHaltReason jumpFunction(final int section) { */ public ExceptionalHaltReason returnFunction() { CodeSection thisInfo = code.getCodeSection(this.section); - var returnInfo = returnStack.pop(); + var rStack = returnStack.get(); + var returnInfo = rStack.pop(); if ((returnInfo.getStackHeight() + thisInfo.getOutputs()) != stack.size()) { return ExceptionalHaltReason.INCORRECT_CODE_SECTION_RETURN_OUTPUTS; - } else if (returnStack.isEmpty()) { + } else if (rStack.isEmpty()) { setState(MessageFrame.State.CODE_SUCCESS); setOutputData(Bytes.EMPTY); return null; @@ -596,7 +555,7 @@ public int stackSize() { * @return The current return stack size */ public int returnStackSize() { - return returnStack.size(); + return returnStack.get().size(); } /** @@ -605,7 +564,7 @@ public int returnStackSize() { * @return The top item of the return stack, or null if the stack is empty */ public ReturnStack.ReturnStackItem peekReturnStack() { - return returnStack.peek(); + return returnStack.get().peek(); } /** @@ -614,7 +573,7 @@ public ReturnStack.ReturnStackItem peekReturnStack() { * @param returnStackItem item to be pushed */ public void pushReturnStackItem(final ReturnStack.ReturnStackItem returnStackItem) { - returnStack.push(returnStackItem); + returnStack.get().push(returnStackItem); } /** @@ -945,7 +904,7 @@ public long getGasRefund() { * @param address The recipient to self-destruct */ public void addSelfDestruct(final Address address) { - selfDestructs.add(address); + txValues.selfDestructs().add(address); } /** @@ -954,12 +913,7 @@ public void addSelfDestruct(final Address address) { * @param addresses The addresses to self-destruct */ public void addSelfDestructs(final Set
    addresses) { - selfDestructs.addAll(addresses); - } - - /** Removes all entries in the self-destruct set. */ - public void clearSelfDestructs() { - selfDestructs.clear(); + txValues.selfDestructs().addAll(addresses); } /** @@ -968,7 +922,46 @@ public void clearSelfDestructs() { * @return the self-destruct set */ public Set
    getSelfDestructs() { - return selfDestructs; + return txValues.selfDestructs(); + } + + /** + * Add recipient to the create set if not already present. + * + * @param address The recipient to create + */ + public void addCreate(final Address address) { + txValues.creates().add(address); + } + /** + * Add addresses to the create set if they are not already present. + * + * @param addresses The addresses to create + */ + public void addCreates(final Set
    addresses) { + txValues.creates().addAll(addresses); + } + + /** + * Returns the create set. + * + * @return the create set + */ + public Set
    getCreates() { + return txValues.creates(); + } + + /** + * Was the account at this address created in this transaction? (in any of the previously executed + * message frames in this transaction). + * + * @param address the address to check + * @return true if the account was created in any parent or prior message frame in this + * transaction. False if the account existed in the world state at the beginning of the + * transaction. + */ + public boolean wasCreatedInTransaction(final Address address) { + return txValues.creates().contains((address)); } /** @@ -997,22 +990,7 @@ public Map getRefunds() { * @return true if the address was already warmed up */ public boolean warmUpAddress(final Address address) { - if (warmedUpAddresses.add(address)) { - return parentMessageFrame != null && parentMessageFrame.isWarm(address); - } else { - return true; - } - } - - private boolean isWarm(final Address address) { - MessageFrame frame = this; - while (frame != null) { - if (frame.warmedUpAddresses.contains(address)) { - return true; - } - frame = frame.parentMessageFrame; - } - return false; + return !txValues.warmedUpAddresses().add(address); } /** @@ -1023,36 +1001,7 @@ private boolean isWarm(final Address address) { * @return true if the storage slot was already warmed up */ public boolean warmUpStorage(final Address address, final Bytes32 slot) { - if (warmedUpStorage.put(address, slot)) { - return parentMessageFrame != null && parentMessageFrame.isWarm(address, slot); - } else { - return true; - } - } - - private boolean isWarm(final Address address, final Bytes32 slot) { - MessageFrame frame = this; - while (frame != null) { - if (frame.warmedUpStorage.containsEntry(address, slot)) { - return true; - } - frame = frame.parentMessageFrame; - } - return false; - } - - /** - * Merge warmed up fields. - * - * @param childFrame the child frame - */ - public void mergeWarmedUpFields(final MessageFrame childFrame) { - if (childFrame == this) { - return; - } - - warmedUpAddresses.addAll(childFrame.warmedUpAddresses); - warmedUpStorage.putAll(childFrame.warmedUpStorage); + return txValues.warmedUpStorage().put(address, slot, Boolean.TRUE) != null; } /** @@ -1119,21 +1068,29 @@ public Address getRecipientAddress() { } /** - * Returns the message stack depth. + * Returns the message stack size. * - * @return the message stack depth + * @return the message stack size */ - public int getMessageStackDepth() { - return depth; + public int getMessageStackSize() { + return txValues.messageFrameStack().size(); } + /** + * Returns the Call Depth, where the rootmost call is depth 0 + * + * @return the call depth + */ + public int getDepth() { + return getMessageStackSize() - 1; + } /** * Returns the recipient that originated the message. * * @return the recipient that originated the message */ public Address getOriginatorAddress() { - return originator; + return txValues.originator(); } /** @@ -1151,7 +1108,7 @@ public Address getContractAddress() { * @return the current gas price */ public Wei getGasPrice() { - return gasPrice; + return txValues.gasPrice(); } /** @@ -1187,7 +1144,7 @@ public Wei getApparentValue() { * @return the current block header */ public BlockValues getBlockValues() { - return blockValues; + return txValues.blockValues(); } /** Performs updates based on the message frame's execution. */ @@ -1201,7 +1158,7 @@ public void notifyCompletion() { * @return the current message frame stack */ public Deque getMessageFrameStack() { - return messageFrameStack; + return txValues.messageFrameStack(); } /** @@ -1229,7 +1186,7 @@ public Optional getExceptionalHaltReason() { * @return the current mining beneficiary */ public Address getMiningBeneficiary() { - return miningBeneficiary; + return txValues.miningBeneficiary(); } /** @@ -1238,7 +1195,7 @@ public Address getMiningBeneficiary() { * @return the block hash lookup */ public Function getBlockHashLookup() { - return blockHashLookup; + return txValues.blockHashLookup(); } /** @@ -1256,7 +1213,7 @@ public Operation getCurrentOperation() { * @return the max stack size */ public int getMaxStackSize() { - return maxStackSize; + return txValues.maxStackSize(); } /** @@ -1308,8 +1265,8 @@ public void setCurrentOperation(final Operation currentOperation) { * * @return the warmed up storage */ - public Multimap getWarmedUpStorage() { - return warmedUpStorage; + public Table getWarmedUpStorage() { + return txValues.warmedUpStorage(); } /** @@ -1338,21 +1295,8 @@ public Optional getMaybeUpdatedStorage() { * @return the data value read */ public Bytes32 getTransientStorageValue(final Address accountAddress, final Bytes32 slot) { - Bytes32 data = transientStorage.get(accountAddress, slot); - - if (data != null) { - return data; - } - - if (parentMessageFrame != null) { - data = parentMessageFrame.getTransientStorageValue(accountAddress, slot); - } - if (data == null) { - data = Bytes32.ZERO; - } - transientStorage.put(accountAddress, slot, data); - - return data; + Bytes32 v = txValues.transientStorage().get(accountAddress, slot); + return v == null ? Bytes32.ZERO : v; } /** @@ -1364,14 +1308,12 @@ public Bytes32 getTransientStorageValue(final Address accountAddress, final Byte */ public void setTransientStorageValue( final Address accountAddress, final Bytes32 slot, final Bytes32 value) { - transientStorage.put(accountAddress, slot, value); + txValues.transientStorage().put(accountAddress, slot, value); } - /** Writes the transient storage to the parent frame, if one exists */ - public void commitTransientStorage() { - if (parentMessageFrame != null) { - parentMessageFrame.transientStorage.putAll(transientStorage); - } + /** Undo all the changes done by this message frame, such as when a revert is called for. */ + public void rollback() { + txValues.undoChanges(undoMark); } /** @@ -1379,8 +1321,8 @@ public void commitTransientStorage() { * * @return optional list of hashes */ - public Optional> getVersionedHashes() { - return versionedHashes; + public Optional> getVersionedHashes() { + return txValues.versionedHashes(); } /** Reset. */ @@ -1392,8 +1334,8 @@ public void reset() { /** The MessageFrame Builder. */ public static class Builder { + private MessageFrame parentMessageFrame; private Type type; - private Deque messageFrameStack; private WorldUpdater worldUpdater; private Long initialGas; private Address address; @@ -1406,7 +1348,6 @@ public static class Builder { private Wei apparentValue; private Code code; private BlockValues blockValues; - private int depth = -1; private int maxStackSize = DEFAULT_MAX_STACK_SIZE; private boolean isStatic = false; private Consumer completer; @@ -1417,27 +1358,28 @@ public static class Builder { private Set
    accessListWarmAddresses = emptySet(); private Multimap accessListWarmStorage = HashMultimap.create(); - private Optional> versionedHashes; + private Optional> versionedHashes = Optional.empty(); /** - * Sets Type. + * The "parent" message frame. When present some fields will be populated from the parent and + * ignored if passed in via builder * - * @param type the type + * @param parentMessageFrame the parent message frame * @return the builder */ - public Builder type(final Type type) { - this.type = type; + public Builder parentMessageFrame(final MessageFrame parentMessageFrame) { + this.parentMessageFrame = parentMessageFrame; return this; } /** - * Sets Message frame stack. + * Sets Type. * - * @param messageFrameStack the message frame stack + * @param type the type * @return the builder */ - public Builder messageFrameStack(final Deque messageFrameStack) { - this.messageFrameStack = messageFrameStack; + public Builder type(final Type type) { + this.type = type; return this; } @@ -1573,17 +1515,6 @@ public Builder blockValues(final BlockValues blockValues) { return this; } - /** - * Sets Depth. - * - * @param depth the depth - * @return the builder - */ - public Builder depth(final int depth) { - this.depth = depth; - return this; - } - /** * Sets Is static. * @@ -1689,30 +1620,30 @@ public Builder accessListWarmStorage(final Multimap accessList * @param versionedHashes the Optional list of versioned hashes * @return the builder */ - public Builder versionedHashes(final Optional> versionedHashes) { + public Builder versionedHashes(final Optional> versionedHashes) { this.versionedHashes = versionedHashes; return this; } private void validate() { + if (parentMessageFrame == null) { + checkState(worldUpdater != null, "Missing message frame world updater"); + checkState(originator != null, "Missing message frame originator"); + checkState(gasPrice != null, "Missing message frame getGasRemaining price"); + checkState(blockValues != null, "Missing message frame block header"); + checkState(miningBeneficiary != null, "Missing mining beneficiary"); + checkState(blockHashLookup != null, "Missing block hash lookup"); + } checkState(type != null, "Missing message frame type"); - checkState(messageFrameStack != null, "Missing message frame message frame stack"); - checkState(worldUpdater != null, "Missing message frame world updater"); checkState(initialGas != null, "Missing message frame initial getGasRemaining"); checkState(address != null, "Missing message frame recipient"); - checkState(originator != null, "Missing message frame originator"); checkState(contract != null, "Missing message frame contract"); - checkState(gasPrice != null, "Missing message frame getGasRemaining price"); checkState(inputData != null, "Missing message frame input data"); checkState(sender != null, "Missing message frame sender"); checkState(value != null, "Missing message frame value"); checkState(apparentValue != null, "Missing message frame apparent value"); checkState(code != null, "Missing message frame code"); - checkState(blockValues != null, "Missing message frame block header"); - checkState(depth > -1, "Missing message frame depth"); checkState(completer != null, "Missing message frame completer"); - checkState(miningBeneficiary != null, "Missing mining beneficiary"); - checkState(blockHashLookup != null, "Missing block hash lookup"); } /** @@ -1723,32 +1654,60 @@ private void validate() { public MessageFrame build() { validate(); - return new MessageFrame( - type, - messageFrameStack, - worldUpdater, - initialGas, - address, - originator, - contract, - gasPrice, - inputData, - sender, - value, - apparentValue, - code, - blockValues, - depth, - isStatic, - completer, - miningBeneficiary, - blockHashLookup, - contextVariables == null ? Map.of() : contextVariables, - reason, - maxStackSize, - accessListWarmAddresses, - accessListWarmStorage, - versionedHashes); + WorldUpdater updater; + boolean newStatic; + TxValues newTxValues; + if (parentMessageFrame == null) { + newTxValues = + new TxValues( + blockHashLookup, + maxStackSize, + UndoSet.of(new HashSet<>()), + UndoTable.of(HashBasedTable.create()), + originator, + gasPrice, + blockValues, + new ArrayDeque<>(), + miningBeneficiary, + versionedHashes, + UndoTable.of(HashBasedTable.create()), + UndoSet.of(new HashSet<>()), + UndoSet.of(new HashSet<>())); + updater = worldUpdater; + newStatic = isStatic; + } else { + newTxValues = parentMessageFrame.txValues; + updater = parentMessageFrame.worldUpdater.updater(); + newStatic = isStatic || parentMessageFrame.isStatic; + } + + MessageFrame messageFrame = + new MessageFrame( + type, + updater, + initialGas, + address, + contract, + inputData, + sender, + value, + apparentValue, + code, + newStatic, + completer, + contextVariables == null ? Map.of() : contextVariables, + reason, + newTxValues); + newTxValues.messageFrameStack().addFirst(messageFrame); + messageFrame.warmUpAddress(sender); + messageFrame.warmUpAddress(contract); + for (Address a : accessListWarmAddresses) { + messageFrame.warmUpAddress(a); + } + for (var e : accessListWarmStorage.entries()) { + messageFrame.warmUpStorage(e.getKey(), e.getValue()); + } + return messageFrame; } } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/frame/TxValues.java b/evm/src/main/java/org/hyperledger/besu/evm/frame/TxValues.java new file mode 100644 index 00000000000..65f7f47b569 --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/frame/TxValues.java @@ -0,0 +1,63 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evm.frame; + +import org.hyperledger.besu.collections.undo.UndoSet; +import org.hyperledger.besu.collections.undo.UndoTable; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.VersionedHash; +import org.hyperledger.besu.datatypes.Wei; + +import java.util.Deque; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + +import org.apache.tuweni.bytes.Bytes32; + +/** + * Transaction Values used by various EVM Opcodes. These are the values that either do not change or + * the backing stores whose changes transcend message frames and are not part of state, such as + * transient storage and address warming. + */ +public record TxValues( + Function blockHashLookup, + int maxStackSize, + UndoSet
    warmedUpAddresses, + UndoTable warmedUpStorage, + Address originator, + Wei gasPrice, + BlockValues blockValues, + Deque messageFrameStack, + Address miningBeneficiary, + Optional> versionedHashes, + UndoTable transientStorage, + UndoSet
    creates, + UndoSet
    selfDestructs) { + + /** + * For all data stored in this record, undo the changes since the mark. + * + * @param mark the mark to which it should be rolled back to + */ + public void undoChanges(final long mark) { + warmedUpAddresses.undo(mark); + warmedUpStorage.undo(mark); + transientStorage.undo(mark); + creates.undo(mark); + selfDestructs.undo(mark); + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java index b78e765cc8b..4e58f05d29b 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java @@ -14,21 +14,43 @@ */ package org.hyperledger.besu.evm.gascalculator; +import static org.hyperledger.besu.datatypes.Address.KZG_POINT_EVAL; + /** * Gas Calculator for Cancun * *
      *
    • Gas costs for TSTORE/TLOAD - *
    • Data gas for EIP-4844 + *
    • Blob gas for EIP-4844 *
    */ -public class CancunGasCalculator extends LondonGasCalculator { +public class CancunGasCalculator extends ShanghaiGasCalculator { + + /** Instantiates a new Cancun Gas Calculator. */ + public CancunGasCalculator() { + this(KZG_POINT_EVAL.toArrayUnsafe()[19]); + } + + /** + * Instantiates a new Cancun Gas Calculator + * + * @param maxPrecompile the max precompile + */ + private CancunGasCalculator(final int maxPrecompile) { + super(maxPrecompile); + } private static final long TLOAD_GAS = WARM_STORAGE_READ_COST; private static final long TSTORE_GAS = WARM_STORAGE_READ_COST; - private static final long DATA_GAS_PER_BLOB = 1 << 17; - private static final long TARGET_DATA_GAS_PER_BLOCK = 1 << 18; + /** + * The blob gas cost per blob. This is the gas cost for each blob of blob that is added to the + * block. + */ + public static final long BLOB_GAS_PER_BLOB = 1 << 17; + + /** The target blob gas per block. */ + public static final long TARGET_BLOB_GAS_PER_BLOCK = 0x60000; // EIP-1153 @Override @@ -42,18 +64,47 @@ public long getTransientStoreOperationGasCost() { } @Override - public long dataGasCost(final int blobCount) { - return DATA_GAS_PER_BLOB * blobCount; + public long blobGasCost(final int blobCount) { + return BLOB_GAS_PER_BLOB * blobCount; + } + + /** + * Retrieves the target blob gas per block. + * + * @return The target blob gas per block. + */ + public long getTargetBlobGasPerBlock() { + return TARGET_BLOB_GAS_PER_BLOCK; + } + + /** + * Computes the excess blob gas for a given block based on the parent's excess blob gas and blob + * gas used. If the sum of parent's excess blob gas and parent's blob gas used is less than the + * target blob gas per block, the excess blob gas is calculated as 0. Otherwise, it is computed as + * the difference between the sum and the target blob gas per block. + * + * @param parentExcessBlobGas The excess blob gas of the parent block. + * @param newBlobs blob gas incurred by current block + * @return The excess blob gas for the current block. + */ + @Override + public long computeExcessBlobGas(final long parentExcessBlobGas, final int newBlobs) { + final long consumedBlobGas = blobGasCost(newBlobs); + final long currentExcessBlobGas = parentExcessBlobGas + consumedBlobGas; + + if (currentExcessBlobGas < TARGET_BLOB_GAS_PER_BLOCK) { + return 0L; + } + return currentExcessBlobGas - TARGET_BLOB_GAS_PER_BLOCK; } @Override - public long computeExcessDataGas(final long parentExcessDataGas, final int newBlobs) { - final long consumedDataGas = dataGasCost(newBlobs); - final long currentExcessDataGas = parentExcessDataGas + consumedDataGas; + public long computeExcessBlobGas(final long parentExcessBlobGas, final long blobGasUsed) { + final long currentExcessBlobGas = parentExcessBlobGas + blobGasUsed; - if (currentExcessDataGas < TARGET_DATA_GAS_PER_BLOCK) { + if (currentExcessBlobGas < TARGET_BLOB_GAS_PER_BLOCK) { return 0L; } - return currentExcessDataGas - TARGET_DATA_GAS_PER_BLOCK; + return currentExcessBlobGas - TARGET_BLOB_GAS_PER_BLOCK; } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java index 5356475f175..daab215faa6 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java @@ -526,19 +526,30 @@ default long getTransientStoreOperationGasCost() { * @param blobCount the number of blobs * @return the total gas cost */ - default long dataGasCost(final int blobCount) { + default long blobGasCost(final int blobCount) { return 0L; } /** - * Compute the new value for the excess data gas, given the parent value and the count of new + * Compute the new value for the excess blob gas, given the parent value and the count of new * blobs * - * @param parentExcessDataGas excess data gas from the parent + * @param parentExcessBlobGas excess blob gas from the parent * @param newBlobs count of new blobs - * @return the new excess data gas value + * @return the new excess blob gas value */ - default long computeExcessDataGas(final long parentExcessDataGas, final int newBlobs) { + default long computeExcessBlobGas(final long parentExcessBlobGas, final int newBlobs) { + return 0L; + } + + /** + * Compute the new value for the excess blob gas, given the parent value and the blob gas used + * + * @param parentExcessBlobGas excess blob gas from the parent + * @param blobGasUsed blob gas used + * @return the new excess blob gas value + */ + default long computeExcessBlobGas(final long parentExcessBlobGas, final long blobGasUsed) { return 0L; } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/LondonGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/LondonGasCalculator.java index 69336414542..9687e89c80f 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/LondonGasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/LondonGasCalculator.java @@ -29,6 +29,20 @@ public class LondonGasCalculator extends BerlinGasCalculator { // redefinitions for EIP-3529 private static final int NEW_MAX_REFUND_QUOTIENT = 5; + /** + * Instantiates a new LondonGasCalculator + * + * @param maxPrecompile the max precompile + */ + protected LondonGasCalculator(final int maxPrecompile) { + super(maxPrecompile); + } + + /** Instantiates a new LondonGasCalculator */ + public LondonGasCalculator() { + super(); + } + // Redefined refund amount from EIP-3529 @Override public long getSelfDestructRefundAmount() { diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/ShanghaiGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/ShanghaiGasCalculator.java index ce764b58524..e3c8c43928c 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/ShanghaiGasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/ShanghaiGasCalculator.java @@ -25,6 +25,20 @@ public class ShanghaiGasCalculator extends LondonGasCalculator { private static final long INIT_CODE_COST = 2L; + /** + * Instantiates a new ShanghaiGasCalculator + * + * @param maxPrecompile the max precompile + */ + protected ShanghaiGasCalculator(final int maxPrecompile) { + super(maxPrecompile); + } + + /** Instantiates a new ShanghaiGasCalculator */ + public ShanghaiGasCalculator() { + super(); + } + @Override public long transactionIntrinsicGasCost(final Bytes payload, final boolean isContractCreation) { long intrinsicGasCost = super.transactionIntrinsicGasCost(payload, isContractCreation); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java index 529754905aa..64cb42757ea 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java @@ -178,7 +178,7 @@ public OperationResult execute(final MessageFrame frame, final EVM evm) { final Wei balance = account == null ? Wei.ZERO : account.getBalance(); // If the call is sending more value than the account has or the message frame is to deep // return a failed call - if (value(frame).compareTo(balance) > 0 || frame.getMessageStackDepth() >= 1024) { + if (value(frame).compareTo(balance) > 0 || frame.getDepth() >= 1024) { frame.expandMemory(inputDataOffset(frame), inputDataLength(frame)); frame.expandMemory(outputDataOffset(frame), outputDataLength(frame)); frame.incrementRemainingGas(gasAvailableForChildCall(frame) + cost); @@ -195,32 +195,23 @@ public OperationResult execute(final MessageFrame frame, final EVM evm) { : evm.getCode(contract.getCodeHash(), contract.getCode()); if (code.isValid()) { - final MessageFrame childFrame = - MessageFrame.builder() - .type(MessageFrame.Type.MESSAGE_CALL) - .messageFrameStack(frame.getMessageFrameStack()) - .worldUpdater(frame.getWorldUpdater().updater()) - .initialGas(gasAvailableForChildCall(frame)) - .address(address(frame)) - .originator(frame.getOriginatorAddress()) - .contract(to) - .gasPrice(frame.getGasPrice()) - .inputData(inputData) - .sender(sender(frame)) - .value(value(frame)) - .apparentValue(apparentValue(frame)) - .code(code) - .blockValues(frame.getBlockValues()) - .depth(frame.getMessageStackDepth() + 1) - .isStatic(isStatic(frame)) - .completer(child -> complete(frame, child)) - .miningBeneficiary(frame.getMiningBeneficiary()) - .blockHashLookup(frame.getBlockHashLookup()) - .maxStackSize(frame.getMaxStackSize()) - .build(); + // frame addition is automatically handled by parent messageFrameStack + MessageFrame.builder() + .parentMessageFrame(frame) + .type(MessageFrame.Type.MESSAGE_CALL) + .initialGas(gasAvailableForChildCall(frame)) + .address(address(frame)) + .contract(to) + .inputData(inputData) + .sender(sender(frame)) + .value(value(frame)) + .apparentValue(apparentValue(frame)) + .code(code) + .isStatic(isStatic(frame)) + .completer(child -> complete(frame, child)) + .build(); frame.incrementRemainingGas(cost); - frame.getMessageFrameStack().addFirst(childFrame); frame.setState(MessageFrame.State.CODE_SUSPENDED); return new OperationResult(cost, null, 0); } else { @@ -259,6 +250,7 @@ public void complete(final MessageFrame frame, final MessageFrame childFrame) { frame.setReturnData(outputData); frame.addLogs(childFrame.getLogs()); frame.addSelfDestructs(childFrame.getSelfDestructs()); + frame.addCreates(childFrame.getCreates()); frame.incrementGasRefund(childFrame.getGasRefund()); final long gasRemaining = childFrame.getRemainingGas(); @@ -266,7 +258,6 @@ public void complete(final MessageFrame frame, final MessageFrame childFrame) { frame.popStackItems(getStackItemsConsumed()); if (childFrame.getState() == MessageFrame.State.COMPLETED_SUCCESS) { - frame.mergeWarmedUpFields(childFrame); frame.pushStackItem(SUCCESS_STACK_ITEM); } else { frame.pushStackItem(FAILURE_STACK_ITEM); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java index 5ea9737299f..50ced6fd8b7 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java @@ -22,11 +22,14 @@ import org.hyperledger.besu.evm.EVM; import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.code.CodeFactory; +import org.hyperledger.besu.evm.code.CodeInvalid; import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.gascalculator.GasCalculator; import org.hyperledger.besu.evm.internal.Words; +import java.util.Optional; + import org.apache.tuweni.bytes.Bytes; /** The Abstract create operation. */ @@ -87,7 +90,7 @@ public OperationResult execute(final MessageFrame frame, final EVM evm) { } if (value.compareTo(account.getBalance()) > 0 - || frame.getMessageStackDepth() >= 1024 + || frame.getDepth() >= 1024 || account.getNonce() == -1) { fail(frame); } else { @@ -134,40 +137,32 @@ private void fail(final MessageFrame frame) { frame.pushStackItem(FAILURE_STACK_ITEM); } - private void spawnChildMessage(final MessageFrame frame, final Code code, final EVM evm) { - final Wei value = Wei.wrap(frame.getStackItem(0)); + private void spawnChildMessage(final MessageFrame parent, final Code code, final EVM evm) { + final Wei value = Wei.wrap(parent.getStackItem(0)); - final Address contractAddress = targetContractAddress(frame); + final Address contractAddress = targetContractAddress(parent); + parent.addCreate(contractAddress); final long childGasStipend = - gasCalculator().gasAvailableForChildCreate(frame.getRemainingGas()); - frame.decrementRemainingGas(childGasStipend); - - final MessageFrame childFrame = - MessageFrame.builder() - .type(MessageFrame.Type.CONTRACT_CREATION) - .messageFrameStack(frame.getMessageFrameStack()) - .worldUpdater(frame.getWorldUpdater().updater()) - .initialGas(childGasStipend) - .address(contractAddress) - .originator(frame.getOriginatorAddress()) - .contract(contractAddress) - .gasPrice(frame.getGasPrice()) - .inputData(Bytes.EMPTY) - .sender(frame.getRecipientAddress()) - .value(value) - .apparentValue(value) - .code(code) - .blockValues(frame.getBlockValues()) - .depth(frame.getMessageStackDepth() + 1) - .completer(child -> complete(frame, child, evm)) - .miningBeneficiary(frame.getMiningBeneficiary()) - .blockHashLookup(frame.getBlockHashLookup()) - .maxStackSize(frame.getMaxStackSize()) - .build(); - - frame.getMessageFrameStack().addFirst(childFrame); - frame.setState(MessageFrame.State.CODE_SUSPENDED); + gasCalculator().gasAvailableForChildCreate(parent.getRemainingGas()); + parent.decrementRemainingGas(childGasStipend); + + // frame addition is automatically handled by parent messageFrameStack + MessageFrame.builder() + .parentMessageFrame(parent) + .type(MessageFrame.Type.CONTRACT_CREATION) + .initialGas(childGasStipend) + .address(contractAddress) + .contract(contractAddress) + .inputData(Bytes.EMPTY) + .sender(parent.getRecipientAddress()) + .value(value) + .apparentValue(value) + .code(code) + .completer(child -> complete(parent, child, evm)) + .build(); + + parent.setState(MessageFrame.State.CODE_SUSPENDED); } private void complete(final MessageFrame frame, final MessageFrame childFrame, final EVM evm) { @@ -181,22 +176,61 @@ private void complete(final MessageFrame frame, final MessageFrame childFrame, f frame.incrementRemainingGas(childFrame.getRemainingGas()); frame.addLogs(childFrame.getLogs()); frame.addSelfDestructs(childFrame.getSelfDestructs()); + frame.addCreates(childFrame.getCreates()); frame.incrementGasRefund(childFrame.getGasRefund()); if (childFrame.getState() == MessageFrame.State.COMPLETED_SUCCESS) { - frame.mergeWarmedUpFields(childFrame); - frame.pushStackItem(Words.fromAddress(childFrame.getContractAddress())); + Address createdAddress = childFrame.getContractAddress(); + frame.pushStackItem(Words.fromAddress(createdAddress)); + onSuccess(frame, createdAddress); } else { frame.setReturnData(childFrame.getOutputData()); frame.pushStackItem(FAILURE_STACK_ITEM); + onFailure(frame, childFrame.getExceptionalHaltReason()); } } else { frame.getWorldUpdater().deleteAccount(childFrame.getRecipientAddress()); frame.setReturnData(childFrame.getOutputData()); frame.pushStackItem(FAILURE_STACK_ITEM); + onInvalid(frame, (CodeInvalid) outputCode); } final int currentPC = frame.getPC(); frame.setPC(currentPC + 1); } + + /** + * Called when the child {@code CONTRACT_CREATION} message has completed successfully, used to + * give library users a chance to do implementation specific logic. + * + * @param frame the frame running the successful operation + * @param createdAddress the address of the newly created contract + */ + protected void onSuccess(final MessageFrame frame, final Address createdAddress) { + // no-op by default + } + + /** + * Called when the child {@code CONTRACT_CREATION} message has failed to execute, used to give + * library users a chance to do implementation specific logic. + * + * @param frame the frame running the successful operation + * @param haltReason the exceptional halt reason of the child frame + */ + protected void onFailure( + final MessageFrame frame, final Optional haltReason) { + // no-op by default + } + + /** + * Called when the child {@code CONTRACT_CREATION} message has completed successfully but the + * returned contract is invalid per chain rules, used to give library users a chance to do + * implementation specific logic. + * + * @param frame the frame running the successful operation + * @param invalidCode the code object containing the invalid code + */ + protected void onInvalid(final MessageFrame frame, final CodeInvalid invalidCode) { + // no-op by default + } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/DataHashOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/BlobHashOperation.java similarity index 60% rename from evm/src/main/java/org/hyperledger/besu/evm/operation/DataHashOperation.java rename to evm/src/main/java/org/hyperledger/besu/evm/operation/BlobHashOperation.java index eda3f5dfd4e..3fe212b8b35 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/DataHashOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/BlobHashOperation.java @@ -14,46 +14,52 @@ */ package org.hyperledger.besu.evm.operation; -import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.evm.EVM; import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.gascalculator.GasCalculator; import java.util.List; -import java.util.Optional; import org.apache.tuweni.bytes.Bytes; /** - * The DataHash operation. https://eips.ethereum.org/EIPS/eip-4844 + * The BlobHash operation. As specified in EIP-4844 * *

    Reads index from the top of the stack as big-endian uint256, and replaces it on the stack with * tx.message.blob_versioned_hashes[index] if index < len(tx.message.blob_versioned_hashes), and * otherwise with a zeroed bytes32 value. */ -public class DataHashOperation extends AbstractOperation { +public class BlobHashOperation extends AbstractOperation { - /** DATAHASH opcode number */ + /** BLOBHASH opcode number */ public static final int OPCODE = 0x49; /** - * Instantiates a new DataHash operation. + * Instantiates a new BlobHash operation. * * @param gasCalculator the gas calculator */ - public DataHashOperation(final GasCalculator gasCalculator) { - super(OPCODE, "DATAHASH", 1, 1, gasCalculator); + public BlobHashOperation(final GasCalculator gasCalculator) { + super(OPCODE, "BLOBHASH", 1, 1, gasCalculator); } @Override public OperationResult execute(final MessageFrame frame, final EVM evm) { - int blobIndex = frame.popStackItem().toInt(); - final Optional> maybeHashes = frame.getVersionedHashes(); + Bytes versionedHashIndexParam = frame.popStackItem(); if (frame.getVersionedHashes().isPresent()) { - List versionedHashes = maybeHashes.get(); - if (blobIndex < versionedHashes.size()) { - Hash requested = versionedHashes.get(blobIndex); - frame.pushStackItem(requested); + List versionedHashes = frame.getVersionedHashes().get(); + Bytes trimmedIndex = versionedHashIndexParam.trimLeadingZeros(); + if (trimmedIndex.size() > 4) { + // won't fit in an int + frame.pushStackItem(Bytes.EMPTY); + return new OperationResult(3, null); + } + int versionedHashIndex = trimmedIndex.toInt(); + if (versionedHashIndex < versionedHashes.size() && versionedHashIndex >= 0) { + VersionedHash requested = versionedHashes.get(versionedHashIndex); + frame.pushStackItem(requested.toBytes()); } else { frame.pushStackItem(Bytes.EMPTY); } @@ -62,9 +68,4 @@ public OperationResult execute(final MessageFrame frame, final EVM evm) { } return new OperationResult(3, null); } - - @Override - public boolean isVirtualOperation() { - return super.isVirtualOperation(); - } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/SelfDestructOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/SelfDestructOperation.java index e0e5a728293..98807652034 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/SelfDestructOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/SelfDestructOperation.java @@ -27,54 +27,77 @@ /** The Self destruct operation. */ public class SelfDestructOperation extends AbstractOperation { + final boolean eip6780Semantics; + /** * Instantiates a new Self destruct operation. * * @param gasCalculator the gas calculator */ public SelfDestructOperation(final GasCalculator gasCalculator) { + this(gasCalculator, false); + } + + /** + * Instantiates a new Self destruct operation, with an optional EIP-6780 semantics flag. EIP-6780 + * will only remove an account if the account was created within the current transaction. All + * other semantics remain. + * + * @param gasCalculator the gas calculator + * @param eip6780Semantics Enforce EIP6780 semantics. + */ + public SelfDestructOperation(final GasCalculator gasCalculator, final boolean eip6780Semantics) { super(0xFF, "SELFDESTRUCT", 1, 0, gasCalculator); + this.eip6780Semantics = eip6780Semantics; } @Override public OperationResult execute(final MessageFrame frame, final EVM evm) { - final Address recipientAddress = Words.toAddress(frame.popStackItem()); - - // because of weird EIP150/158 reasons we care about a null account, so we can't merge this. - final Account recipientNullable = frame.getWorldUpdater().get(recipientAddress); - final Wei inheritance = frame.getWorldUpdater().get(frame.getRecipientAddress()).getBalance(); + // First calculate cost. There's a bit of yak shaving getting values to calculate the cost. + final Address beneficiaryAddress = Words.toAddress(frame.popStackItem()); + // Because of weird EIP150/158 reasons we care about a null account, so we can't merge this. + final Account beneficiaryNullable = frame.getWorldUpdater().get(beneficiaryAddress); + final boolean beneficiaryIsWarm = + frame.warmUpAddress(beneficiaryAddress) || gasCalculator().isPrecompile(beneficiaryAddress); - final boolean accountIsWarm = - frame.warmUpAddress(recipientAddress) || gasCalculator().isPrecompile(recipientAddress); + final Address originatorAddress = frame.getRecipientAddress(); + final Wei originatorBalance = frame.getWorldUpdater().get(originatorAddress).getBalance(); final long cost = - gasCalculator().selfDestructOperationGasCost(recipientNullable, inheritance) - + (accountIsWarm ? 0L : gasCalculator().getColdAccountAccessCost()); + gasCalculator().selfDestructOperationGasCost(beneficiaryNullable, originatorBalance) + + (beneficiaryIsWarm ? 0L : gasCalculator().getColdAccountAccessCost()); + // With the cost we can test for two early exits: static or not enough gas. if (frame.isStatic()) { return new OperationResult(cost, ExceptionalHaltReason.ILLEGAL_STATE_CHANGE); } else if (frame.getRemainingGas() < cost) { return new OperationResult(cost, ExceptionalHaltReason.INSUFFICIENT_GAS); } - final Address address = frame.getRecipientAddress(); - final MutableAccount account = frame.getWorldUpdater().getAccount(address).getMutable(); - - frame.addSelfDestruct(address); + // We passed preliminary checks, get mutable accounts. + final MutableAccount originatorAccount = + frame.getWorldUpdater().getAccount(originatorAddress).getMutable(); + final MutableAccount beneficiaryAccount = + frame.getWorldUpdater().getOrCreate(beneficiaryAddress).getMutable(); - final MutableAccount recipient = - frame.getWorldUpdater().getOrCreate(recipientAddress).getMutable(); + // Do the "sweep," all modes send all originator balance to the beneficiary account. + originatorAccount.decrementBalance(originatorBalance); + beneficiaryAccount.incrementBalance(originatorBalance); - if (!account.getAddress().equals(recipient.getAddress())) { - recipient.incrementBalance(account.getBalance()); + // If we are actually destroying the originator (pre-Cancun or same-tx-create) we need to + // explicitly zero out the account balance (destroying ether/value if the originator is the + // beneficiary) as well as tag it for later self-destruct cleanup. + if (!eip6780Semantics || frame.wasCreatedInTransaction(originatorAddress)) { + frame.addSelfDestruct(originatorAddress); + originatorAccount.setBalance(Wei.ZERO); } - // add refund in message frame - frame.addRefund(recipient.getAddress(), account.getBalance()); - - account.setBalance(Wei.ZERO); + // Add refund in message frame. + frame.addRefund(beneficiaryAddress, originatorBalance); + // Set frame to CODE_SUCCESS so that the frame performs a normal halt. frame.setState(MessageFrame.State.CODE_SUCCESS); + return new OperationResult(cost, null); } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/precompile/AbstractAltBnPrecompiledContract.java b/evm/src/main/java/org/hyperledger/besu/evm/precompile/AbstractAltBnPrecompiledContract.java index c44e4822ad0..c02b484eb27 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/precompile/AbstractAltBnPrecompiledContract.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/precompile/AbstractAltBnPrecompiledContract.java @@ -40,12 +40,22 @@ public abstract class AbstractAltBnPrecompiledContract extends AbstractPrecompil static boolean useNative; static { + maybeEnableNative(); + } + + /** + * Attempt to enable the native library for AltBn contracts + * + * @return true if the native library was enabled. + */ + public static boolean maybeEnableNative() { try { useNative = LibEthPairings.ENABLED; - } catch (UnsatisfiedLinkError ule) { + } catch (UnsatisfiedLinkError | NoClassDefFoundError ule) { LOG.info("altbn128 native precompile not available: {}", ule.getMessage()); useNative = false; } + return useNative; } /** Disable native. */ diff --git a/evm/src/main/java/org/hyperledger/besu/evm/precompile/BigIntegerModularExponentiationPrecompiledContract.java b/evm/src/main/java/org/hyperledger/besu/evm/precompile/BigIntegerModularExponentiationPrecompiledContract.java index 1520947960a..669edc78103 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/precompile/BigIntegerModularExponentiationPrecompiledContract.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/precompile/BigIntegerModularExponentiationPrecompiledContract.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.evm.precompile; +import static org.hyperledger.besu.evm.internal.Words.clampedAdd; import static org.hyperledger.besu.evm.internal.Words.clampedMultiply; import static org.hyperledger.besu.evm.internal.Words.clampedToInt; import static org.hyperledger.besu.evm.internal.Words.clampedToLong; @@ -44,15 +45,6 @@ public class BigIntegerModularExponentiationPrecompiledContract /** Use native Arithmetic libraries. */ static boolean useNative; - static { - try { - useNative = LibArithmetic.ENABLED; - } catch (UnsatisfiedLinkError | NoClassDefFoundError ule) { - LOG.info("modexp native precompile not available: {}", ule.getMessage()); - useNative = false; - } - } - /** The constant BASE_OFFSET. */ public static final int BASE_OFFSET = 96; @@ -75,6 +67,21 @@ public static void disableNative() { useNative = false; } + /** + * Attempt to enable the native library for ModExp + * + * @return true if the native library was enabled. + */ + public static boolean maybeEnableNative() { + try { + useNative = LibArithmetic.ENABLED; + } catch (UnsatisfiedLinkError | NoClassDefFoundError ule) { + LOG.info("modexp native precompile not available: {}", ule.getMessage()); + useNative = false; + } + return useNative; + } + /** * Check if native Arithmetic libraries are enabled. * @@ -148,9 +155,9 @@ public static long multiplicationComplexity(final long x) { if (x <= 64) { return square(x); } else if (x <= 1024) { - return (square(x) / 4) + (x * 96) - 3072; + return clampedAdd((square(x) / 4), clampedMultiply(x, 96)) - 3072; } else { - return (square(x) / 16) + (480 * x) - 199680; + return clampedAdd((square(x) / 16), clampedMultiply(480, x)) - 199680; } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/precompile/ECRECPrecompiledContract.java b/evm/src/main/java/org/hyperledger/besu/evm/precompile/ECRECPrecompiledContract.java index 07e05bfb801..ad99945cffc 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/precompile/ECRECPrecompiledContract.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/precompile/ECRECPrecompiledContract.java @@ -35,14 +35,26 @@ public class ECRECPrecompiledContract extends AbstractPrecompiledContract { private static final int V_BASE = 27; - + final SignatureAlgorithm signatureAlgorithm; /** - * Instantiates a new ECREC precompiled contract. + * Instantiates a new ECREC precompiled contract with the default signature algorithm. * * @param gasCalculator the gas calculator */ public ECRECPrecompiledContract(final GasCalculator gasCalculator) { + this(gasCalculator, SignatureAlgorithmFactory.getInstance()); + } + + /** + * Configure a new ECRecover precompile with a specific signature algorith and gas. + * + * @param gasCalculator the gas calculator + * @param signatureAlgorithm the algoritm (such as secp256k1 or secp256r1) + */ + public ECRECPrecompiledContract( + final GasCalculator gasCalculator, final SignatureAlgorithm signatureAlgorithm) { super("ECREC", gasCalculator); + this.signatureAlgorithm = signatureAlgorithm; } @Override @@ -68,7 +80,6 @@ public PrecompileContractResult computePrecompile( final int recId = d.get(63) - V_BASE; final BigInteger r = d.slice(64, 32).toUnsignedBigInteger(); final BigInteger s = d.slice(96, 32).toUnsignedBigInteger(); - final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance(); final SECPSignature signature; try { diff --git a/evm/src/main/java/org/hyperledger/besu/evm/precompile/KZGPointEvalPrecompiledContract.java b/evm/src/main/java/org/hyperledger/besu/evm/precompile/KZGPointEvalPrecompiledContract.java index ed1a3c94332..78171b720f0 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/precompile/KZGPointEvalPrecompiledContract.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/precompile/KZGPointEvalPrecompiledContract.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.evm.precompile; +import org.hyperledger.besu.crypto.Hash; import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.internal.Words; @@ -102,45 +103,41 @@ public PrecompileContractResult computePrecompile( final Bytes input, @NotNull final MessageFrame messageFrame) { if (input.size() != 192) { - return new PrecompileContractResult( - Bytes.EMPTY, - false, - MessageFrame.State.COMPLETED_FAILED, - Optional.of(ExceptionalHaltReason.PRECOMPILE_ERROR)); + return PrecompileContractResult.halt( + null, Optional.of(ExceptionalHaltReason.PRECOMPILE_ERROR)); } + Bytes32 versionedHash = Bytes32.wrap(input.slice(0, 32)); Bytes z = input.slice(32, 32); Bytes y = input.slice(64, 32); Bytes commitment = input.slice(96, 48); Bytes proof = input.slice(144, 48); - - PrecompileContractResult result; + if (versionedHash.get(0) != 0x01) { // unsupported hash version + return PrecompileContractResult.halt( + null, Optional.of(ExceptionalHaltReason.PRECOMPILE_ERROR)); + } else { + byte[] hash = Hash.sha256(commitment).toArray(); + hash[0] = 0x01; + if (!versionedHash.equals(Bytes32.wrap(hash))) { + return PrecompileContractResult.halt( + null, Optional.of(ExceptionalHaltReason.PRECOMPILE_ERROR)); + } + } try { boolean proved = CKZG4844JNI.verifyKzgProof( commitment.toArray(), z.toArray(), y.toArray(), proof.toArray()); if (proved) { - result = - new PrecompileContractResult( - successResult, false, MessageFrame.State.COMPLETED_SUCCESS, Optional.empty()); + return PrecompileContractResult.success(successResult); } else { - result = - new PrecompileContractResult( - Bytes.EMPTY, - false, - MessageFrame.State.COMPLETED_FAILED, - Optional.of(ExceptionalHaltReason.PRECOMPILE_ERROR)); + return PrecompileContractResult.halt( + null, Optional.of(ExceptionalHaltReason.PRECOMPILE_ERROR)); } - return result; } catch (RuntimeException kzgFailed) { System.out.println(kzgFailed.getMessage()); - result = - new PrecompileContractResult( - Bytes.EMPTY, - false, - MessageFrame.State.COMPLETED_FAILED, - Optional.of(ExceptionalHaltReason.PRECOMPILE_ERROR)); + + return PrecompileContractResult.halt( + null, Optional.of(ExceptionalHaltReason.PRECOMPILE_ERROR)); } - return result; } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/processor/AbstractMessageProcessor.java b/evm/src/main/java/org/hyperledger/besu/evm/processor/AbstractMessageProcessor.java index d2b1c99688d..22d466e17d9 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/processor/AbstractMessageProcessor.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/processor/AbstractMessageProcessor.java @@ -115,8 +115,9 @@ private void clearAccumulatedStateBesidesGasAndOutput(final MessageFrame frame) frame.getWorldUpdater().commit(); frame.clearLogs(); - frame.clearSelfDestructs(); frame.clearGasRefund(); + + frame.rollback(); } /** @@ -148,7 +149,6 @@ protected void revert(final MessageFrame frame) { */ private void completedSuccess(final MessageFrame frame) { frame.getWorldUpdater().commit(); - frame.commitTransientStorage(); frame.getMessageFrameStack().removeFirst(); frame.notifyCompletion(); } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/processor/ContractCreationProcessor.java b/evm/src/main/java/org/hyperledger/besu/evm/processor/ContractCreationProcessor.java index 87c0c3bd120..17fa4da60b8 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/processor/ContractCreationProcessor.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/processor/ContractCreationProcessor.java @@ -111,12 +111,13 @@ public void start(final MessageFrame frame, final OperationTracer operationTrace final MutableAccount sender = frame.getWorldUpdater().getSenderAccount(frame).getMutable(); sender.decrementBalance(frame.getValue()); + Address contractAddress = frame.getContractAddress(); final MutableAccount contract = - frame.getWorldUpdater().getOrCreate(frame.getContractAddress()).getMutable(); + frame.getWorldUpdater().getOrCreate(contractAddress).getMutable(); if (accountExists(contract)) { LOG.trace( "Contract creation error: account has already been created for address {}", - frame.getContractAddress()); + contractAddress); frame.setExceptionalHaltReason(Optional.of(ExceptionalHaltReason.INSUFFICIENT_GAS)); frame.setState(MessageFrame.State.EXCEPTIONAL_HALT); operationTracer.traceAccountCreationResult( @@ -126,6 +127,7 @@ public void start(final MessageFrame frame, final OperationTracer operationTrace contract.setNonce(initialContractNonce); contract.clearStorage(); frame.setState(MessageFrame.State.CODE_EXECUTING); + frame.addCreate(contractAddress); } } catch (final ModificationNotAllowedException ex) { LOG.trace("Contract creation error: attempt to mutate an immutable account"); @@ -175,6 +177,9 @@ public void codeSuccess(final MessageFrame frame, final OperationTracer operatio contractCode.size(), frame.getRemainingGas()); frame.setState(MessageFrame.State.COMPLETED_SUCCESS); + if (operationTracer.isExtendedTracing()) { + operationTracer.traceAccountCreationResult(frame, Optional.empty()); + } } else { final Optional exceptionalHaltReason = invalidReason.get(); frame.setExceptionalHaltReason(exceptionalHaltReason); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/tracing/AccessListOperationTracer.java b/evm/src/main/java/org/hyperledger/besu/evm/tracing/AccessListOperationTracer.java index 703b0cec122..f466b443fba 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/tracing/AccessListOperationTracer.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/tracing/AccessListOperationTracer.java @@ -22,13 +22,13 @@ import java.util.ArrayList; import java.util.List; -import com.google.common.collect.Multimap; +import com.google.common.collect.Table; import org.apache.tuweni.bytes.Bytes32; /** The Access List Operation Tracer. */ public class AccessListOperationTracer extends EstimateGasOperationTracer { - private Multimap warmedUpStorage; + private Table warmedUpStorage; @Override public void tracePostExecution(final MessageFrame frame, final OperationResult operationResult) { @@ -36,9 +36,6 @@ public void tracePostExecution(final MessageFrame frame, final OperationResult o warmedUpStorage = frame.getWarmedUpStorage(); } - @Override - public void tracePreExecution(final MessageFrame frame) {} - /** * Get the access list. * @@ -46,12 +43,12 @@ public void tracePreExecution(final MessageFrame frame) {} */ public List getAccessList() { final List list = new ArrayList<>(); - if (warmedUpStorage != null) { + if (warmedUpStorage != null && !warmedUpStorage.isEmpty()) { warmedUpStorage - .asMap() + .rowMap() .forEach( (address, storageKeys) -> - list.add(new AccessListEntry(address, new ArrayList<>(storageKeys)))); + list.add(new AccessListEntry(address, new ArrayList<>(storageKeys.keySet())))); } return list; } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/tracing/EstimateGasOperationTracer.java b/evm/src/main/java/org/hyperledger/besu/evm/tracing/EstimateGasOperationTracer.java index a9ac495a176..c7b11620311 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/tracing/EstimateGasOperationTracer.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/tracing/EstimateGasOperationTracer.java @@ -27,12 +27,12 @@ public class EstimateGasOperationTracer implements OperationTracer { @Override public void tracePostExecution(final MessageFrame frame, final OperationResult operationResult) { - if (frame.getCurrentOperation() instanceof SStoreOperation && sStoreStipendNeeded == 0L) { - sStoreStipendNeeded = - ((SStoreOperation) frame.getCurrentOperation()).getMinimumGasRemaining(); + if (frame.getCurrentOperation() instanceof SStoreOperation sStoreOperation + && sStoreStipendNeeded == 0L) { + sStoreStipendNeeded = sStoreOperation.getMinimumGasRemaining(); } - if (maxDepth < frame.getMessageStackDepth()) { - maxDepth = frame.getMessageStackDepth(); + if (maxDepth < frame.getDepth()) { + maxDepth = frame.getDepth(); } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/tracing/OperationTracer.java b/evm/src/main/java/org/hyperledger/besu/evm/tracing/OperationTracer.java index d278d1d7832..26862134fb9 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/tracing/OperationTracer.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/tracing/OperationTracer.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.evm.tracing; +import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.operation.Operation.OperationResult; @@ -63,6 +64,13 @@ default void tracePrecompileCall( default void traceAccountCreationResult( final MessageFrame frame, final Optional haltReason) {} + /** + * Trace the start of a transaction. + * + * @param transaction the transaction which will be processed + */ + default void traceStartTransaction(final Transaction transaction) {} + /** * Trace the end of a transaction. * @@ -71,4 +79,13 @@ default void traceAccountCreationResult( * @param timeNs the time in nanoseconds it took to execute the transaction */ default void traceEndTransaction(final Bytes output, final long gasUsed, final long timeNs) {} + + /** + * Returns a boolean indicating whether extended tracing is enabled. + * + * @return true if extended tracing is enabled, false otherwise. + */ + default boolean isExtendedTracing() { + return false; + } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/tracing/StandardJsonTracer.java b/evm/src/main/java/org/hyperledger/besu/evm/tracing/StandardJsonTracer.java index 3db7c38e116..5dbc99dd0cf 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/tracing/StandardJsonTracer.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/tracing/StandardJsonTracer.java @@ -48,6 +48,7 @@ public class StandardJsonTracer implements OperationTracer { private String gas; private Bytes memory; private int memorySize; + private int depth; /** * Instantiates a new Standard json tracer. @@ -125,6 +126,7 @@ public void tracePreExecution(final MessageFrame messageFrame) { } else { memory = null; } + depth = messageFrame.getMessageStackSize(); } @Override @@ -133,7 +135,6 @@ public void tracePostExecution( final Operation currentOp = messageFrame.getCurrentOperation(); final int opcode = currentOp.getOpcode(); final Bytes returnData = messageFrame.getReturnData(); - final int depth = messageFrame.getMessageStackDepth() + 1; final StringBuilder sb = new StringBuilder(1024); sb.append("{"); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/UpdateTrackingAccount.java b/evm/src/main/java/org/hyperledger/besu/evm/worldstate/UpdateTrackingAccount.java index e1121171ccc..865ab0b9b02 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/UpdateTrackingAccount.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/worldstate/UpdateTrackingAccount.java @@ -73,7 +73,7 @@ public class UpdateTrackingAccount implements MutableAccount, UpdateTrackingAccount(final Address address) { checkNotNull(address); this.address = address; - this.addressHash = Hash.hash(this.address); + this.addressHash = this.address.addressHash(); this.account = null; this.nonce = 0; @@ -95,7 +95,7 @@ public UpdateTrackingAccount(final A account) { this.addressHash = (account instanceof UpdateTrackingAccount) ? ((UpdateTrackingAccount) account).addressHash - : Hash.hash(this.address); + : this.address.addressHash(); this.account = account; this.nonce = account.getNonce(); @@ -243,7 +243,6 @@ public UInt256 getOriginalStorageValue(final UInt256 key) { } @Override - @SuppressWarnings("unchecked") public NavigableMap storageEntriesFrom( final Bytes32 startKeyHash, final int limit) { final NavigableMap entries; diff --git a/evm/src/test/java/org/hyperledger/besu/collections/undo/UndoListTest.java b/evm/src/test/java/org/hyperledger/besu/collections/undo/UndoListTest.java new file mode 100644 index 00000000000..1ca96c470a8 --- /dev/null +++ b/evm/src/test/java/org/hyperledger/besu/collections/undo/UndoListTest.java @@ -0,0 +1,383 @@ +/* + * Copyright contributors to Hyperledger Besu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ +package org.hyperledger.besu.collections.undo; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Set; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class UndoListTest { + UndoList subject; + + @BeforeEach + void createUndoMap() { + final List set = new ArrayList<>(); + subject = new UndoList<>(set); + } + + @Test + void markMovesForward() { + long mark = subject.mark(); + + subject.add("Hello"); + assertThat(subject.mark()).isGreaterThan(mark); + + mark = subject.mark(); + subject.add("Hello"); + assertThat(subject.mark()).isGreaterThan(mark); + + mark = subject.mark(); + subject.add("There"); + assertThat(subject.mark()).isGreaterThan(mark); + } + + @Test + void markOnlyMovesOnWrite() { + long mark; + subject.add("Hello"); + + mark = subject.mark(); + subject.add("Hi"); + assertThat(subject.mark()).isGreaterThan(mark); + + mark = subject.mark(); + subject.undo(mark); + assertThat(subject.mark()).isEqualTo(mark); + + mark = subject.mark(); + subject.add("Hello"); + assertThat(subject.mark()).isGreaterThan(mark); + + mark = subject.mark(); + subject.undo(mark); + assertThat(subject.mark()).isEqualTo(mark); + + mark = subject.mark(); + // no actions + assertThat(subject.mark()).isEqualTo(mark); + + mark = subject.mark(); + subject.remove("Hi"); + assertThat(subject.mark()).isGreaterThan(mark); + + mark = subject.mark(); + // non-changing undo does not advance mark + subject.undo(mark); + assertThat(subject.mark()).isEqualTo(mark); + + mark = subject.mark(); + // non-existent remove doesn't advance mark + subject.remove("Bonjour"); + assertThat(subject.mark()).isEqualTo(mark); + + mark = subject.mark(); + subject.clear(); + assertThat(subject.mark()).isGreaterThan(mark); + } + + @Test + void sizeAdjustsWithUndo() { + assertThat(subject).isEmpty(); + + subject.add("Hello"); + long mark1 = subject.mark(); + assertThat(subject).hasSize(1); + + subject.add("Hello"); + long mark2 = subject.mark(); + assertThat(subject).hasSize(2); + + subject.remove(0); + assertThat(subject).hasSize(1); + + subject.remove("Hello"); + assertThat(subject).isEmpty(); + + subject.undo(mark2); + assertThat(subject).hasSize(2); + + subject.undo(mark1); + assertThat(subject).hasSize(1); + + subject.undo(0); + assertThat(subject).isEmpty(); + } + + @Test + void checkUndoContents() { + long mark0 = subject.mark(); + subject.add("foo"); + long level1 = subject.mark(); + subject.add("baz"); + long level2 = subject.mark(); + subject.add(1, "qux"); + long level3 = subject.mark(); + subject.add("foo"); + long level4 = subject.mark(); + subject.add(2, "foo"); + long level5 = subject.mark(); + subject.add("foo"); + long level6 = subject.mark(); + subject.remove("foo"); + long level7 = subject.mark(); + subject.add("foo"); + long level8 = subject.mark(); + subject.set(3, "qux"); + long level9 = subject.mark(); + subject.clear(); + + assertThat(subject).isEmpty(); + + subject.undo(level9); + assertThat(subject).containsExactly("qux", "foo", "baz", "qux", "foo", "foo"); + + subject.undo(level8); + assertThat(subject).containsExactly("qux", "foo", "baz", "foo", "foo", "foo"); + + subject.undo(level7); + assertThat(subject).containsExactly("qux", "foo", "baz", "foo", "foo"); + + subject.undo(level6); + assertThat(subject).containsExactly("foo", "qux", "foo", "baz", "foo", "foo"); + + subject.undo(level5); + assertThat(subject).containsExactly("foo", "qux", "foo", "baz", "foo"); + + subject.undo(level4); + assertThat(subject).containsExactly("foo", "qux", "baz", "foo"); + + subject.undo(level3); + assertThat(subject).containsExactly("foo", "qux", "baz"); + + subject.undo(level2); + assertThat(subject).containsExactly("foo", "baz"); + + subject.undo(level1); + assertThat(subject).containsExactly("foo"); + + subject.undo(mark0); + assertThat(subject).isEmpty(); + } + + @Test + void addAll() { + subject.add("foo"); + + long mark = subject.mark(); + subject.addAll(List.of("Alpha", "Charlie")); + assertThat(subject).containsExactly("foo", "Alpha", "Charlie"); + + long mark2 = subject.mark(); + subject.addAll(2, List.of("foo", "bar")); + assertThat(subject).containsExactly("foo", "Alpha", "foo", "bar", "Charlie"); + + subject.undo(mark2); + assertThat(subject).containsExactly("foo", "Alpha", "Charlie"); + + subject.undo(mark); + assertThat(subject).containsExactly("foo"); + } + + @Test + void removeAll() { + subject.add("foo"); + subject.add("bar"); + subject.add("baz"); + subject.add("qux"); + subject.add("foo"); + + long mark = subject.mark(); + subject.removeAll(Set.of("bar", "baz")); + + assertThat(subject).containsExactly("foo", "qux", "foo"); + + subject.undo(mark); + assertThat(subject).containsExactly("foo", "bar", "baz", "qux", "foo"); + } + + @Test + void retainAll() { + subject.add("foo"); + subject.add("bar"); + subject.add("baz"); + subject.add("qux"); + subject.add("foo"); + + long mark = subject.mark(); + subject.retainAll(Set.of("bar", "baz")); + + assertThat(subject).containsExactly("bar", "baz"); + + subject.undo(mark); + assertThat(subject).containsExactly("foo", "bar", "baz", "qux", "foo"); + } + + @SuppressWarnings(("java:S5838")) // direct use of contains and containsAll need to be tested here + @Test + void contains() { + subject.add("one"); + long mark1 = subject.mark(); + subject.add("three"); + + assertThat(subject).containsOnly("one", "three"); + + subject.undo(mark1); + assertThat(subject).containsOnly("one"); + + subject.add("three"); + long mark2 = subject.mark(); + subject.remove("three"); + assertThat(subject).containsOnly("one"); + + subject.undo(mark2); + assertThat(subject).containsOnly("one", "three"); + + assertThat(subject.contains("one")).isTrue(); + assertThat(subject.contains("two")).isFalse(); + assertThat(subject.containsAll(Set.of("one", "three"))).isTrue(); + assertThat(subject.containsAll(Set.of("one", "two"))).isFalse(); + } + + @Test + void toArray() { + subject.add("foo"); + subject.add("bar"); + long mark = subject.mark(); + subject.add("baz"); + subject.add("qux"); + + String[] generated = subject.toArray(String[]::new); + //noinspection RedundantCast + assertThat(subject.toArray()).containsExactlyInAnyOrder((Object[]) generated); + + subject.undo(mark); + + assertThat(subject.toArray(new String[2])) + .containsExactlyInAnyOrder(subject.toArray(new String[0])); + } + + @SuppressWarnings("JdkObsolete") + @Test + void equalityTests() { + subject.add("Hello"); + long mark = subject.mark(); + subject.add("Hello"); + subject.add("Bonjour"); + subject.undo(mark); + + UndoList second = new UndoList<>(new LinkedList<>()); + second.add("Hello"); + + assertThat(subject).hasSameHashCodeAs(second).isEqualTo(second); + } + + @SuppressWarnings("JdkObsolete") + @Test + void globalMark() { + subject.add("Hello"); + UndoList second = new UndoList<>(new LinkedList<>()); + + second.add("Hello"); + // assert that a mark gathered from another undoSet works in another undoSet + long mark = second.mark(); + + subject.add("Hello"); + subject.add("Bonjour"); + subject.undo(mark); + + assertThat(subject).hasSameHashCodeAs(second).isEqualTo(second); + } + + @Test + void reading() { + subject.add("foo"); + subject.add("bar"); + long mark = subject.mark(); + subject.set(1, "bif"); + subject.add(1, "baz"); + subject.add("qux"); + subject.add("foo"); + + System.out.println(subject); + + assertThat(subject.get(1)).isEqualTo("baz"); + assertThat(subject.get(2)).isEqualTo("bif"); + assertThat(subject.indexOf("foo")).isZero(); + assertThat(subject.lastIndexOf("foo")).isEqualTo(4); + assertThat(subject.lastIndexOf("bar")).isNegative(); + subject.undo(mark); + assertThat(subject.get(1)).isEqualTo("bar"); + assertThat(subject.indexOf("foo")).isZero(); + assertThat(subject.lastIndexOf("foo")).isZero(); + assertThat(subject.lastIndexOf("bif")).isNegative(); + } + + @Test + void sublist() { + subject.add("foo"); + subject.add("bar"); + long mark1 = subject.mark(); + subject.add("baz"); + subject.add("qux"); + subject.add("foo"); + + assertThat(subject.subList(1, 4)).containsExactly("bar", "baz", "qux"); + subject.undo(mark1); + subject.add("one"); + subject.add("two"); + assertThat(subject.subList(1, 4)).containsExactly("bar", "one", "two"); + } + + @Test + void listIterator() { + subject.add("foo"); + subject.add("bar"); + long mark1 = subject.mark(); + subject.add("baz"); + subject.add("qux"); + subject.add("foo"); + + ListIterator listIterator = subject.listIterator(); + assertThat(listIterator.hasPrevious()).isFalse(); + listIterator.next(); + listIterator.next(); + assertThat(listIterator.next()).isEqualTo("baz"); + + assertThatThrownBy(listIterator::remove) + .isExactlyInstanceOf(UnsupportedOperationException.class); + assertThatThrownBy(() -> listIterator.add("quux")) + .isExactlyInstanceOf(UnsupportedOperationException.class); + assertThatThrownBy(() -> listIterator.set("quux")) + .isExactlyInstanceOf(UnsupportedOperationException.class); + + assertThat(listIterator.previousIndex()).isEqualTo(2); + assertThat(listIterator.nextIndex()).isEqualTo(3); + assertThat(listIterator.previous()).isEqualTo("baz"); + + subject.undo(mark1); + ListIterator listIterator2 = subject.listIterator(1); + assertThat(listIterator2.next()).isEqualTo("bar"); + assertThat(listIterator2.hasNext()).isFalse(); + } +} diff --git a/evm/src/test/java/org/hyperledger/besu/collections/undo/UndoMapTest.java b/evm/src/test/java/org/hyperledger/besu/collections/undo/UndoMapTest.java new file mode 100644 index 00000000000..b2eb030eab9 --- /dev/null +++ b/evm/src/test/java/org/hyperledger/besu/collections/undo/UndoMapTest.java @@ -0,0 +1,269 @@ +/* + * Copyright contributors to Hyperledger Besu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ +package org.hyperledger.besu.collections.undo; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class UndoMapTest { + UndoMap subject; + + @BeforeEach + void createUndoMap() { + final Map map = new HashMap<>(); + subject = new UndoMap<>(map); + } + + @Test + void markMovesForward() { + long mark = subject.mark(); + + subject.put("Hello", "World"); + assertThat(subject.mark()).isGreaterThan(mark); + + mark = subject.mark(); + subject.put("Hello", "There"); + assertThat(subject.mark()).isGreaterThan(mark); + } + + @Test + void markOnlyMovesOnWrite() { + long mark; + subject.put("Hello", "World"); + + mark = subject.mark(); + subject.put("Hi", "There"); + assertThat(subject.mark()).isGreaterThan(mark); + + mark = subject.mark(); + subject.undo(mark); + assertThat(subject.mark()).isEqualTo(mark); + + mark = subject.mark(); + subject.put("Hello", "Again"); + assertThat(subject.mark()).isGreaterThan(mark); + + mark = subject.mark(); + subject.undo(mark); + assertThat(subject.mark()).isEqualTo(mark); + + mark = subject.mark(); + // no actions + assertThat(subject.mark()).isEqualTo(mark); + + mark = subject.mark(); + subject.remove("Hi"); + assertThat(subject.mark()).isGreaterThan(mark); + + subject.put("Bonjour", "Hi"); + + mark = subject.mark(); + // failed specified value remove does not advance mark + subject.remove("Bonjour", "Hello"); + assertThat(subject.mark()).isEqualTo(mark); + + mark = subject.mark(); + // non-changing undo does not advance mark + subject.undo(mark); + assertThat(subject.mark()).isEqualTo(mark); + + mark = subject.mark(); + // modifying change advances mark + subject.remove("Bonjour"); + subject.undo(mark); + assertThat(subject.mark()).isGreaterThan(mark); + + mark = subject.mark(); + subject.clear(); + assertThat(subject.mark()).isGreaterThan(mark); + } + + @Test + void sizeAdjustsWithUndo() { + assertThat(subject).isEmpty(); + + subject.put("Hello", "World"); + long mark1 = subject.mark(); + assertThat(subject).hasSize(1); + + subject.put("Hello", "There"); + long mark2 = subject.mark(); + assertThat(subject).hasSize(1); + + subject.remove("Hello"); + assertThat(subject).isEmpty(); + + subject.undo(mark2); + assertThat(subject).hasSize(1); + + subject.undo(mark1); + assertThat(subject).hasSize(1); + + subject.undo(0); + assertThat(subject).isEmpty(); + } + + @Test + void checkUndoContents() { + long mark0 = subject.mark(); + subject.put("foo", "bar"); + long level1 = subject.mark(); + subject.put("baz", "bif"); + long level2 = subject.mark(); + subject.put("qux", "quux"); + long level3 = subject.mark(); + subject.put("foo", "FEE"); + long level4 = subject.mark(); + subject.put("foo", "bar"); + long level5 = subject.mark(); + subject.put("foo", "FIE"); + long level6 = subject.mark(); + subject.remove("foo"); + long level7 = subject.mark(); + subject.put("foo", "FUM"); + long level8 = subject.mark(); + subject.put("qux", "quuux"); + long level9 = subject.mark(); + subject.clear(); + + assertThat(subject).isEmpty(); + + subject.undo(level9); + assertThat(subject) + .containsOnly(Map.entry("foo", "FUM"), Map.entry("baz", "bif"), Map.entry("qux", "quuux")); + + subject.undo(level8); + assertThat(subject) + .containsOnly(Map.entry("foo", "FUM"), Map.entry("baz", "bif"), Map.entry("qux", "quux")); + + subject.undo(level7); + assertThat(subject).containsOnly(Map.entry("baz", "bif"), Map.entry("qux", "quux")); + + subject.undo(level6); + assertThat(subject) + .containsOnly(Map.entry("foo", "FIE"), Map.entry("baz", "bif"), Map.entry("qux", "quux")); + + subject.undo(level5); + assertThat(subject) + .containsOnly(Map.entry("foo", "bar"), Map.entry("baz", "bif"), Map.entry("qux", "quux")); + + subject.undo(level4); + assertThat(subject) + .containsOnly(Map.entry("foo", "FEE"), Map.entry("baz", "bif"), Map.entry("qux", "quux")); + + subject.undo(level3); + assertThat(subject) + .containsOnly(Map.entry("foo", "bar"), Map.entry("baz", "bif"), Map.entry("qux", "quux")); + + subject.undo(level2); + assertThat(subject).containsOnly(Map.entry("foo", "bar"), Map.entry("baz", "bif")); + + subject.undo(level1); + assertThat(subject).containsOnly(Map.entry("foo", "bar")); + + subject.undo(mark0); + assertThat(subject).isEmpty(); + } + + @Test + void putAll() { + subject.put("foo", "bar"); + + long mark = subject.mark(); + subject.putAll(Map.of("Alpha", "Bravo", "Charlie", "Delta")); + assertThat(subject) + .containsOnly( + Map.entry("foo", "bar"), Map.entry("Alpha", "Bravo"), Map.entry("Charlie", "Delta")); + + subject.undo(mark); + assertThat(subject).containsOnly(Map.entry("foo", "bar")); + + mark = subject.mark(); + subject.putAll(Map.of("foo", "foo", "bar", "bar")); + assertThat(subject).containsOnly(Map.entry("foo", "foo"), Map.entry("bar", "bar")); + + subject.undo(mark); + assertThat(subject).containsOnly(Map.entry("foo", "bar")); + } + + @Test + void contains() { + subject.put("one", "two"); + long mark1 = subject.mark(); + subject.put("three", "four"); + + assertThat(subject).containsKey("three").containsValue("four").containsOnlyKeys("one", "three"); + assertThat(subject.values()).containsOnly("two", "four"); + + subject.undo(mark1); + assertThat(subject) + .doesNotContainKey("three") + .doesNotContainValue("four") + .containsOnlyKeys("one"); + assertThat(subject.values()).containsOnly("two"); + + subject.put("three", "four"); + long mark2 = subject.mark(); + subject.remove("three"); + assertThat(subject) + .doesNotContainKey("three") + .doesNotContainValue("four") + .containsOnlyKeys("one"); + assertThat(subject.values()).containsOnly("two"); + + subject.undo(mark2); + assertThat(subject).containsKey("three").containsValue("four").containsOnlyKeys("one", "three"); + assertThat(subject.values()).containsOnly("two", "four"); + } + + @Test + void equalityTests() { + subject.put("Hello", "There"); + long mark = subject.mark(); + subject.put("Hello", "World"); + subject.put("Bonjour", "Hi"); + subject.undo(mark); + + UndoMap second = new UndoMap<>(new TreeMap<>()); + second.put("Hello", "There"); + + assertThat(subject.keySet()).isEqualTo(second.keySet()); + assertThat(subject).hasSameHashCodeAs(second).isEqualTo(second); + } + + @Test + void globalMark() { + subject.put("Hello", "There"); + UndoMap second = new UndoMap<>(new TreeMap<>()); + + second.put("Hello", "There"); + // assert that a mark gathered from another undomap works in another undomap + long mark = second.mark(); + + subject.put("Hello", "World"); + subject.put("Bonjour", "Hi"); + subject.undo(mark); + + assertThat(subject.keySet()).isEqualTo(second.keySet()); + assertThat(subject).hasSameHashCodeAs(second).isEqualTo(second); + } +} diff --git a/evm/src/test/java/org/hyperledger/besu/collections/undo/UndoSetTest.java b/evm/src/test/java/org/hyperledger/besu/collections/undo/UndoSetTest.java new file mode 100644 index 00000000000..545cb68df12 --- /dev/null +++ b/evm/src/test/java/org/hyperledger/besu/collections/undo/UndoSetTest.java @@ -0,0 +1,301 @@ +/* + * Copyright contributors to Hyperledger Besu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ +package org.hyperledger.besu.collections.undo; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.HashSet; +import java.util.Set; +import java.util.TreeSet; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class UndoSetTest { + UndoSet subject; + + @BeforeEach + void createUndoSet() { + final Set set = new HashSet<>(); + subject = new UndoSet<>(set); + } + + @Test + void markMovesForward() { + long mark = subject.mark(); + + subject.add("Hello"); + assertThat(subject.mark()).isGreaterThan(mark); + + mark = subject.mark(); + subject.add("Hello"); + assertThat(subject.mark()).isEqualTo(mark); + + mark = subject.mark(); + subject.add("There"); + assertThat(subject.mark()).isGreaterThan(mark); + } + + @Test + void markOnlyMovesOnWrite() { + long mark; + subject.add("Hello"); + + mark = subject.mark(); + subject.add("Hi"); + assertThat(subject.mark()).isGreaterThan(mark); + + mark = subject.mark(); + subject.undo(mark); + assertThat(subject.mark()).isEqualTo(mark); + + mark = subject.mark(); + subject.add("Hello"); + assertThat(subject.mark()).isEqualTo(mark); + + mark = subject.mark(); + subject.undo(mark); + assertThat(subject.mark()).isEqualTo(mark); + + mark = subject.mark(); + // no actions + assertThat(subject.mark()).isEqualTo(mark); + + mark = subject.mark(); + subject.remove("Hi"); + assertThat(subject.mark()).isGreaterThan(mark); + + mark = subject.mark(); + // non-changing undo does not advance mark + subject.undo(mark); + assertThat(subject.mark()).isEqualTo(mark); + + mark = subject.mark(); + // non-existent remove doesn't advance mark + subject.remove("Bonjour"); + assertThat(subject.mark()).isEqualTo(mark); + + mark = subject.mark(); + subject.clear(); + assertThat(subject.mark()).isGreaterThan(mark); + } + + @Test + void sizeAdjustsWithUndo() { + assertThat(subject).isEmpty(); + + subject.add("Hello"); + long mark1 = subject.mark(); + assertThat(subject).hasSize(1); + + subject.add("Hello"); + long mark2 = subject.mark(); + assertThat(subject).hasSize(1); + + subject.remove("Hello"); + assertThat(subject).isEmpty(); + + subject.undo(mark2); + assertThat(subject).hasSize(1); + + subject.undo(mark1); + assertThat(subject).hasSize(1); + + subject.undo(0); + assertThat(subject).isEmpty(); + } + + @Test + void checkUndoContents() { + long mark0 = subject.mark(); + subject.add("foo"); + long level1 = subject.mark(); + subject.add("baz"); + long level2 = subject.mark(); + subject.add("qux"); + long level3 = subject.mark(); + subject.add("foo"); + long level4 = subject.mark(); + subject.add("foo"); + long level5 = subject.mark(); + subject.add("foo"); + long level6 = subject.mark(); + subject.remove("foo"); + long level7 = subject.mark(); + subject.add("foo"); + long level8 = subject.mark(); + subject.add("qux"); + long level9 = subject.mark(); + subject.clear(); + + assertThat(subject).isEmpty(); + + subject.undo(level9); + assertThat(subject).containsOnly("foo", "baz", "qux"); + + subject.undo(level8); + assertThat(subject).containsOnly("foo", "baz", "qux"); + + subject.undo(level7); + assertThat(subject).containsOnly("baz", "qux"); + + subject.undo(level6); + assertThat(subject).containsOnly("foo", "baz", "qux"); + + subject.undo(level5); + assertThat(subject).containsOnly("foo", "baz", "qux"); + + subject.undo(level4); + assertThat(subject).containsOnly("foo", "baz", "qux"); + + subject.undo(level3); + assertThat(subject).containsOnly("foo", "baz", "qux"); + + subject.undo(level2); + assertThat(subject).containsOnly("foo", "baz"); + + subject.undo(level1); + assertThat(subject).containsOnly("foo"); + + subject.undo(mark0); + assertThat(subject).isEmpty(); + } + + @Test + void addAll() { + subject.add("foo"); + + long mark = subject.mark(); + subject.addAll(Set.of("Alpha", "Charlie")); + assertThat(subject).containsOnly("foo", "Alpha", "Charlie"); + + subject.undo(mark); + assertThat(subject).containsOnly("foo"); + + mark = subject.mark(); + subject.addAll(Set.of("foo", "bar")); + assertThat(subject).containsOnly("foo", "bar"); + + subject.undo(mark); + assertThat(subject).containsOnly("foo"); + } + + @Test + void removeAll() { + subject.add("foo"); + subject.add("bar"); + subject.add("baz"); + subject.add("qux"); + + long mark = subject.mark(); + subject.removeAll(Set.of("bar", "baz")); + + assertThat(subject).containsOnly("foo", "qux"); + + subject.undo(mark); + assertThat(subject).containsOnly("foo", "bar", "baz", "qux"); + } + + @Test + void retainAll() { + subject.add("foo"); + subject.add("bar"); + subject.add("baz"); + subject.add("qux"); + + long mark = subject.mark(); + subject.retainAll(Set.of("bar", "baz")); + + assertThat(subject).containsOnly("bar", "baz"); + + subject.undo(mark); + assertThat(subject).containsOnly("foo", "bar", "baz", "qux"); + } + + @SuppressWarnings(("java:S5838")) // direct use of contains and containsAll need to be tested here + @Test + void contains() { + subject.add("one"); + long mark1 = subject.mark(); + subject.add("three"); + + assertThat(subject).containsOnly("one", "three"); + + assertThat(subject.contains("one")).isTrue(); + assertThat(subject.contains("two")).isFalse(); + assertThat(subject.containsAll(Set.of("one", "three"))).isTrue(); + assertThat(subject.containsAll(Set.of("one", "two"))).isFalse(); + + subject.undo(mark1); + assertThat(subject).containsOnly("one"); + + subject.add("three"); + long mark2 = subject.mark(); + subject.remove("three"); + assertThat(subject).containsOnly("one"); + + subject.undo(mark2); + assertThat(subject).containsOnly("one", "three"); + } + + @Test + void toArray() { + subject.add("foo"); + subject.add("bar"); + long mark = subject.mark(); + subject.add("baz"); + subject.add("qux"); + + String[] generated = subject.toArray(String[]::new); + //noinspection RedundantCast + assertThat(subject.toArray()).containsExactlyInAnyOrder((Object[]) generated); + + subject.undo(mark); + + assertThat(subject.toArray(new String[2])) + .containsExactlyInAnyOrder(subject.toArray(new String[0])); + } + + @Test + void equalityTests() { + subject.add("Hello"); + long mark = subject.mark(); + subject.add("Hello"); + subject.add("Bonjour"); + subject.undo(mark); + + UndoSet second = new UndoSet<>(new TreeSet<>()); + second.add("Hello"); + + assertThat(subject).hasSameHashCodeAs(second).isEqualTo(second); + } + + @Test + void globalMark() { + subject.add("Hello"); + UndoSet second = new UndoSet<>(new TreeSet<>()); + + second.add("Hello"); + // assert that a mark gathered from another undoSet works in another undoSet + long mark = second.mark(); + + subject.add("Hello"); + subject.add("Bonjour"); + subject.undo(mark); + + assertThat(subject).hasSameHashCodeAs(second).isEqualTo(second); + } +} diff --git a/evm/src/test/java/org/hyperledger/besu/evm/code/CodeV0Test.java b/evm/src/test/java/org/hyperledger/besu/evm/code/CodeV0Test.java index ff8014c10e7..07f0f17040c 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/code/CodeV0Test.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/code/CodeV0Test.java @@ -37,7 +37,6 @@ import org.hyperledger.besu.evm.operation.OperationRegistry; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import java.util.ArrayDeque; import javax.annotation.Nonnull; import org.apache.tuweni.bytes.Bytes; @@ -86,7 +85,6 @@ private MessageFrame createJumpFrame(final CodeV0 getsCached) { final MessageFrame frame = MessageFrame.builder() .type(MESSAGE_CALL) - .messageFrameStack(new ArrayDeque<>()) .worldUpdater(mock(WorldUpdater.class)) .initialGas(10_000L) .address(Address.ZERO) @@ -99,7 +97,6 @@ private MessageFrame createJumpFrame(final CodeV0 getsCached) { .apparentValue(Wei.ZERO) .code(getsCached) .blockValues(mock(BlockValues.class)) - .depth(0) .completer(f -> {}) .miningBeneficiary(Address.ZERO) .blockHashLookup(l -> Hash.EMPTY) diff --git a/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculatorTest.java b/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculatorTest.java new file mode 100644 index 00000000000..f8e53703b25 --- /dev/null +++ b/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculatorTest.java @@ -0,0 +1,46 @@ +/* + * Copyright Hyperledger Besu contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evm.gascalculator; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class CancunGasCalculatorTest { + + private final CancunGasCalculator gasCalculator = new CancunGasCalculator(); + + @ParameterizedTest(name = "{index} - parent gas {0}, used gas {1}, new excess {2}") + @MethodSource("blobGasses") + public void shouldCalculateExcessBlobGasCorrectly( + final long parentExcess, final long used, final long expected) { + assertThat(gasCalculator.computeExcessBlobGas(parentExcess, (int) used)).isEqualTo(expected); + } + + static Iterable blobGasses() { + long targetGasPerBlock = CancunGasCalculator.TARGET_BLOB_GAS_PER_BLOCK; + return List.of( + Arguments.of(0L, 0L, 0L), + Arguments.of(targetGasPerBlock, 0L, 0L), + Arguments.of(0L, 3, 0L), + Arguments.of(1, 3, 1), + Arguments.of(targetGasPerBlock, 1, CancunGasCalculator.BLOB_GAS_PER_BLOB), + Arguments.of(targetGasPerBlock, 3, targetGasPerBlock)); + } +} diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operation/AbstractCreateOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operation/AbstractCreateOperationTest.java new file mode 100644 index 00000000000..aa3dfd40217 --- /dev/null +++ b/evm/src/test/java/org/hyperledger/besu/evm/operation/AbstractCreateOperationTest.java @@ -0,0 +1,233 @@ +/* + * Copyright contributors to Hyperledger Besu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ +package org.hyperledger.besu.evm.operation; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.evm.EVM; +import org.hyperledger.besu.evm.MainnetEVMs; +import org.hyperledger.besu.evm.account.Account; +import org.hyperledger.besu.evm.account.MutableAccount; +import org.hyperledger.besu.evm.code.CodeFactory; +import org.hyperledger.besu.evm.code.CodeInvalid; +import org.hyperledger.besu.evm.frame.BlockValues; +import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.ConstantinopleGasCalculator; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; +import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.evm.internal.Words; +import org.hyperledger.besu.evm.processor.ContractCreationProcessor; +import org.hyperledger.besu.evm.tracing.OperationTracer; +import org.hyperledger.besu.evm.worldstate.WorldUpdater; +import org.hyperledger.besu.evm.worldstate.WrappedEvmAccount; + +import java.util.Deque; +import java.util.List; +import java.util.Optional; + +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.units.bigints.UInt256; +import org.junit.jupiter.api.Test; + +class AbstractCreateOperationTest { + + private final WorldUpdater worldUpdater = mock(WorldUpdater.class); + private final WrappedEvmAccount account = mock(WrappedEvmAccount.class); + private final WrappedEvmAccount newAccount = mock(WrappedEvmAccount.class); + private final MutableAccount mutableAccount = mock(MutableAccount.class); + private final MutableAccount newMutableAccount = mock(MutableAccount.class); + private final FakeCreateOperation operation = + new FakeCreateOperation(new ConstantinopleGasCalculator(), Integer.MAX_VALUE); + + private static final Bytes SIMPLE_CREATE = + Bytes.fromHexString( + "0x" + + "6000" // PUSH1 0x00 + + "6000" // PUSH1 0x00 + + "F3" // RETURN + ); + private static final Bytes POP_UNDERFLOW_CREATE = + Bytes.fromHexString( + "0x" + + "50" // POP (but empty stack) + + "6000" // PUSH1 0x00 + + "6000" // PUSH1 0x00 + + "F3" // RETURN + ); + public static final Bytes INVALID_EOF = + Bytes.fromHexString( + "0x" + + "73EF99010100040200010001030000000000000000" // PUSH20 contract + + "6000" // PUSH1 0x00 + + "52" // MSTORE + + "6014" // PUSH1 20 + + "600c" // PUSH1 12 + + "F3" // RETURN + ); + public static final String SENDER = "0xdeadc0de00000000000000000000000000000000"; + + /** The Create operation. */ + public static class FakeCreateOperation extends AbstractCreateOperation { + + private MessageFrame successFrame; + private Address successCreatedAddress; + private MessageFrame failureFrame; + private Optional failureHaltReason; + private MessageFrame invalidFrame; + private CodeInvalid invalidInvalidCode; + + /** + * Instantiates a new Create operation. + * + * @param gasCalculator the gas calculator + * @param maxInitcodeSize Maximum init code size + */ + public FakeCreateOperation(final GasCalculator gasCalculator, final int maxInitcodeSize) { + super(0xEF, "FAKECREATE", 3, 1, gasCalculator, maxInitcodeSize); + } + + @Override + public long cost(final MessageFrame frame) { + return gasCalculator().createOperationGasCost(frame); + } + + @Override + protected Address targetContractAddress(final MessageFrame frame) { + final Account sender = frame.getWorldUpdater().get(frame.getRecipientAddress()); + // Decrement nonce by 1 to normalize the effect of transaction execution + final Address address = + Address.contractAddress(frame.getRecipientAddress(), sender.getNonce() - 1L); + frame.warmUpAddress(address); + return address; + } + + @Override + protected void onSuccess(final MessageFrame frame, final Address createdAddress) { + successFrame = frame; + successCreatedAddress = createdAddress; + } + + @Override + protected void onFailure( + final MessageFrame frame, final Optional haltReason) { + failureFrame = frame; + failureHaltReason = haltReason; + } + + @Override + protected void onInvalid(final MessageFrame frame, final CodeInvalid invalidCode) { + invalidFrame = frame; + invalidInvalidCode = invalidCode; + } + } + + private void executeOperation(final Bytes contract, final EVM evm) { + final UInt256 memoryOffset = UInt256.fromHexString("0xFF"); + final MessageFrame messageFrame = + MessageFrame.builder() + .type(MessageFrame.Type.CONTRACT_CREATION) + .contract(Address.ZERO) + .inputData(Bytes.EMPTY) + .sender(Address.fromHexString(SENDER)) + .value(Wei.ZERO) + .apparentValue(Wei.ZERO) + .code(CodeFactory.createCode(SIMPLE_CREATE, 0, true)) + .completer(__ -> {}) + .address(Address.fromHexString(SENDER)) + .blockHashLookup(n -> Hash.hash(Words.longBytes(n))) + .blockValues(mock(BlockValues.class)) + .gasPrice(Wei.ZERO) + .miningBeneficiary(Address.ZERO) + .originator(Address.ZERO) + .initialGas(100000L) + .worldUpdater(worldUpdater) + .build(); + final Deque messageFrameStack = messageFrame.getMessageFrameStack(); + messageFrame.pushStackItem(Bytes.ofUnsignedLong(contract.size())); + messageFrame.pushStackItem(memoryOffset); + messageFrame.pushStackItem(Bytes.EMPTY); + messageFrame.expandMemory(0, 500); + messageFrame.writeMemory(memoryOffset.trimLeadingZeros().toInt(), contract.size(), contract); + + when(account.getMutable()).thenReturn(mutableAccount); + when(account.getNonce()).thenReturn(55L); + when(mutableAccount.getBalance()).thenReturn(Wei.ZERO); + when(worldUpdater.getAccount(any())).thenReturn(account); + when(worldUpdater.get(any())).thenReturn(account); + when(worldUpdater.getSenderAccount(any())).thenReturn(account); + when(worldUpdater.getOrCreate(any())).thenReturn(newAccount); + when(newAccount.getMutable()).thenReturn(newMutableAccount); + when(newMutableAccount.getCode()).thenReturn(Bytes.EMPTY); + when(worldUpdater.updater()).thenReturn(worldUpdater); + + operation.execute(messageFrame, evm); + final MessageFrame createFrame = messageFrameStack.peek(); + final ContractCreationProcessor ccp = + new ContractCreationProcessor(evm.getGasCalculator(), evm, false, List.of(), 0, List.of()); + ccp.process(createFrame, OperationTracer.NO_TRACING); + } + + @Test + void onSuccess() { + final EVM evm = MainnetEVMs.london(EvmConfiguration.DEFAULT); + + executeOperation(SIMPLE_CREATE, evm); + + assertThat(operation.successFrame).isNotNull(); + assertThat(operation.successCreatedAddress) + .isEqualTo(Address.fromHexString("0xecccb0113190dfd26a044a7f26f45152a4270a64")); + assertThat(operation.failureFrame).isNull(); + assertThat(operation.failureHaltReason).isNull(); + assertThat(operation.invalidFrame).isNull(); + assertThat(operation.invalidInvalidCode).isNull(); + } + + @Test + void onFailure() { + final EVM evm = MainnetEVMs.london(EvmConfiguration.DEFAULT); + + executeOperation(POP_UNDERFLOW_CREATE, evm); + + assertThat(operation.successFrame).isNull(); + assertThat(operation.successCreatedAddress).isNull(); + assertThat(operation.failureFrame).isNotNull(); + assertThat(operation.failureHaltReason) + .contains(ExceptionalHaltReason.INSUFFICIENT_STACK_ITEMS); + assertThat(operation.invalidFrame).isNull(); + assertThat(operation.invalidInvalidCode).isNull(); + } + + @Test + void onInvalid() { + final EVM evm = MainnetEVMs.futureEips(EvmConfiguration.DEFAULT); + + executeOperation(INVALID_EOF, evm); + + assertThat(operation.successFrame).isNull(); + assertThat(operation.successCreatedAddress).isNull(); + assertThat(operation.failureFrame).isNull(); + assertThat(operation.failureHaltReason).isNull(); + assertThat(operation.invalidFrame).isNotNull(); + assertThat(operation.invalidInvalidCode).isNotNull(); + } +} diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/DataHashOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/BlobHashOperationTest.java similarity index 63% rename from evm/src/test/java/org/hyperledger/besu/evm/operations/DataHashOperationTest.java rename to evm/src/test/java/org/hyperledger/besu/evm/operations/BlobHashOperationTest.java index 6e334fea67c..0f789a94477 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operations/DataHashOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/BlobHashOperationTest.java @@ -21,27 +21,33 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.evm.EVM; import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; import org.hyperledger.besu.evm.gascalculator.LondonGasCalculator; -import org.hyperledger.besu.evm.operation.DataHashOperation; +import org.hyperledger.besu.evm.operation.BlobHashOperation; import org.hyperledger.besu.evm.operation.Operation; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Optional; import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; import org.junit.jupiter.api.Test; -class DataHashOperationTest { +class BlobHashOperationTest { + + private static final String testVersionedHash = + "0x01cafebabeb0b0facedeadbeefbeef0001cafebabeb0b0facedeadbeefbeef00"; @Test void putsHashOnStack() { - Hash version0Hash = Hash.fromHexStringLenient("0xcafebabeb0b0facedeadbeef"); - List versionedHashes = List.of(version0Hash); - DataHashOperation getHash = new DataHashOperation(new LondonGasCalculator()); + VersionedHash version0Hash = new VersionedHash(Bytes32.fromHexStringStrict(testVersionedHash)); + List versionedHashes = Arrays.asList(version0Hash); + BlobHashOperation getHash = new BlobHashOperation(new LondonGasCalculator()); MessageFrame frame = mock(MessageFrame.class); when(frame.popStackItem()).thenReturn(Bytes.of(0)); when(frame.getVersionedHashes()).thenReturn(Optional.of(versionedHashes)); @@ -49,7 +55,7 @@ void putsHashOnStack() { Operation.OperationResult r = getHash.execute(frame, fakeEVM); assertThat(r.getGasCost()).isEqualTo(3); assertThat(r.getHaltReason()).isNull(); - verify(frame).pushStackItem(version0Hash); + verify(frame).pushStackItem(version0Hash.toBytes()); } @Test @@ -57,7 +63,7 @@ void pushesZeroOnBloblessTx() { EVM fakeEVM = mock(EVM.class); - DataHashOperation getHash = new DataHashOperation(new LondonGasCalculator()); + BlobHashOperation getHash = new BlobHashOperation(new CancunGasCalculator()); MessageFrame frame = mock(MessageFrame.class); when(frame.popStackItem()).thenReturn(Bytes.of(0)); when(frame.getVersionedHashes()).thenReturn(Optional.empty()); @@ -76,9 +82,9 @@ void pushesZeroOnBloblessTx() { @Test void pushZeroOnVersionIndexOutOFBounds() { - Hash version0Hash = Hash.fromHexStringLenient("0xcafebabeb0b0facedeadbeef"); - List versionedHashes = List.of(version0Hash); - DataHashOperation getHash = new DataHashOperation(new LondonGasCalculator()); + VersionedHash version0Hash = new VersionedHash(Bytes32.fromHexStringStrict(testVersionedHash)); + List versionedHashes = Arrays.asList(version0Hash); + BlobHashOperation getHash = new BlobHashOperation(new CancunGasCalculator()); MessageFrame frame = mock(MessageFrame.class); when(frame.popStackItem()).thenReturn(Bytes.of(1)); when(frame.getVersionedHashes()).thenReturn(Optional.of(versionedHashes)); @@ -88,4 +94,19 @@ void pushZeroOnVersionIndexOutOFBounds() { assertThat(r.getHaltReason()).isNull(); verify(frame).pushStackItem(Bytes.EMPTY); } + + @Test + public void pushZeroWhenPopsMissingUint256SizedIndex() { + VersionedHash version0Hash = new VersionedHash(Bytes32.fromHexStringStrict(testVersionedHash)); + List versionedHashes = Arrays.asList(version0Hash); + BlobHashOperation getHash = new BlobHashOperation(new CancunGasCalculator()); + MessageFrame frame = mock(MessageFrame.class); + when(frame.popStackItem()).thenReturn(Bytes32.repeat((byte) 0x2C)); + when(frame.getVersionedHashes()).thenReturn(Optional.of(versionedHashes)); + EVM fakeEVM = mock(EVM.class); + Operation.OperationResult r = getHash.execute(frame, fakeEVM); + assertThat(r.getGasCost()).isEqualTo(3); + assertThat(r.getHaltReason()).isNull(); + verify(frame).pushStackItem(Bytes.EMPTY); + } } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/Create2OperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/Create2OperationTest.java index 5fdc25d9380..5590cd09b4f 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operations/Create2OperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/Create2OperationTest.java @@ -42,7 +42,7 @@ import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evm.worldstate.WrappedEvmAccount; -import java.util.ArrayDeque; +import java.util.Deque; import java.util.List; import org.apache.tuweni.bytes.Bytes; @@ -157,13 +157,11 @@ public void setUp(final String sender, final String salt, final String code) { .value(Wei.ZERO) .apparentValue(Wei.ZERO) .code(CodeFactory.createCode(codeBytes, 0, true)) - .depth(1) .completer(__ -> {}) .address(Address.fromHexString(sender)) .blockHashLookup(n -> Hash.hash(Words.longBytes(n))) .blockValues(mock(BlockValues.class)) .gasPrice(Wei.ZERO) - .messageFrameStack(new ArrayDeque<>()) .miningBeneficiary(Address.ZERO) .originator(Address.ZERO) .initialGas(100_000L) @@ -214,9 +212,7 @@ void shouldCalculateGasPrice( void shanghaiMaxInitCodeSizeCreate() { final UInt256 memoryOffset = UInt256.fromHexString("0xFF"); final UInt256 memoryLength = UInt256.fromHexString("0xc000"); - final ArrayDeque messageFrameStack = new ArrayDeque<>(); - final MessageFrame messageFrame = - testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1, messageFrameStack); + final MessageFrame messageFrame = testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1); when(account.getMutable()).thenReturn(mutableAccount); when(account.getNonce()).thenReturn(55L); @@ -231,7 +227,7 @@ void shanghaiMaxInitCodeSizeCreate() { final EVM evm = MainnetEVMs.shanghai(DEV_NET_CHAIN_ID, EvmConfiguration.DEFAULT); var result = maxInitCodeOperation.execute(messageFrame, evm); - final MessageFrame createFrame = messageFrameStack.peek(); + final MessageFrame createFrame = messageFrame.getMessageFrameStack().peek(); final ContractCreationProcessor ccp = new ContractCreationProcessor(evm.getGasCalculator(), evm, false, List.of(), 0, List.of()); ccp.process(createFrame, OperationTracer.NO_TRACING); @@ -246,9 +242,7 @@ void shanghaiMaxInitCodeSizeCreate() { void shanghaiMaxInitCodeSizePlus1Create() { final UInt256 memoryOffset = UInt256.fromHexString("0xFF"); final UInt256 memoryLength = UInt256.fromHexString("0xc001"); - final ArrayDeque messageFrameStack = new ArrayDeque<>(); - final MessageFrame messageFrame = - testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1, messageFrameStack); + final MessageFrame messageFrame = testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1); when(account.getMutable()).thenReturn(mutableAccount); when(account.getNonce()).thenReturn(55L); @@ -271,8 +265,7 @@ private MessageFrame testMemoryFrame( final UInt256 memoryOffset, final UInt256 memoryLength, final UInt256 value, - final int depth, - final ArrayDeque messageFrameStack) { + final int depth) { final MessageFrame messageFrame = MessageFrame.builder() .type(MessageFrame.Type.CONTRACT_CREATION) @@ -282,13 +275,11 @@ private MessageFrame testMemoryFrame( .value(Wei.ZERO) .apparentValue(Wei.ZERO) .code(CodeFactory.createCode(SIMPLE_CREATE, 0, true)) - .depth(depth) .completer(__ -> {}) .address(Address.fromHexString(SENDER)) .blockHashLookup(n -> Hash.hash(Words.longBytes(n))) .blockValues(mock(BlockValues.class)) .gasPrice(Wei.ZERO) - .messageFrameStack(messageFrameStack) .miningBeneficiary(Address.ZERO) .originator(Address.ZERO) .initialGas(100000L) @@ -301,6 +292,10 @@ private MessageFrame testMemoryFrame( messageFrame.expandMemory(0, 500); messageFrame.writeMemory( memoryOffset.trimLeadingZeros().toInt(), SIMPLE_CREATE.size(), SIMPLE_CREATE); + final Deque messageFrameStack = messageFrame.getMessageFrameStack(); + while (messageFrameStack.size() < depth) { + messageFrameStack.push(messageFrame); + } return messageFrame; } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/CreateOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/CreateOperationTest.java index e3ffc975772..b685b8702ff 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operations/CreateOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/CreateOperationTest.java @@ -42,7 +42,7 @@ import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evm.worldstate.WrappedEvmAccount; -import java.util.ArrayDeque; +import java.util.Deque; import java.util.List; import org.apache.tuweni.bytes.Bytes; @@ -89,9 +89,7 @@ void createFromMemoryMutationSafe() { // Given: Execute a CREATE operation with a contract that logs in the constructor final UInt256 memoryOffset = UInt256.fromHexString("0xFF"); final UInt256 memoryLength = UInt256.valueOf(SIMPLE_CREATE.size()); - final ArrayDeque messageFrameStack = new ArrayDeque<>(); - final MessageFrame messageFrame = - testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1, messageFrameStack); + final MessageFrame messageFrame = testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1); when(account.getMutable()).thenReturn(mutableAccount); when(account.getNonce()).thenReturn(55L); @@ -106,7 +104,7 @@ void createFromMemoryMutationSafe() { final EVM evm = MainnetEVMs.london(EvmConfiguration.DEFAULT); operation.execute(messageFrame, evm); - final MessageFrame createFrame = messageFrameStack.peek(); + final MessageFrame createFrame = messageFrame.getMessageFrameStack().peek(); final ContractCreationProcessor ccp = new ContractCreationProcessor(evm.getGasCalculator(), evm, false, List.of(), 0, List.of()); ccp.process(createFrame, OperationTracer.NO_TRACING); @@ -130,9 +128,7 @@ void createFromMemoryMutationSafe() { void nonceTooLarge() { final UInt256 memoryOffset = UInt256.fromHexString("0xFF"); final UInt256 memoryLength = UInt256.valueOf(SIMPLE_CREATE.size()); - final ArrayDeque messageFrameStack = new ArrayDeque<>(); - final MessageFrame messageFrame = - testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1, messageFrameStack); + final MessageFrame messageFrame = testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1); when(worldUpdater.getAccount(any())).thenReturn(account); when(account.getMutable()).thenReturn(mutableAccount); @@ -149,9 +145,8 @@ void nonceTooLarge() { void messageFrameStackTooDeep() { final UInt256 memoryOffset = UInt256.fromHexString("0xFF"); final UInt256 memoryLength = UInt256.valueOf(SIMPLE_CREATE.size()); - final ArrayDeque messageFrameStack = new ArrayDeque<>(); final MessageFrame messageFrame = - testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1025, messageFrameStack); + testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1025); when(worldUpdater.getAccount(any())).thenReturn(account); when(account.getMutable()).thenReturn(mutableAccount); @@ -168,9 +163,9 @@ void messageFrameStackTooDeep() { void notEnoughValue() { final UInt256 memoryOffset = UInt256.fromHexString("0xFF"); final UInt256 memoryLength = UInt256.valueOf(SIMPLE_CREATE.size()); - final ArrayDeque messageFrameStack = new ArrayDeque<>(); final MessageFrame messageFrame = - testMemoryFrame(memoryOffset, memoryLength, UInt256.valueOf(1), 1, messageFrameStack); + testMemoryFrame(memoryOffset, memoryLength, UInt256.valueOf(1), 1); + final Deque messageFrameStack = messageFrame.getMessageFrameStack(); for (int i = 0; i < 1025; i++) { messageFrameStack.add(messageFrame); } @@ -190,9 +185,7 @@ void notEnoughValue() { void shanghaiMaxInitCodeSizeCreate() { final UInt256 memoryOffset = UInt256.fromHexString("0xFF"); final UInt256 memoryLength = UInt256.fromHexString("0xc000"); - final ArrayDeque messageFrameStack = new ArrayDeque<>(); - final MessageFrame messageFrame = - testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1, messageFrameStack); + final MessageFrame messageFrame = testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1); when(account.getMutable()).thenReturn(mutableAccount); when(account.getNonce()).thenReturn(55L); @@ -207,7 +200,7 @@ void shanghaiMaxInitCodeSizeCreate() { final EVM evm = MainnetEVMs.shanghai(DEV_NET_CHAIN_ID, EvmConfiguration.DEFAULT); var result = maxInitCodeOperation.execute(messageFrame, evm); - final MessageFrame createFrame = messageFrameStack.peek(); + final MessageFrame createFrame = messageFrame.getMessageFrameStack().peek(); final ContractCreationProcessor ccp = new ContractCreationProcessor(evm.getGasCalculator(), evm, false, List.of(), 0, List.of()); ccp.process(createFrame, OperationTracer.NO_TRACING); @@ -222,9 +215,7 @@ void shanghaiMaxInitCodeSizeCreate() { void shanghaiMaxInitCodeSizePlus1Create() { final UInt256 memoryOffset = UInt256.fromHexString("0xFF"); final UInt256 memoryLength = UInt256.fromHexString("0xc001"); - final ArrayDeque messageFrameStack = new ArrayDeque<>(); - final MessageFrame messageFrame = - testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1, messageFrameStack); + final MessageFrame messageFrame = testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1); when(account.getMutable()).thenReturn(mutableAccount); when(account.getNonce()).thenReturn(55L); @@ -299,8 +290,7 @@ private MessageFrame testMemoryFrame( final UInt256 memoryOffset, final UInt256 memoryLength, final UInt256 value, - final int depth, - final ArrayDeque messageFrameStack) { + final int depth) { final MessageFrame messageFrame = MessageFrame.builder() .type(MessageFrame.Type.CONTRACT_CREATION) @@ -310,13 +300,11 @@ private MessageFrame testMemoryFrame( .value(Wei.ZERO) .apparentValue(Wei.ZERO) .code(CodeFactory.createCode(SIMPLE_CREATE, 0, true)) - .depth(depth) .completer(__ -> {}) .address(Address.fromHexString(SENDER)) .blockHashLookup(n -> Hash.hash(Words.longBytes(n))) .blockValues(mock(BlockValues.class)) .gasPrice(Wei.ZERO) - .messageFrameStack(messageFrameStack) .miningBeneficiary(Address.ZERO) .originator(Address.ZERO) .initialGas(100000L) @@ -328,6 +316,10 @@ private MessageFrame testMemoryFrame( messageFrame.expandMemory(0, 500); messageFrame.writeMemory( memoryOffset.trimLeadingZeros().toInt(), SIMPLE_CREATE.size(), SIMPLE_CREATE); + final Deque messageFrameStack = messageFrame.getMessageFrameStack(); + while (messageFrameStack.size() < depth) { + messageFrameStack.push(messageFrame); + } return messageFrame; } } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/SelfDestructOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/SelfDestructOperationTest.java new file mode 100644 index 00000000000..f596bed8aad --- /dev/null +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/SelfDestructOperationTest.java @@ -0,0 +1,183 @@ +/* + * Copyright contributors to Hyperledger Besu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evm.operations; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.evm.EVM; +import org.hyperledger.besu.evm.account.MutableAccount; +import org.hyperledger.besu.evm.code.CodeFactory; +import org.hyperledger.besu.evm.frame.BlockValues; +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.ConstantinopleGasCalculator; +import org.hyperledger.besu.evm.internal.Words; +import org.hyperledger.besu.evm.operation.Operation; +import org.hyperledger.besu.evm.operation.SelfDestructOperation; +import org.hyperledger.besu.evm.worldstate.WorldUpdater; +import org.hyperledger.besu.evm.worldstate.WrappedEvmAccount; + +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class SelfDestructOperationTest { + + private static final Bytes SELFDESTRUCT_CODE = + Bytes.fromHexString( + "6000" // PUSH1 0 + + "35" // CALLDATALOAD + + "ff" // SELFDESTRUCT + ); + + private MessageFrame messageFrame; + @Mock private WorldUpdater worldUpdater; + @Mock private WrappedEvmAccount accountOriginator; + @Mock private WrappedEvmAccount accountBeneficiary; + @Mock private MutableAccount mutableAccountOriginator; + @Mock private MutableAccount mutableAccountBeneficiary; + @Mock private EVM evm; + + private final SelfDestructOperation frontierOperation = + new SelfDestructOperation(new ConstantinopleGasCalculator()); + + private final SelfDestructOperation eip6780Operation = + new SelfDestructOperation(new ConstantinopleGasCalculator(), true); + + void checkContractDeletionCommon( + final String originator, + final String beneficiary, + final String balanceHex, + final boolean newContract, + final SelfDestructOperation operation) { + Address originatorAddress = Address.fromHexString(originator); + Address beneficiaryAddress = Address.fromHexString(beneficiary); + messageFrame = + MessageFrame.builder() + .type(MessageFrame.Type.CONTRACT_CREATION) + .contract(Address.ZERO) + .inputData(Bytes.EMPTY) + .sender(beneficiaryAddress) + .value(Wei.ZERO) + .apparentValue(Wei.ZERO) + .code(CodeFactory.createCode(SELFDESTRUCT_CODE, 0, true)) + .completer(__ -> {}) + .address(originatorAddress) + .blockHashLookup(n -> Hash.hash(Words.longBytes(n))) + .blockValues(mock(BlockValues.class)) + .gasPrice(Wei.ZERO) + .miningBeneficiary(Address.ZERO) + .originator(Address.ZERO) + .initialGas(100_000L) + .worldUpdater(worldUpdater) + .build(); + messageFrame.pushStackItem(Bytes.fromHexString(beneficiary)); + if (newContract) { + messageFrame.addCreate(originatorAddress); + } + + when(worldUpdater.getAccount(originatorAddress)).thenReturn(accountOriginator); + when(worldUpdater.get(originatorAddress)).thenReturn(accountOriginator); + if (!originatorAddress.equals(beneficiaryAddress)) { + when(worldUpdater.get(beneficiaryAddress)).thenReturn(accountBeneficiary); + } + when(worldUpdater.getOrCreate(beneficiaryAddress)).thenReturn(accountBeneficiary); + when(accountOriginator.getMutable()).thenReturn(mutableAccountOriginator); + when(accountOriginator.getBalance()).thenReturn(Wei.fromHexString(balanceHex)); + when(accountBeneficiary.getMutable()).thenReturn(mutableAccountBeneficiary); + + final Operation.OperationResult operationResult = operation.execute(messageFrame, evm); + assertThat(operationResult).isNotNull(); + + // The interactions with the contracts varies based on the parameterized tests, but it will be + // some subset of these calls. + verify(accountOriginator, atLeast(0)).getBalance(); + verify(accountBeneficiary, atLeast(0)).getBalance(); + verify(mutableAccountOriginator, atLeast(0)).getBalance(); + verify(mutableAccountOriginator).decrementBalance(Wei.fromHexString(balanceHex)); + verify(mutableAccountOriginator, atLeast(0)).setBalance(Wei.ZERO); + verify(mutableAccountBeneficiary).incrementBalance(Wei.fromHexString(balanceHex)); + } + + public static Object[][] params() { + return new Object[][] { + { + "0x00112233445566778899aabbccddeeff11223344", + "0x1234567890abcdef1234567890abcdef12345678", + true, + "0x1234567890" + }, + { + "0x00112233445566778899aabbccddeeff11223344", + "0x1234567890abcdef1234567890abcdef12345678", + false, + "0x1234567890" + }, + { + "0x00112233445566778899aabbccddeeff11223344", + "0x00112233445566778899aabbccddeeff11223344", + true, + "0x1234567890" + }, + { + "0x1234567890abcdef1234567890abcdef12345678", + "0x1234567890abcdef1234567890abcdef12345678", + false, + "0x1234567890" + }, + }; + } + + @ParameterizedTest + @MethodSource("params") + void checkContractDeletionFrontier( + final String originator, + final String beneficiary, + final boolean newAccount, + final String balanceHex) { + checkContractDeletionCommon(originator, beneficiary, balanceHex, newAccount, frontierOperation); + + assertThat(messageFrame.getSelfDestructs()).contains(Address.fromHexString(originator)); + } + + @ParameterizedTest + @MethodSource("params") + void checkContractDeletionEIP6780( + final String originator, + final String beneficiary, + final boolean newAccount, + final String balanceHex) { + checkContractDeletionCommon(originator, beneficiary, balanceHex, newAccount, eip6780Operation); + + Address orignatorAddress = Address.fromHexString(originator); + if (newAccount) { + assertThat(messageFrame.getSelfDestructs()).contains(orignatorAddress); + assertThat(messageFrame.getCreates()).contains(orignatorAddress); + } else { + assertThat(messageFrame.getSelfDestructs()).isEmpty(); + assertThat(messageFrame.getCreates()).doesNotContain(orignatorAddress); + } + } +} diff --git a/evm/src/test/java/org/hyperledger/besu/evm/precompile/Benchmarks.java b/evm/src/test/java/org/hyperledger/besu/evm/precompile/Benchmarks.java index 37006694c89..9d3298b1cbf 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/precompile/Benchmarks.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/precompile/Benchmarks.java @@ -18,7 +18,6 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static org.hyperledger.besu.crypto.Hash.keccak256; -import static org.mockito.Mockito.mock; import org.hyperledger.besu.crypto.Hash; import org.hyperledger.besu.crypto.KeyPair; @@ -29,16 +28,15 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.evm.code.CodeV0; -import org.hyperledger.besu.evm.frame.BlockValues; +import org.hyperledger.besu.evm.fluent.SimpleBlockValues; +import org.hyperledger.besu.evm.fluent.SimpleWorld; import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.gascalculator.BerlinGasCalculator; import org.hyperledger.besu.evm.gascalculator.IstanbulGasCalculator; -import org.hyperledger.besu.evm.worldstate.WorldUpdater; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; -import java.util.ArrayDeque; import java.util.Map; import java.util.Random; import java.util.concurrent.TimeUnit; @@ -50,6 +48,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; +@SuppressWarnings("UnusedMethod") public class Benchmarks { static final Random random = new Random(); @@ -70,17 +69,15 @@ public class Benchmarks { .value(Wei.ZERO) .apparentValue(Wei.ZERO) .code(CodeV0.EMPTY_CODE) - .depth(1) .completer(__ -> {}) .address(Address.ZERO) .blockHashLookup(n -> null) - .blockValues(mock(BlockValues.class)) + .blockValues(new SimpleBlockValues()) .gasPrice(Wei.ZERO) - .messageFrameStack(new ArrayDeque<>()) .miningBeneficiary(Address.ZERO) .originator(Address.ZERO) .initialGas(100_000L) - .worldUpdater(mock(WorldUpdater.class)) + .worldUpdater(new SimpleWorld()) .build(); private static void benchSecp256k1Recover() { @@ -116,7 +113,7 @@ public static void benchSha256() { final byte[] warmupData = new byte[240]; final Bytes warmupBytes = Bytes.wrap(warmupData); for (int i = 0; i < HASH_WARMUP; i++) { - contract.compute(warmupBytes, fakeFrame); + contract.computePrecompile(warmupBytes, fakeFrame); } for (int len = 0; len <= 256; len += 8) { final byte[] data = new byte[len]; @@ -124,7 +121,7 @@ public static void benchSha256() { final Bytes bytes = Bytes.wrap(data); final Stopwatch timer = Stopwatch.createStarted(); for (int i = 0; i < HASH_ITERATIONS; i++) { - contract.compute(bytes, fakeFrame); + contract.computePrecompile(bytes, fakeFrame); } timer.stop(); @@ -172,7 +169,7 @@ private static void benchRipeMD() { final byte[] warmupData = new byte[240]; final Bytes warmupBytes = Bytes.wrap(warmupData); for (int i = 0; i < HASH_WARMUP; i++) { - contract.compute(warmupBytes, fakeFrame); + contract.computePrecompile(warmupBytes, fakeFrame); } for (int len = 0; len <= 256; len += 8) { final byte[] data = new byte[len]; @@ -180,7 +177,7 @@ private static void benchRipeMD() { final Bytes bytes = Bytes.wrap(data); final Stopwatch timer = Stopwatch.createStarted(); for (int i = 0; i < HASH_ITERATIONS; i++) { - contract.compute(bytes, fakeFrame); + contract.computePrecompile(bytes, fakeFrame); } timer.stop(); @@ -214,6 +211,14 @@ private static void benchModExp() { + "0000000000000000000000000000000000000000000000000000000000000020" + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e" + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f")) + .put( + "even-modulus-1", + Bytes.fromHexString( + "0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000003c2040160024518968061546464452029984405379963244433254832348165045983839181603600983245188119082741180552472823434126339186042653363989253518144015007104659260895861906540664936284389736130979465984263224400655133820675791338815252163142936101184074977707018635613728563507946963514079867296353079585444179075183175315953500862929638853495671020263166123912364061541662955981749424030252416330220564030645929402440479045589943839631409636357644094127401186503107365632233122371688639562179885062893961510897259834525401728081797411184820573804096446362924176080926052008070342876591822173915634645231182811305568049542955744148010693635112077769594038286419007643605441221736768092092706367136248982357930831050114862462054469804238839007660797444001134145988063087013657265067255538916788266246587774231646489345179567885975873995767749906187041937713976494258573504873269320274358396975658022816526738914029788471066595929777423497242252763504644221066495966982158816143636722736200299105017320500139589998102103536908651755056175006587609525845133254470473698921229697550145309121304642224273213418856615560961843245211567388930209839462064588566503446549415643465733541976019955544090933949692508519895293721888001835024288589127818157262958206047538648802179821901844091151603223229973835165715768557428338775055435040494382003663260090655173262271219880999454966135210800173588881197223814096778846598765822161982688788574265773201009190341430440400154076998270731076034021917712825351270109621323258567738829791704547404897555410847468529100600344699859551947494210268509149049419749744679372826553895949980386864014015247047775654329663958663391477680679444996526407026021137970100258833584773507489900747148344826790699325870056679710341571267983857125765234149331990149745571500943300684008078036054281629105618499442731182983775330888524074001975745730722737461725166625564316976464879780901853271273641654911641084141502464")) + .put( + "even-modulus-2", + Bytes.fromHexString( + "000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000d80000000000000000000000000000000000000000000000000000000000000010e0060000a921212121212121ff0000212b212121ffff1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f00feffff212121212121ffffffff1fe1e0e0e01e1f1f169f1f1f1f490afcefffffffffffffffff82828282828282828282828282828282828282828200ffff28ff2b212121ffff1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1fffffffffff0afceffffff7ffffffffff7c8282828282a1828282828282828282828282828200ffff28ff2b212121ffff1f1f1f1f1f1fd11f1f1f1f1f1f1f1f1f1f1fffffffffffffffff21212121212121fb2121212121ffff1f1f1f1f1f1f1f1fffaf82828282828200ffff28ff2b218282000000000000000000")) .put( "nagydani-1-square", Bytes.fromHexString( @@ -274,6 +279,10 @@ private static void benchModExp() { "nagydani-5-pow0x10001", Bytes.fromHexString( "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf010001e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad")) + .put( + "even-modulous2", + Bytes.fromHexString( + "0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000003c2040160024518968061546464452029984405379963244433254832348165045983839181603600983245188119082741180552472823434126339186042653363989253518144015007104659260895861906540664936284389736130979465984263224400655133820675791338815252163142936101184074977707018635613728563507946963514079867296353079585444179075183175315953500862929638853495671020263166123912364061541662955981749424030252416330220564030645929402440479045589943839631409636357644094127401186503107365632233122371688639562179885062893961510897259834525401728081797411184820573804096446362924176080926052008070342876591822173915634645231182811305568049542955744148010693635112077769594038286419007643605441221736768092092706367136248982357930831050114862462054469804238839007660797444001134145988063087013657265067255538916788266246587774231646489345179567885975873995767749906187041937713976494258573504873269320274358396975658022816526738914029788471066595929777423497242252763504644221066495966982158816143636722736200299105017320500139589998102103536908651755056175006587609525845133254470473698921229697550145309121304642224273213418856615560961843245211567388930209839462064588566503446549415643465733541976019955544090933949692508519895293721888001835024288589127818157262958206047538648802179821901844091151603223229973835165715768557428338775055435040494382003663260090655173262271219880999454966135210800173588881197223814096778846598765822161982688788574265773201009190341430440400154076998270731076034021917712825351270109621323258567738829791704547404897555410847468529100600344699859551947494210268509149049419749744679372826553895949980386864014015247047775654329663958663391477680679444996526407026021137970100258833584773507489900747148344826790699325870056679710341571267983857125765234149331990149745571500943300684008078036054281629105618499442731182983775330888524074001975745730722737461725166625564316976464879780901853271273641654911641084141502464")) .build(); final BigIntegerModularExponentiationPrecompiledContract contract = new BigIntegerModularExponentiationPrecompiledContract(new BerlinGasCalculator()); @@ -281,10 +290,16 @@ private static void benchModExp() { for (final Map.Entry testCase : testcases.entrySet()) { final double gasSpent = runBenchmark(testCase.getValue(), contract); + long gasCost = contract.gasRequirement(testCase.getValue()); System.out.printf( - "ModEXP %s for \t%,d gas. Charging %,d gas.%n", - testCase.getKey(), (int) gasSpent, contract.gasRequirement(testCase.getValue())); + "ModEXP %s for \t%,d gas. Charging %,d gas. \t@ %,.3f MGps%n", + testCase.getKey(), + (int) gasSpent, + gasCost, + gasCost / gasSpent * GAS_PER_SECOND_STANDARD / 1_000_000); } + + System.getProperties().forEach((k, v) -> System.out.println(k + " = " + v)); } private static void benchBNADD() { @@ -410,7 +425,7 @@ private static void benchBLS12G1Mul() { + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); final BLS12G1MulPrecompiledContract contract = new BLS12G1MulPrecompiledContract(); - contract.compute(arg, fakeFrame); + contract.computePrecompile(arg, fakeFrame); final double gasSpent = runBenchmark(arg, contract); diff --git a/evm/src/test/java/org/hyperledger/besu/evm/precompile/KZGPointEvalPrecompileContractTest.java b/evm/src/test/java/org/hyperledger/besu/evm/precompile/KZGPointEvalPrecompileContractTest.java index e56ed49e5ed..d482dea7d60 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/precompile/KZGPointEvalPrecompileContractTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/precompile/KZGPointEvalPrecompileContractTest.java @@ -16,12 +16,15 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.evm.frame.MessageFrame; import java.io.IOException; import java.io.InputStream; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -29,6 +32,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; @@ -52,6 +56,7 @@ public static void tearDown() { @ParameterizedTest(name = "{index}") @MethodSource("getPointEvaluationPrecompileTestVectors") public void testComputePrecompile(final PrecompileTestParameters parameters) { + when(toRun.getVersionedHashes()).thenReturn(Optional.of(List.of(parameters.versionedHash))); PrecompiledContract.PrecompileContractResult result = contract.computePrecompile(parameters.input, toRun); if (parameters.valid) { @@ -78,10 +83,12 @@ public static List getPointEvaluationPrecompileTestVec final JsonNode testCase = testCases.get(i); final Bytes input = Bytes.fromHexString(testCase.get("Input").asText()); final boolean valid = testCase.get("Valid").asBoolean(); - return new PrecompileTestParameters(input, valid, returnValue); + return new PrecompileTestParameters( + input, valid, returnValue, new VersionedHash(Bytes32.wrap(input.slice(0, 32)))); }) .collect(Collectors.toList()); } - record PrecompileTestParameters(Bytes input, boolean valid, Bytes returnValue) {} + record PrecompileTestParameters( + Bytes input, boolean valid, Bytes returnValue, VersionedHash versionedHash) {} } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/testutils/TestCodeExecutor.java b/evm/src/test/java/org/hyperledger/besu/evm/testutils/TestCodeExecutor.java index 69fbe4e13bb..02f6ffba191 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/testutils/TestCodeExecutor.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/testutils/TestCodeExecutor.java @@ -28,7 +28,6 @@ import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import java.util.ArrayDeque; import java.util.Deque; import java.util.function.Consumer; @@ -54,8 +53,6 @@ public MessageFrame executeCode( public MessageFrame executeCode( final String codeHexString, final long gasLimit, final WorldUpdater worldUpdater) { - final Deque messageFrameStack = new ArrayDeque<>(); - final MessageCallProcessor messageCallProcessor = new MessageCallProcessor(evm, new PrecompileContractRegistry()); final Bytes codeBytes = Bytes.fromHexString(codeHexString.replaceAll("\\s", "")); @@ -63,7 +60,6 @@ public MessageFrame executeCode( final MessageFrame initialFrame = new TestMessageFrameBuilder() - .messageFrameStack(messageFrameStack) .worldUpdater(worldUpdater) .initialGas(gasLimit) .address(SENDER_ADDRESS) @@ -75,10 +71,9 @@ public MessageFrame executeCode( .value(Wei.ZERO) .code(code) .blockValues(blockValues) - .depth(0) .build(); - messageFrameStack.addFirst(initialFrame); + final Deque messageFrameStack = initialFrame.getMessageFrameStack(); while (!messageFrameStack.isEmpty()) { messageCallProcessor.process(messageFrameStack.peekFirst(), OperationTracer.NO_TRACING); } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/testutils/TestMessageFrameBuilder.java b/evm/src/test/java/org/hyperledger/besu/evm/testutils/TestMessageFrameBuilder.java index dfceccaf4f8..0e7fdb50418 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/testutils/TestMessageFrameBuilder.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/testutils/TestMessageFrameBuilder.java @@ -27,9 +27,7 @@ import org.hyperledger.besu.evm.toy.ToyWorld; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Deque; import java.util.List; import java.util.Optional; import java.util.function.Function; @@ -41,7 +39,6 @@ public class TestMessageFrameBuilder { public static final Address DEFAUT_ADDRESS = Address.fromHexString("0xe8f1b89"); private static final int maxStackSize = DEFAULT_MAX_STACK_SIZE; - private Deque messageFrameStack = new ArrayDeque<>(); private Optional blockValues = Optional.empty(); private Optional worldUpdater = Optional.empty(); private long initialGas = Long.MAX_VALUE; @@ -56,15 +53,9 @@ public class TestMessageFrameBuilder { private int pc = 0; private int section = 0; private final List stackItems = new ArrayList<>(); - private int depth = 0; private Optional> blockHashLookup = Optional.empty(); private Bytes memory = Bytes.EMPTY; - TestMessageFrameBuilder messageFrameStack(final Deque messageFrameStack) { - this.messageFrameStack = messageFrameStack; - return this; - } - public TestMessageFrameBuilder worldUpdater(final WorldUpdater worldUpdater) { this.worldUpdater = Optional.of(worldUpdater); return this; @@ -130,11 +121,6 @@ public TestMessageFrameBuilder blockValues(final BlockValues blockValues) { return this; } - public TestMessageFrameBuilder depth(final int depth) { - this.depth = depth; - return this; - } - public TestMessageFrameBuilder pushStackItem(final Bytes item) { stackItems.add(item); return this; @@ -154,7 +140,6 @@ public MessageFrame build() { final MessageFrame frame = MessageFrame.builder() .type(MessageFrame.Type.MESSAGE_CALL) - .messageFrameStack(messageFrameStack) .worldUpdater(worldUpdater.orElseGet(this::createDefaultWorldUpdater)) .initialGas(initialGas) .address(address) @@ -167,7 +152,6 @@ public MessageFrame build() { .contract(contract) .code(code) .blockValues(blockValues.orElseGet(() -> new FakeBlockValues(1337))) - .depth(depth) .completer(c -> {}) .miningBeneficiary(Address.ZERO) .blockHashLookup(blockHashLookup.orElse(number -> Hash.hash(Words.longBytes(number)))) diff --git a/evm/src/test/java/org/hyperledger/besu/evm/toy/EvmToyCommand.java b/evm/src/test/java/org/hyperledger/besu/evm/toy/EvmToyCommand.java index 00e875d1849..eb8030cde76 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/toy/EvmToyCommand.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/toy/EvmToyCommand.java @@ -34,7 +34,6 @@ import java.io.PrintStream; import java.math.BigInteger; import java.nio.charset.StandardCharsets; -import java.util.ArrayDeque; import java.util.Deque; import java.util.List; @@ -168,11 +167,9 @@ public void run() { ? new StandardJsonTracer(System.out, showMemory, showStack, showReturnData) : OperationTracer.NO_TRACING; - final Deque messageFrameStack = new ArrayDeque<>(); - messageFrameStack.add( + MessageFrame initialMessageFrame = MessageFrame.builder() .type(MessageFrame.Type.MESSAGE_CALL) - .messageFrameStack(messageFrameStack) .worldUpdater(worldUpdater.updater()) .initialGas(gas) .contract(Address.ZERO) @@ -185,25 +182,21 @@ public void run() { .apparentValue(ethValue) .code(code) .blockValues(new ToyBlockValues()) - .depth(0) .completer(c -> {}) .miningBeneficiary(Address.ZERO) .blockHashLookup(h -> null) - .build()); + .build(); final MessageCallProcessor mcp = new MessageCallProcessor(evm, precompileContractRegistry); final ContractCreationProcessor ccp = new ContractCreationProcessor(evm.getGasCalculator(), evm, false, List.of(), 0); stopwatch.start(); + Deque messageFrameStack = initialMessageFrame.getMessageFrameStack(); while (!messageFrameStack.isEmpty()) { final MessageFrame messageFrame = messageFrameStack.peek(); switch (messageFrame.getType()) { - case CONTRACT_CREATION: - ccp.process(messageFrame, tracer); - break; - case MESSAGE_CALL: - mcp.process(messageFrame, tracer); - break; + case CONTRACT_CREATION -> ccp.process(messageFrame, tracer); + case MESSAGE_CALL -> mcp.process(messageFrame, tracer); } if (lastLoop) { if (messageFrame.getExceptionalHaltReason().isPresent()) { diff --git a/evm/src/test/java/org/hyperledger/besu/evm/toy/ToyAccount.java b/evm/src/test/java/org/hyperledger/besu/evm/toy/ToyAccount.java index dd6971d83f4..d81e8f7f46e 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/toy/ToyAccount.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/toy/ToyAccount.java @@ -40,7 +40,7 @@ public class ToyAccount implements EvmAccount, MutableAccount { private Address address; private final Supplier addressHash = - Suppliers.memoize(() -> address == null ? Hash.ZERO : Hash.hash(address)); + Suppliers.memoize(() -> address == null ? Hash.ZERO : address.addressHash()); private long nonce; private Wei balance; private Bytes code; diff --git a/evm/src/test/java/org/hyperledger/besu/evm/tracing/ExtendedOperationTracerTest.java b/evm/src/test/java/org/hyperledger/besu/evm/tracing/ExtendedOperationTracerTest.java new file mode 100644 index 00000000000..e74d43d8ec4 --- /dev/null +++ b/evm/src/test/java/org/hyperledger/besu/evm/tracing/ExtendedOperationTracerTest.java @@ -0,0 +1,107 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evm.tracing; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.evm.EVM; +import org.hyperledger.besu.evm.account.EvmAccount; +import org.hyperledger.besu.evm.account.MutableAccount; +import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; +import org.hyperledger.besu.evm.processor.ContractCreationProcessor; +import org.hyperledger.besu.evm.worldstate.WorldUpdater; + +import java.util.Collections; +import java.util.Optional; + +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class ExtendedOperationTracerTest { + + @Mock GasCalculator gasCalculator; + @Mock EVM evm; + @Mock MessageFrame frame; + @Mock WorldUpdater worldUpdater; + @Mock EvmAccount evmAccount; + @Mock MutableAccount mutableAccount; + + @BeforeEach + void setUp() { + when(frame.getOutputData()).thenReturn(Bytes.EMPTY); + when(gasCalculator.codeDepositGasCost(anyInt())).thenReturn(0L); + when(frame.getRemainingGas()).thenReturn(1L); + + when(frame.getWorldUpdater()).thenReturn(worldUpdater); + when(worldUpdater.getOrCreate(any())).thenReturn(evmAccount); + when(evmAccount.getMutable()).thenReturn(mutableAccount); + } + + @Test + void shouldCallTraceAccountCreationResultIfIsExtendedTracing() { + final ContractCreationProcessor contractCreationProcessor = + new ContractCreationProcessor(gasCalculator, evm, false, Collections.emptyList(), 0); + + final ExtendedOperationTracer tracer = new ExtendedOperationTracer(); + contractCreationProcessor.codeSuccess(frame, tracer); + + // traceAccountCreationResult has been called and values have been set + assertThat(tracer.frame).isNotNull(); + assertThat(tracer.haltReason).isNotNull(); + assertThat(tracer.haltReason).isEmpty(); + } + + @Test + void shouldNotCallTraceAccountCreationResultIfIsNotExtendedTracing() { + final ContractCreationProcessor contractCreationProcessor = + new ContractCreationProcessor(gasCalculator, evm, false, Collections.emptyList(), 0); + + final DefaultOperationTracer tracer = new DefaultOperationTracer(); + contractCreationProcessor.codeSuccess(frame, tracer); + + // traceAccountCreationResult has not been called and values are still null + assertThat(tracer.frame).isNull(); + assertThat(tracer.haltReason).isNull(); + } + + static class DefaultOperationTracer implements OperationTracer { + public MessageFrame frame = null; + public Optional haltReason = null; + + @Override + public void traceAccountCreationResult( + final MessageFrame frame, final Optional haltReason) { + this.frame = frame; + this.haltReason = haltReason; + } + } + + static class ExtendedOperationTracer extends DefaultOperationTracer { + @Override + public boolean isExtendedTracing() { + return true; + } + } +} diff --git a/evm/src/test/resources/org/hyperledger/besu/evm/precompile/pointEvaluationPrecompile.json b/evm/src/test/resources/org/hyperledger/besu/evm/precompile/pointEvaluationPrecompile.json index b3f920acd77..3dc0aed1af1 100644 --- a/evm/src/test/resources/org/hyperledger/besu/evm/precompile/pointEvaluationPrecompile.json +++ b/evm/src/test/resources/org/hyperledger/besu/evm/precompile/pointEvaluationPrecompile.json @@ -2,168 +2,23 @@ "PrecompileReturnValue": "000000000000000000000000000000000000000000000000000000000000100073eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", "TestCases": [ { - "Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44febbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524a97456b8097baed6e90ce381d2b21c970a3f9ad4f6c92b1bb26337f919bd639dd43bd470839153db09115e2862051f33a8cd9ff4ff4f98ba4ea89e80747cfdc694ac9969b841c8d558dc41bceb3c8f97c8c48c1409304ec70176c4e24fc7f6fa", + "Input": "012801238108394529333e45adfaff59edde33727fa766ee99752921b472893600000000000000000000000000000000000000000000000000000000000020010f69060fb771fa559a9e842e1dd79dde8a107486e801707032d93b5965d0cd48abb6bcbe313530ce7779abdf633d5a3594a41fbad9a79f4a9b46b89c0cfe78f6a15948dec92c4404aedac8b5e7dd60598ad6f539bc7280de6af4c95e7cef39bb6873f18c46ee5eb67299324ee7c6e6da71be2dbd5e2cbafbae4b2d60b40a808c", "FailureMode": "", "Valid": true }, { - "Input": "012801238108394529333e45adfaff59edde33727fa766ee99752921b472893611f5bc1101693a3a77098f71ec13c7ccaf4542a037b9397dd4ebe522e05d9d47629f4dddbcf4a5c28f5b09c9bee1895d3de14ea9312df7cf607d09517eb7863dabb6bcbe313530ce7779abdf633d5a3594a41fbad9a79f4a9b46b89c0cfe78f6a15948dec92c4404aedac8b5e7dd60598a963e56a55c2659c306beeb49ac79b7bd375fad150619b2fb5d835ee8f8305c3aac541ca6adad9be851b4f6dca5cd73", - "FailureMode": "", - "Valid": true - }, - { - "Input": "0116f63b849a1a5704c55538e61f3576b09fe82fe038a39c96a3cd97986777a97ca4870f96b96f3c0ccef8ebccb186d1df0eccad55374fcf2262bc32e224763f5ac3abbe48a5c2f3731087f86bbf567910fe098f6183a2be6c1bd97ed2e1c562a4429aefed1de5145c9426c68b2fa5dc9ac0bd0c7d0420e0763824849abf47ff9be8942d481525d54dbf8d2508490e42a5e6166b8755b63c54b54802049c01c4a79b6c55b3cf3b7a22e9382cf4960f703b339622aa530e0961ef6747faf3ebf3", - "FailureMode": "", - "Valid": true - }, - { - "Input": "01aebaf22aa7b4019a4917f97176f9c0e79513f1e297b4daef1158fbed94f8afe753520d2b0aa53ea1926266ad4f46d60fd855bb73b5642171d89242e4eb4e3735096476da0d660f9e2913bbe7d29301fa96a178d02349323fac041d6ac1070d934abbb7ff0028c06ce8d27accbf0312fd4bfd55e58e6d8920aaf9d7d51f1a59ac00b34e7eedf5464ddf69b3c6e3e8d1b577b30ec9d82eb5e56827c875fb33892e29b504198fa7a6b196ac7cd6d64838ca452d94adeb57f1ae4b5d894d26d616", - "FailureMode": "", - "Valid": true - }, - { - "Input": "016ee58067bdbc41ad3978fb379e8fe3ab0bc4cda0f131ee9baf2db213cd4dc552031d0bc05ada403657cce08ded05db3fa1dfc891337a73bf4e6952e6b2272f02b04885539a8052bd8e104f6f894fca92355da265a04fc5a16b2fca2e016252a90cf079520942b69d207a57445406dc1f539f60467cf2bcd805814190ea87280103f02e68e50a314b25dea197c2543488e5992ffd5e03890ef5c362569a670b955cb11d923b176b152750e853190ee7dd6b56074f009580e191d79e3888bc26", - "FailureMode": "", - "Valid": true - }, - { - "Input": "01bbbb1a74e35dd8cb8faec442693b1355f40ab9d0b44c47a9ec8ff197987929bdb2e70855ab0f43cb1b365b6e8bc5df6f6a69d6afb18fc50dc53f62e879002728aa2577ad9b59293956d5d76783b1e54c1777d3ebc2ac5dea349f10a66735399913a98b55d225411649847f9cf0c5afedf4f30623392cea17ed509864d8e0d87ecfa303e0f9c9c083456d9125a3a8d5b723e9a64edda406fc74ab8685039dd6039b6d2f8ed8d15887776860d7ea57a3767410a4eb46bba045f925b41e2fa299", - "FailureMode": "", - "Valid": true - }, - { - "Input": "01792bd31013b362e1383652ea9c6d7d0f6c7880f4478eab785923d2a24417fe2862b206eafb444560e09fd54e2985e49f33f3e3cd2fa5175c3b1672ea40d91e808310a87ca1c24a2b2258c38e495d0df51d1cea6c11431679cc04a8468c9f5a86bdcd35acafb637235ccb8c908332cea2ca9e4efa5afc66c24f9f3ea0281ff3c588b147d90844248b36b79cbae7d016b6c46951710384a5fc425bfc89f804b9bfe0148805c54162a4ec091e5bf063db88577b12b9839def3fb15ab4b15e46e8", - "FailureMode": "", - "Valid": true - }, - { - "Input": "0111c228100fd51f22a0be9e86211f971ab6c7a5dfe6988b5b45e159c77d937b93117d047f4c7a47f5a409502fc744e9cffc7cf1ebadba69aab1ec81ec07b2166770490221efc59c136280d4152adcfee9dbd2d17b6b727a4838373258054631b416564857a5239934c918dd7ce1585016082ca9bb79a0626d1ccb00afcd458910d69b36e69752791ff49736af318707855231b9ecc3cd8ed8f52eb31673482ad804ccaeeadb91fda7104f90b483d609fefa5b677efe9ceb772a4d80decbf404", - "FailureMode": "", - "Valid": true - }, - { - "Input": "016d0d27b2a1b5266e1f6fe2f987bff57bd67157222831d9260f782dbf85e957fec04702149daf498a6973ca0f6504eeffc506ff092cd0bbf827c391eece8a0e004ddc8a839cd6c7d381795dd08e8ef23e97f59e7c34457f3aa802b5edbba35a94c3f402eb91cf43a4f502d486f22f0f04bd99c1a8180353d93e6c612ddb22c7838d3e03c471b4289bd2fd5060a615379172bbbf1f4606d3c777886412b18c5e551b098d9373cec1957dc333e9b83d0306941c61a7a0fdf031f243c4e2fc0919", - "FailureMode": "", - "Valid": true - }, - { - "Input": "011459b168df56c35b2a1712329aabd7f904735dfb7e948b12869a4396d7cb9e69701200a9ede44b1f2edd44f002c4f22f8f900c28aae50d479e99a1f0956306740e0b40715e2d1d5b32c1960253f8a2b2c32db833279863237e1da14867b24b840eedd5e97ba21d82aaa67583b8f9b8936b1d0e11e69c77ab9f8381cf47f3013dc258944bf04fd91fe5663aa33b5397a05bcb8545682fbdc37663bbf01010c13164a422915a9c8961efe82825fb68302a3435ed2cf7e01bbac059a420277f05", - "FailureMode": "", - "Valid": true - }, - { - "Input": "01dc43cf428476b6fde56262f081988eeeb5ae6e665a2fcbcd667f93b474ebc9d51fddfd3c3e1a4eb34e45bfd344414b6530bc234e003593dd910ddb45042a72c1f4fd101b80df1af58a2d77804c711e999d09a90f2e379ef18c752dd3866e34ac51bce1515c3df45ee85b5342c88291288a171f8799d31b1e77ff2d692f3f1f6880e2fd0262132fdaac0e4245958fafaaed1182c6af9f27f01e9e0c47dd3278496c3d3b4126c9f62a6fb81542d3223a480323fa09fb524ad4f70c83f46150f1", - "FailureMode": "", - "Valid": true - }, - { - "Input": "0111c36a6aa83254e02e96995ac0ac766f5edadd8044fd0170d4e459df72267a40cfa7fbd18e4f504813af39b4e2005095f945316c7e4ae52b08e4ea47cb026a43dfedc72048fbe7a9107e8abcdca472f722cd3327c78a6a1dd475d556e1063f8a6775af1fb1d442d7fef688d3e34aa7055e131fa13be05528cde77479d33ffd2f21708b479d3e36fabff48ccaceec19acbd62bfac28c7f29f62e0e3b8587fb50abd49370c1e164f3555abbe9199aabacf170d7c39beafb36506ec73847a6729", - "FailureMode": "", - "Valid": true - }, - { - "Input": "014adbe3d78e1a41777dc899baa9597dc97bcffa2bc6d8f79fe9de417078d8f8ab7e72f966df8452ddd718b49480c054c5c2cf3e8afc5f377a7ebafa4992db617d7ec99ffb7dac5dd4d5dc011447816b11b46094b584d5070fb620ef71edb114a8d63144a4ed21007c816a63e56701ad142dd4a26feaf9249040246b1b290450fac06edfc3f223e98aca2b7c758c459884b90ccabd00e842e492ffdea7495f3732dd2cfe142892400089b121bcac3dd21ab347d0f6dc092f23710354ea071438", - "FailureMode": "", - "Valid": true - }, - { - "Input": "01cbb255a9e362102497d90841b3099aa812f281980b20c12951fdfdc30204c7162e3df7fb2fba54729c822e751e8059f58b594ca87a7589c8f4900a4c59b45904ec35e25ea7595f7e7352abbe50d6c1fa57c612b43cf77d17ab598ffa0f023f8a20f1cbae3472de159c30b66bcec852689326c449720ffeaa87d5b86629489ce1a5c660bb06c2a2539dcf1438d2c960a246002bcfe66adb8f9463c873b855ade410313c5128a8adfab5492da5e662cc556999ee653b697a449a21628c1585c7", - "FailureMode": "", - "Valid": true - }, - { - "Input": "0103a676648fcc81830d61b0b07937aaf48690aeda04d5b02b5a251bd5ca5c4f81dd07f59080ef560761eca855bc3f5e2555e359c6f88adb166b671a4e208d51e6ecb876da33438c5cf8fe1463008e14d012cda7365474e61148e2eb76d3910a852f33ed26a17a7a6b9db96b03c110d5709251a5377d0e86d4349bce0610d01ae2d6c4e2a45aea1d20822988bcbca345b17fca68d1b4024f157d9b81f57ff2917d0101f8e02cc05ae8c6655102b4dd55d8461c6f971f5111f1f0b82338837cb5", - "FailureMode": "", - "Valid": true - }, - { - "Input": "01e7ab7a7aaea9ee3e2fc8d17bde6badc12e2bf824bfe8db0eafc43dd0762bf1ec8cd2f225d124599c255623365aff62551e6d67e476a02d65e13d2a50e76549efae7b3b28a8d235894e618237f4abaffaa500fff7cb926e9309a7d4fe7eb53cab1484ed8e82a622d2647871e0e784fc676e55047dde4cf156b2036f937562dfff92102fd993352513fb75913935b47e89dc14149659b5d999abd29d2fc33f76b287b0140434c6c26c214fb0aa3f1ac27369ea89f4b2ab79aa03040720d32c67", - "FailureMode": "", - "Valid": true - }, - { - "Input": "010b73d38034466a538f1acaf463f7575d3d3f4baa23dcf6d559700e8fb5fd82573c9df0ba215a5b31eabf9d16f8be6785e7f67402f5b57fb357143a52ae3e4144abb69b6b607cce5f1830f05ad98f8c184d39a1c76d860876fffb5852fc450fa372cb9c0a5b0c14406f59e4926acde14f737d69d4a926906fbabad357e743f2ecab5a7da7e5384dca593697eaeaf58aa1b8b02d82fac14d98121dae7e04d9f3e38a5fc4164e0d0dd6692ba0b55b8063d4aee0987a0f811396617f4045609a71", - "FailureMode": "", - "Valid": true - }, - { - "Input": "013e3ff78fc9bb6c6564d205fe1064aa6e11eddef9f0e985d8f364005d03c22fc2eb67ee4f728f5dc6ae2918f7957e6cb5b080822073cbd101ceea4954751739e3e04001d6c2037a831ff7ad639fbdb277264edd75b50d025eb183120464f940a86e11eedc9683475153b147c8ce10ae29495aed6cf2e58c5c3385f1be4d2162696d0488a94b4a2a552eeb0502eae3cc80049aaaf808839090c40d57463ffb5b56228d88f2329b5811ac7f5931085fa7360876a58893cc049debf820bc7ab88b", - "FailureMode": "", - "Valid": true - }, - { - "Input": "019f4cc64584a59f7d924fb921ede13a7a04c1d595bdd96ba66722baeb145e862d9b32ece4c2c45f5b739392d7333e71e5790a903ef1e0235044c159563cf0309ae1b4c885a4afeb472ccf74b3ec7d68044ab28890a647d76939d31097645025817785fe342e0354ee0845753542d0eaff5c0acb9a7c2206de60c930a57c81b6db2e2b414ba3ab2730f3364f7d35dfdfa4df917a3c7c9e3457871234e6bf9a35ad025f0e40ef2a2502a5024c7f0ce709cc27c3bd2399c9a1ec02238d38124c9e", - "FailureMode": "", - "Valid": true - }, - { - "Input": "0128f689b5b1121319a69abacd871979a1075506bd04ac7f08399a1996626201984afde97913fa61f037fd0cb8d1fd751543949d5c6ff6759eba97695803c9284b3b9280d5b4d8f18181f4a0d199bd69e63463b75a2722835b23fe5145711a5997885c37b0edb98b1569af211135fa3b2ec29871005ef58bd429533bbabb70275840fec04fdd4fc327c730d0919fb0d08bd1b47fac65f7874afc7d394b5873c48c82a70e67c5c4dac616896fcec24df35f7e1ac5a6236927671d11aaa0a25c71", - "FailureMode": "", - "Valid": true - }, - { - "Input": "", - "FailureMode": "incorrectPrecompileLength", - "Valid": false - }, - { - "Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44febbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac5", - "FailureMode": "incorrectPrecompileLength", - "Valid": false - }, - { - "Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44febbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524a97456b8097baed6e90ce381d2b21c970a3f9ad4f6c92b1bb26337f919bd639dd43bd470839153db09115e2862051f33a8cd9ff4ff4f98ba4ea89e80747cfdc694ac9969b841c8d558dc41bceb3c8f97c8c48c1409304ec70176c4e24fc7f6fa01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44febbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524a97456b8097baed6e90ce381d2b21c970a3f9ad4f6c92b1bb26337f919bd639dd43bd470839153db09115e2862051f33a8cd9ff4ff4f98ba4ea89e80747cfdc694ac9969b841c8d558dc41bceb3c8f97c8c48c1409304ec70176c4e24fc7f6fa", - "FailureMode": "incorrectPrecompileLength", - "Valid": false - }, - { - "Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682c3b23e313cacf2ce5e5e13219c5a54851bc51a0ef723a0e13805186b13f245a7ebbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524a97456b8097baed6e90ce381d2b21c970a3f9ad4f6c92b1bb26337f919bd639dd43bd470839153db09115e2862051f33a8cd9ff4ff4f98ba4ea89e80747cfdc694ac9969b841c8d558dc41bceb3c8f97c8c48c1409304ec70176c4e24fc7f6fa", - "FailureMode": "nonCanonicalInputPoint", - "Valid": false - }, - { - "Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44f98b392451fdc18899c205e8b9f9286daf331b974cba0af44e3343dc307b3baeca97456b8097baed6e90ce381d2b21c970a3f9ad4f6c92b1bb26337f919bd639dd43bd470839153db09115e2862051f33a8cd9ff4ff4f98ba4ea89e80747cfdc694ac9969b841c8d558dc41bceb3c8f97c8c48c1409304ec70176c4e24fc7f6fa", - "FailureMode": "nonCanonicalOutputPoint", - "Valid": false - }, - { - "Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44febbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a8cd9ff4ff4f98ba4ea89e80747cfdc694ac9969b841c8d558dc41bceb3c8f97c8c48c1409304ec70176c4e24fc7f6fa", - "FailureMode": "cannotDeserialiseCommitment", - "Valid": false - }, - { - "Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44febbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa8cd9ff4ff4f98ba4ea89e80747cfdc694ac9969b841c8d558dc41bceb3c8f97c8c48c1409304ec70176c4e24fc7f6fa", - "FailureMode": "cannotDeserialiseCommitment", - "Valid": false - }, - { - "Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44febbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524a97456b8097baed6e90ce381d2b21c970a3f9ad4f6c92b1bb26337f919bd639dd43bd470839153db09115e2862051f33000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "FailureMode": "cannotDeserialiseProof", - "Valid": false - }, - { - "Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44febbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524a97456b8097baed6e90ce381d2b21c970a3f9ad4f6c92b1bb26337f919bd639dd43bd470839153db09115e2862051f33ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "FailureMode": "cannotDeserialiseProof", - "Valid": false - }, - { - "Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea84676820000000000000000000000000000000000000000000000000000000000000000ebbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524a97456b8097baed6e90ce381d2b21c970a3f9ad4f6c92b1bb26337f919bd639dd43bd470839153db09115e2862051f33a8cd9ff4ff4f98ba4ea89e80747cfdc694ac9969b841c8d558dc41bceb3c8f97c8c48c1409304ec70176c4e24fc7f6fa", - "FailureMode": "invalidOpening", - "Valid": false - }, - { - "Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44f0000000000000000000000000000000000000000000000000000000000000000a97456b8097baed6e90ce381d2b21c970a3f9ad4f6c92b1bb26337f919bd639dd43bd470839153db09115e2862051f33a8cd9ff4ff4f98ba4ea89e80747cfdc694ac9969b841c8d558dc41bceb3c8f97c8c48c1409304ec70176c4e24fc7f6fa", - "FailureMode": "invalidOpening", + "Input": "012801238108394569333e45adfaff59edde33727fa766ee99752921b472893600000000000000000000000000000000000000000000000000000000000020010f69060fb771fa559a9e842e1dd79dde8a107486e801707032d93b5965d0cd48abb6bcbe313530ce7779abdf633d5a3594a41fbad9a79f4a9b46b89c0cfe78f6a15948dec92c4404aedac8b5e7dd60598ad6f539bc7280de6af4c95e7cef39bb6873f18c46ee5eb67299324ee7c6e6da71be2dbd5e2cbafbae4b2d60b40a808c", + "FailureMode": "busted versioned hash", "Valid": false }, { - "Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44febbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a8cd9ff4ff4f98ba4ea89e80747cfdc694ac9969b841c8d558dc41bceb3c8f97c8c48c1409304ec70176c4e24fc7f6fa", - "FailureMode": "invalidOpening", + "Input": "012801238108394529333e45adfaff59edde33727fa766ee99752921b472893600000000000000000000000000000000000000000000000000000000000020010f69060fb771fa559a9e842e1dd79dde8a107486e801707032d93b5965d0cd48abb6bcbe313370ce7779abdf633d5a3594a41fbad9a79f4a9b46b89c0cfe78f6a15948dec92c4404aedac8b5e7dd60598ad6f539bc7280de6af4c95e7cef39bb6873f18c46ee5eb67299324ee7c6e6da71be2dbd5e2cbafbae4b2d60b40a808c", + "FailureMode": "busted commitment", "Valid": false }, { - "Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44febbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524a97456b8097baed6e90ce381d2b21c970a3f9ad4f6c92b1bb26337f919bd639dd43bd470839153db09115e2862051f33c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "FailureMode": "invalidOpening", + "Input": "012801238108394529333e45adfaff59edde33727fa766ee99752921b472893600000000000000000000000000000000000000000000000000000000000020010f69060fb771fa559a9e842e1dd79dde8a107486e801707032d93b5965d0cd48abb6bcbe313530ce7779abdf633d5a3594a41fbad9a79f4a9b46b89c0cfe78f6a15948dec92c4404aedac8b5e7dd60598ad6f539bc7280de6af4c95e7cef39bb6873f18c46ee5eb67299324ee7c6e6da71be2dbd5e2cafebabeb2d60b40a808c", + "FailureMode": "busted proof", "Valid": false } ] diff --git a/evm/src/test/resources/org/hyperledger/besu/evm/precompile/trusted_setup_4096.txt b/evm/src/test/resources/org/hyperledger/besu/evm/precompile/trusted_setup_4096.txt deleted file mode 100644 index c22cfff7515..00000000000 --- a/evm/src/test/resources/org/hyperledger/besu/evm/precompile/trusted_setup_4096.txt +++ /dev/null @@ -1,4163 +0,0 @@ -4096 -65 -97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb -854262641262cb9e056a8512808ea6864d903dbcad713fd6da8dddfa5ce40d85612c912063ace060ed8c4bf005bab839 -86f708eee5ae0cf40be36993e760d9cb3b2371f22db3209947c5d21ea68e55186b30871c50bf11ef29e5248bf42d5678 -94f9c0bafb23cbbf34a93a64243e3e0f934b57593651f3464de7dc174468123d9698f1b9dfa22bb5b6eb96eae002f29f -82b8775b874067bdd4479ac237f8d56036a742c17901354caaf38bf8c70e696650fbec76f0cd941ed8c658f44ea359ff -a7ce299c79c7d7e4f1adecd754c5aff8a720728ab27f5737b7b399f72724407ac54965088596375b8c876665ed8e4ff1 -81ca4c808a76a6f217f8b0540ff400199295da69b2587b7be6aeb56447fa4fac08d154a27c4aa6082bc40660078d36e9 -a70bad5311c97f1f3fea5d3375da1a11ba948aca41609ea28666dd343e07af766834e1256dc685ac1dcd915073250864 -a91c2911a658ba79f56abe30716a3398387630e785b351b07344022a04b2f5c90de5573bd6e8048fe8878dde19336c5b -a8c560283fce9813bcbaddfb78cff93efcbc39b33025cfad94ebd40942a9fa605d2a947dc3a1f03c2e454075892e96bf -aa14f07fbd2c1ce7bd995e335c69b5f675ea573517c1834e787b30ab4fa10aecc62ecc5e617ac8a539af1aff114dc9ec -87f03429aff126b7c5a918423da278e17b5f48a4cdd6d34dba77a75f4f99e26a417e65d6a8579bcb2eaaf1d4d8c64dce -b1ac81ba91ede78315f712d524e9d821a152203f04141ba77f4e481ad5881473dff14a71788ce941f0905b429e7ee5b2 -8f5c2af611ddfa3edf7e442d00e56a24d615bac848c05070c908c741ba18b67eb2e82e6651c9b3c70fb8edbf051810c4 -aa4115b19221e4d17cc335d4f9b0aad22df566231f2286d550e97ff2875cbc419edfa189c4ecb24001123b95c6aaa2da -b363ba913969df0debd4e2712ae6e9177ce82e169ce7e0ff1d7616ef8e352aff3efb40fffbf7bff1b21cb8a33e19b455 -b1013d778727d20466778cea47e1bf56a77168a8ce1b33bb1265f66438ab2bf4a7df4f4142b8681f2993ea9baf798d17 -83b7250ee17d8529207db97b73c1c4a92ac076951a577ce2fe3a2cd633b461c1820c139ab36a895a5962e143c6198386 -86d180bd2f0a4919764e6f4e846ec0d5ebe44060ec1e529ed15101d7e531bf1b8f9412916ea5aeb93b37b2d7c6bfb408 -827451462c79d74b504c01bda199481b3c70416f66a95b2216686ca4d48da48932b0d323d0cd630a1e86e8033e832e5f -b789d217cb12c334fedff0ae01f85b96e968fb98761755d1ba3ee17934e8fbd83172225df7c0c6cb99432a30a0ef8c24 -b730e5412dfbd646b0d2fe084a1a32eb5596c3fe8a5bc0f430151804f9e67f05f70b522e9aef08082b0afdc652a1d213 -9987653bacd9bc1659b17f6964aec06ea63b787813d4601bee0479706aed5595ac82c87ed4f96f0cd30c19e1d9510a91 -9506a9ba38f1d26c35a17c7e2554e28eb347a19cef523846a2559fb80fb40306b2f85bdc2c9fb98c2267df21c1ee3589 -98dda58de74c0cdaef97b2826b4a9d53c9e9ea592dc0a755ccf5b3fbc1264979578563f5979aaa246e679918053c5f83 -b00aaa16841ab53883af481e2f925050f5f7bf7d8088bc696f55f30593bdbbaf434f5d2b46095ed097b6cdb96c8fbc3b -b463d656480f89335d3a840a7b9398877003985388871b148ba708c60f9857c7585ef17c8b2ae67fbb191c04ad61e692 -80af54f3d0584126e23635276d650292baf7e3e12bb06468708107bcd80937d36575721ee7472c5f085ffa71dbf438ad -94ccb8ade84e834685110c96908b42e10d2184208f434d7f98d96cc158e0c0c95135979600e5e9f465d5846b0bb3c787 -8e13674b00c633d7cceb4f6ecd61e4f99420d6cccf9db5e81f8c90f6c661bc76e10939b83b56c225fce8565f525d4fa4 -a46a15b2e671c1a1df2490768dec1093caf537e1a21fbc11ff8ba8b21b9f2be8d50257027d9357df20d9fbb1307d7249 -b8ed532d48b0533a3084d7a5eea7b401255c5825e9a1b80ed81fd530cd69e347d152b1ad8a899acff7d68e0103bbfbde -ad6b7df980ebaa24177d830c4aa522d6179a9a489257f60ee6604cccc2cbe90fb1f72aa9d5bee0d3a88f73b179485f56 -a56855e9fcf62ceef3043991a93ec24f8f6b5667ef5fb7ad1771249ece68a73580ec3cf3e58a009ca4650c01241ad172 -ab2f25517d4b0b33d317eb78d091d3c3f98dc352b8a3e4650f7005f9327129e23d95f38eaeda5e9b51c50a31d20a4c20 -a2d4071385b8a421da86f39739eaadcdea5685466feb6ac083cba0ea4c71dbbdf655032097276d703f9a77a4ca6fab03 -a8681d7c258984f01e92e92c95738692b7bbd59c3a802adf4dda8d34add69590b080391c09e98e3b75c085c9f191e5e5 -97685643da6c07b5e5fe91393122813ba11c8ef3dbd43a03b3a22a7a1603201fd516c1929418eafb14039270694c239a -a7bb3b85d6101e4fb0bcf540f52041cdb3e819d517465e342b832f0e91346a9a18bdb38845ea4d2b71ab87ef3bf59f96 -8afc90b7d35336fdcf8f81cd024e921e244520ecfcb5a3994f2bbd595366b68bfa792a8dceb11e1e889b11432c9dad6b -94d9db7bd04f962d8d6caa3b7aa0f19acbd58a09d35ae187158d77e537d2fc65215f51f1afd62d4ba378e7d176a680f9 -ad62d7c01b14b6f97e6084ec9f9d084f106a7ff3d603032e6e34c027cdce4b0fe3c20ac7931f1209439a59c9fede4815 -a5b44a87bd0ada7498e011e495a2818a8694746c4e7dc9d24c0c1096f54be6439e08c1b11c10d7c4bf68fe392000e971 -828626c6609acc599f1bf216e9a4310fc3cb227e0d2e47bfe3360239427c8b0cc300cddf92456a5c36620596a6d37027 -8380f91baac6447dd39886455ec5d99b874ac114a3c6a6ded18fc4ef69c2208ec19732428d8329d200a69f31792b852e -85a8389b522b0a686234450165514127006baaa3907f6eb29c976522591a542ffb681b3b88c4886814fd7ba3cc8110f7 -b8ae7949ddafad37c0bc4d48325a7cbcd3096fb92c04a027c650a03cc609c7eac250d6a7ba341616bc36f64f1b4c8be4 -8f9b9d2c2ab5c85abe946ed9986e0f304281b277d4d48c7760ea2331b55a9e9a1c4d53a6bdd83fa6294f421ca7431e29 -9464b906ea8bc994b31e03c5f2af2be0724a43293fd42cbd2263b2de75a2ec04832d1100ce62ac2c0708f05fb6bb3ce6 -93d923f6805e7cf972d8387b352d77215724a3e1f5489c4114fcf0b25fc2231963eda872387a1369a02b2e8b888d6427 -aba4af392884eb7283fc5611ddc1cebfecf9477462e951bdae650e311606e129b4424452a3a14717146f954a7fa1cfc3 -a8d0bab694d116e4f21fa19ff8fa4c6fe4061dbb54cbceda8235a7e05159737f87e008beccb90df0bac9c7d572281903 -85743e3ecbac7ae04a81a09c2961397aa4bd20401533cd24d5fc0693cbfbdd2b37bbee6dec2ae5d0a66250d1fcba6944 -80ae913447d7d3f6c54f9cb584aa1603308146daeb3024c8e06ede66ddc97821df09f9591453e9b617b828a02d54c719 -803c2a64bb1c68890b5f1909be3aa180830ee3ef316d3aac38bfd909e2b19d890525e18e8fc2f405ee70ac14f5569b3f -964d2968724eb790f2f42263fcaaa1869c373b57b3eeee904f8b36f13169f07d5e29cb2b03c74d3a7adb772e91d5a59a -98a72ce71a57262aa058643a5cd39af64cc9eee88bef7edb003143983f29d87c7f9658b1ec89712f79f6f79dc24a6a45 -91f3479c5d7c76acd2d51883961179efc975c714720187cc9c0aa7aeff71ca1b3e2db5b0a90fd3ff6abf880ebc49fe36 -84312757edd09f111420bfede10ed3c1fa39d1723ddb9bd4d0004c829f0c1eb060e9648fd75f2e5427a67a5b37945a9f -95edd726cf4042a082d786262304c51d8d5e6a89b1b58e825a11febe5f861d5ce076bdcb2fc0a5dfa95eb2e5b0ffc32e -96500da38f942871d78fcc46cda1e72944c7888b538b82e2a979f149e5061a20c7602860f82b76510d02efdf3a911f5a -8ac62eda98bef8864df243696b53651a02a391b898535d2d76ac5a8e9322e0178a290c83f5afe72ffe80ad56183469e3 -8ab2d4427fb6d3da5cf6c59835bdb39fb0c2de82c213b5de77edae3304458ea505511bd98fda95bdbbb9058bd5e92c34 -ab67c4344a5080930029ca3b803883ad05ca004ddefb48d5164e71a1c6dd96b27aaec70f62b39bb126ce1a57bbff1453 -86c6bf91686bff714a873a78b0fe449db5317a5172a0a14eb3a96b2997b888d5d3f440de8baa32a6966fe44c3625b014 -81d4f1e9d9e550125290d993a4886d46aac8cb29dbbba1e608aefc3432569c5faf14d8b49fcb485d9b75b649ad6b2fa5 -8594140f253ced6fa98dd90ab4f38899916bcc6f1052572f182e46c00752f3053c390512338a0bc8f8c27a91916b855f -911284d4fad4999bb37590206d582b9e62ffbb815f414fd829f5b2843e6f0e1a132cd64464c131d5a0f476469a37daa1 -8631a6a4987410982db9c0ba632023a5b613f553b6b8ffd3cfd501b2417523ba8cf06741c62f24b405554bd93e39e626 -906ac35d22794a10a7273fdbca499fd921799b1ce9414643779dce9e1ec37920a5aa2caceb4b70a0eaf56c6032ef1b43 -87374cdb8b7a1ce3c182b31eec465d435e35df782fe3a11f421462b48cf56c6fef2a9cb8ee4fe89672ba7804156d9e3a -a1f825e0246eee506c8ce40f849a17f75e8a0d6fc3f68b6a4dd431173b4fe997d30dca53005829e4e2422a4077ce35c7 -875ad0379abd9873f6634692e33e9b36353e1a0d15b13d3215eb591244e1f236eb2f8f75274ca7f096179d1714fa68b7 -b87b4e1acc09c5701fd9d75375ab896f178c1b3648fb9a2e2c6e1478778156decc32cd390766f3e80b36beb1e3a6bdec -836ca80949269eb52395776ac5ceb35b7df717a981c5cbbbb627f73c274aa8164e973a7b01012fa72a02404e878a9918 -a770b13a8f07f74e5a75842b18f2520f6d0be42c865a29dd81bfe485e69a83c40ad10ce229afce276ccc9cb46c54b912 -b4b919322bba2866baeed38bf0e2389d4fe6ab6166597e87dbfee75acac7c2f5ad3bef55293b56957c103d5825051bb5 -b6171f1bbeedb3ee1af368c9c9f327d1dc3e55aeaffbe15f14db8038cd72540b62fe65f44ad0b5486dcf4023f0e91af8 -8e42d0c1e8e8c2ccaf06edcc3c686aed56b8c987f9d68f20937fc088120a410cb92fb0ab45bba5db70b86876015a6b72 -937bcff1af9685fd0d1f6616acf91d97ac9fcb1eb96d49d1c880c9945c1fcf1414f63d59fb78348d08a8546f6e83e407 -a6eeb4873c0531fbcd407c2e702c68e4980fa77c9c032b9913b89031702cfa56f335fc413576c37ac4d523357a841203 -b3962b5eed69cfa27fb94edba74b6cedd7569352ea71861494dd579da96d9743655b6308e54f8a42ee6d7e805c1bc0f9 -8eea944dce7202b033ce734c9e88e82dd760c916e00b217cf1f00bf6ec5f20e21885d5fe95d6138871d167de4c46359e -81e6c7b356e2703ee333a9dfeb2b54260636422b9bda118e0523a20ce83b30fefc2f019e8291a8db05d207f0fa7332fb -83817f6164dc9e8e2506252511cb9871a8c9b595dde45f67e75ce3505f947b3fb3b804c18c054ad13b1518a98f59f008 -a9ab4dbe7699e7982cd750d7effe031f273fab6b2e024a0b4f8beccb5c280903bcd3f2400b9cac7e8c94e157b4658ab6 -84d2e3bc66fc6b59a1ee98b8981ebca0901d846c40d207e5bb5004ec9339d28956d16f054af52453f6a7ff3fc66c346b -b24bf0f69c3e86f610b6d27885ac5f4556fbb14e8286681538ddbb0b4921aa0d5604fedef0daf4a514ae15268a640174 -a4be967f7f31995562669bf9587f5463bd1d9873fe9169687790e75961efa5ce2252fd21276d022f580de23527282838 -a3f3c4e673b302bdb91fa3cbdec88499752e6ffe37e2215d69b8a426f4da98c3a10e4c659e77c656172e4e8b1b1a41bb -b704ffbb3434563bbbce69ca7e812a8bd30757b1e90630bf3261735f9ea221524b36f97dec324ffd209bef45bdf6f2b4 -959dde49f15c663a2de000195e182a11d8c396c1380f98322cbe5521b697bc3bec3223ca9e94ee2734c4ffdfb6a19e8c -a469685143cd82b78d7b1854c350da63819d9d86670e9b35a72381d0362cf5c3f1d24e22ef2ea6a12176c9dad39fd51c -adb97ef4463e5e13d91b75a3086d72a841a60be278e9651d9ac5f76c9537bac5eac33424a1ea00522b3357fcefea0738 -a4597b2ced7566576e71b4f105b5ee48aa4ffca93901e9b626f7059824f53be3e8f3560e6861285f3d97fe88054fee83 -a18d9b1b81564447f798ce5966bf10c823aedb14b143972eb4dbbba9312fc79f46635aa016cd20c53be90f170f06fb84 -ac4724069177d3c6ac1b72ea2a7d6bc5ac3d4b2a4dbad124152fbd170c9c1038cdcf255d162a25c14ae8df11a3849945 -892683f64179ba84f6a447c5c7489e3cdf02474d2837dd7bf3b82a4dd05a6461ce94fff28d65b9539cacaf47dddedbc1 -a68ad797bbc1b2909e216a0b3f39aa6c3e4dfc7a49f81a206b530ec0c6ba30f871e4a0053625aeb99448026ae2e0a6eb -964ff8badf35b6b93be6d97209d87f4ac8847be1c2ac4bcafa1db5c3f604f61834c85b3dcf58af50d09bd03ff8d78f27 -b76dc9ec64b1fab7be269097a18a77144623d37bc656934fa1562817c922485e69b18ef40413ee309e100fde645fa7b2 -b2a812be6e69f284580ebdec5ae2cdffd587bc7eae10989e9d2f290498b1eaa934b148ec7783edec300be5d7a9b34af0 -85ffcabc623f8ffc58c5f640f857e27b7c105359315a3969f346e1366acb2af88f4acc025b299b9c324a8535c380a2c5 -8d0140f79fb8ef02d13b1d51c4ba1af5b5ffb19322f88912215d4198f9a592f7ec6800c8a3ca853a3b68f9bf0353a13a -b3174deb53c1ebb6a1e16c915cac287573b70fe4e0036e8e971e8e807a77362ede632f6e3f29cb87a80a318213946ff1 -8c58d603f6420e3f55522ec2853065125af4e7773a909e28296552f7f8ec4691ada9211d834dca38e118f432b6cfe03b -aa7ac268e155ff074bfc197844e21fc2a9f9aec9b50d9cda63f50d3c4fbbf9221e6fac3a6ba0f7e4cde71fecd493a15d -a191337721bc9fd2d3ec2ca6f6f97ca2462ef5e207464bf9e746a650a67d69abb5f578a8238521cee3f704b275845e47 -93521abea8f38c103ebed3313a3af8f27f03c9a54681847f4201bf9f72f1f63064b18175986fca64f80b4380905e894c -a1b9d063d6538885f9826b84944123d7d6027dd030aef29fd6229f4cf5d32404f7dd0e899a0c8f4b6bdf4649e8a8966f -a15d5497f0fd2fd0b2c2e5df58a25a72a9d99df8215951ea58c15569d312c6f096f78034f6a8502f808e649f6cb9283a -b3c275306852612362e1073d0f4da3ce598dc5fac3f3eefa22ccee35dd57a4caae347b43342cd1f6a6e068d3ea9fd30c -94eb678e0700bf39caf428c65bbf2fbf7f601c39e382570a4df9186ff1dd5a958d78e051a5fd084e4f75536a14b7690b -97b13995bbcb8e824bec28488994a830a9c1f34ae4c1a16d5528d57f09e4c8b5d81677ea9f979f0acb8cac629ee09c85 -817c99ad48bc05bd4fd29f952dbdc5ef56bb02f3442c18e3b91cb6d72ac2d2a5df901c099165ded1bee62c3ed13c41e8 -a884acf980f6470e11cff347692d8a7cb7860d4822112f7bfeb02efb05948ea98c837d5d98dd7a104aa36eb8f016a0f4 -95debd2ed23a23a16a393f59f666cfc864f63751238b73981faec4a85b4c04cfa11520c9e4cbe4e23fe80e86c260093a -937b4691c59453bc6cf6468ed5b17dbb25496bfa3817798562cd5fd86ab5ee35745991afea2fe271ce0fbe5a990c41c7 -b4da98c879e6b475c540ff2c5501299f0e3e97b7b93beb45faef1253f7de96968898505e672cfc4a3ee7e20c1f72c256 -8ec9d806f344d0c675bb5ecd47c54defb5f059a5233dfb2d459632b9b22edd6c4b8c47fd7899ab13e35f37ede9b124f8 -aab4408410abb4d2cd98694f71b5452e6fab2690daa3066b3f9747e7dc40b57259d52e6fddeaeeca227b733d049b9694 -b85a12f39808961c331038159255140a61dedc56050345a2eb13b1f7d140ae07b353d68d22f2cf60925fe66e598213e9 -b61bc3bd68bffdbe9731f48fcd523491da04dab83add49fde390070513b9ad87a489010f1ccfe6f54e9a48edaf88b5f9 -8f50f6d8235824cf25031f09e4b139bd89c1090269dae95a5aa0dacaf5f9b59c329a5a3cdddf9efe6c77cd61f481dcbc -91a543b85e18f34361d7df5ece8504d456627fbce65abff437007e9109359538a03996e35393a40f0586f962921eccaf -b7557bc52931324dd4c58d0e63c89a8dbdd2d00d0baf79d81d7a062aedd2de9dd743ea30fb031b18c806ba03175d7e1d -8e056b842a9af7aeb6c0d113a3acc8bfb5c6a8980fa81869747f75abef76b7fd20cb67694e70016e3de6e7821cde030b -966c00fd6472bb13ffa531d8eedc145ffb7733114e0f4a6a9fddb34ab7601f6cfb056460f757636230b692453d8b31d6 -a25d85947c6939547fbee088e0131988053c5bb23aa2bd48ca764f4ef2b29235a817b8918d1de6865695977a95711e9d -958567f217ce7a6d74861777801663d7175eeeca8ff62e240582fb603ac91dc402331034fb4855632352df2328fe0233 -85e53f3802a7d32dec2db84fad7f8c8fc856037cc0cd4ef9a8988e97ab580d4b929023f1fcde7633828b5e8bcdab08c7 -878d1fbbedee7f7ff72eaa3848d7f6bc3cd13b40149278b3afe5e3621e6d1f0386f8ede32971d3f33be189c927bef6f7 -b041e880e4ecb254f6f8d92635a1ef3be3d5d885c751f247bec2d8a016aada6a7fd2f7c599f458ee466886abe721bba9 -920747dac9f35ba0b2670f82c762a71ee9bfb9e490825fb7ed613bf2548ef4ea00bc01e9d2c952dd9c56f3586a3ffb49 -800005cefda1ddb860fd8974342fe315d227902dcb5f3736f8b9ad1fa2f8fbeff8c8ba0eb3f0c21a6706f288ef4bb13b -91f2b822b728fc5d1f15b69a303985bab14c08df5e929decbfa5aa5689f3cd93ccfe19ab10499d31df9d38c84039e492 -957a909486abd85b1e627a4739c7d212cd03f2b62952045b704c415acdf2e6c0cc627af93f382836603f33d1a716ac7d -9733ec7a30ed833cc1e7e0ada4badddb1cd1908bcbd3d4e4694576421c94090a9297aacd7f42d9d305b87d711828304a -ac2785a0dadfd246fe12b63f759e9f021006cff4f06b2b5a9986f0b02a40f29513feb1c9044af6e27d1c5029b1e1db35 -948b22bddf55f4b4bc26892e83f70b882a0458582ed87fbbc81bbd037c946d833c19162327354240c42e05cfef55394b -a49c5d81544028d56f4caf8699477bcda589c65f6754dd40a487ef88d93925008dc7fefa6d458619d51a54b3edb5e5c4 -ac57b8ca2d0623f5c4137cada67afd6935fb75fd82567f2c57cb22e89a0562d3c0716d5e903fc06694a8c2edbc9a6f1c -ad52af6a0cf838bbca5a97aec5d87fee1aec4fcf5e802b8bbad1b110c31ed777de0b0ebf74384bae68289af20e351bb3 -b0c7c48d734e5a1b37674465eb07a629dbdf8f9080c44a578f3dd687261d9d1cc5cbdc084488c745c9114fd998bfefb2 -8a2b2ccd4c52d15bf7aa4a8847b8015bd53f58ee484589339b4510ef08a27db56178c15b4d79a9c6eba1ac0b641eaa61 -98f659a37bffd7a9b7759bb111412ea9e9eec483645511590f683064eaf15e1b101b5eac3b98f79ea38662b1956a06d2 -af6cda3fb2479b6f2d959f2d03e52b49afd12bdccd7a65a1bf6b91e345387924d5e355363f79bbe32a4624287cf4c1ac -a24d325d8c2dbf9d2e346e3504154018937efb74246ee0658e68d148d9ad0f4bfe348ea9bdca77d4467ea1b3dc2fae5f -81a729dad3798121027c29e9310d56e36a48c1c479cffe674cbf9131c562f541d7e6c52c2718025d3470b05b67cdd321 -95bd5cd6d9895c775e58cd4296ebefa51ab9e324418208c3c4d073be59410497a4d0daddba6c1e7373abc08e13d32b89 -809fa97a229b056def6b548902d8d90c873e496db6cb1b2d448709b9ae08d9b9762559666cd96b6bba396eebbab4ea4e -8bcae63cc680494606e44037a3bf6dc7bae2e723e5ec3ac0451550b8ca7914ee1d4bed0f40adc3dfa45f8f80a36c11a5 -b3474711a0f933cf269e97e4e1e98762ddbbf49dd72e468f1e8a2f89514c1c35cb8db32d08dff50f93e50db43bed54f2 -9788a37c3d95310627deec58ba6d9e0324618469275276632a3fa7841fb127c8fefc1b7392064f2eecb508056bd346c7 -8d031fdb156023e185fe5fcac67b966baf9c098fddead4a6f1a3cef54d8e912d0de2d1e1d3f3f05da538eac4af5b6973 -a5efe72b86a714dbbae40fa69fbccf41042e0647d177cd60275700257aa583708130a64b2f9dcacde4fb636b5cbd5aac -824092ea32eb7a8c619182d926f292cedce7ac3d3fc64f60d00fcd767649e1d6cffc20dd9c1d1c8ef6f64be315d1e2b3 -900ad22d3b63376b1ac80c7343a58df23c03c4e7d6e5740dc10d8cdee793be07fec09cfbdf29e1d1c6484d3077630d6a -826815005550844ac5a6e831de0e25fadc49aff808cd601d70743d4873a341e3f0cd40d490422c87df3f3c40921fa723 -b39d189aea740c52b03660c0abc8e796cab72193ed44a4b1f59fd1ec0e283ef7d5e157ed23741eaf289cf968597c0900 -968ed61662d1e656e039900912ab61173b49d2e24aa6b7d3af07c3b04a2c89c4516540934aa543bb48ee14153780d10a -a433b8b689007ecae7f1df15d442b0570664a2db6318de66c6e5fd68884615778d296bd260ab7d07469bfb5f6d8c94ca -a69ed4a0f39920d1a62a01214daec143fb7596212e2439583df9ba508784ef4d2fe86334f0f9a6b7a3342ec0a72ef15f -96f260d9cd88757e7c45201d57bd816f1cfd37587ba17a64997bf7716ca1c2cfe16a7119c36acf1754231f303058a9cf -a51f2bb09d30028eeb0860e2de38094623e5b5514fd5d591a7d4a9731cd4b9c4c12c5dd6ef409e009dafb10d185d5346 -8abe821036140ccb3ff9063dcb5e8b8724cff1cf0784b8f44486c8380fc51715cf55b443cc20870f426c4874be93caeb -acd73facb964d9012ad12405dc866beb52d8de3ef81fe966cfdb14d22a19bbd2e7ad3a29cf029617b9d6510ed323c6a2 -8f18f6883c8e4741cd6c52e0d3335dd71b5571446ee28e8c27cb0625f77a9f5bd0720d960e5e8970257907f503d58a9a -b66457a91e7ddcf56c8ce4936a209c69ee53d71236b72ea386f7719c8b8c9b4ba4ea19039a8de17a0a869da427da42e7 -80b1de58bb3ac5f264e0273061f485e49413de604b5ade73ef81bc249f5e89ce97dbec7d99b088b5a2ff65c0bb93fa76 -8bdf276c88f80371ef0ef7e1224929681629aaebc8cba3c0db0b258be3c26cd17268f56369832f564b1679be33e98c69 -943cf6fc88678816da42e4f337c730eb2dd59f8d738ea638a799e8b77214ad7e74723056bae96b100f9a972155885d26 -91c8c1a8a61f47119005869c11edf0b69d0bcf40534b82e46aa96bb6107f940e582b6733f855144accb8dc21d79acc39 -96ba98bd291faa0904ca0398d6c50eb5bc2ab5a389c359ca42b8909f41f4fc37dcedc370ece777d5035074a597da503e -b4598e6f889d319713a9896161a6c9bd8575ca30c21d3fdd37cff15dc0141ce28dc536f73957e6fc8f6185fc0adb731d -af1ed593a0547c26ff729c159ef14bd0818f25e7c1c6c51ce8ce5425bd2526086eff9fa3341279daf82e480bfe431230 -8c02b9ad3aebf156c80fec9b012241f3794d736adfbe4a272faf505ab818cb121ad2ad7c2eb1716e252d0a2e7ee6b246 -8d2a8a31784c446eff4c2ed7b004009f08b86c87a4786a0b7be3df36ca9130a0ec42a58d09dfede1279a4a6d3d37b501 -a78b61be13005b1718a3aa3deba103ce71e1ff73163c76815f9cbcc101d993f119ca128a25c51a12fa52f46550c4b609 -b990d81d7aec9fc50d798eb8c38b40b162004f78730e9ed4a103faeea0995bb654893e557e5eee9b74046ddcaa70617b -ad56d68777d0ed53d3331b0cfd44503b27435278416ac2268965d8ef711fdd819c16ef5499d8d7fddadd229c3d0d4bd6 -b5110140b9ee542ec03c945cd6180ab1af205537704fd408fc4490d799d87a3f3aa0f1f0ae9c8daa55c1757f7bb53cbd -b7d8a4080c5eeb00be4540a00e65e744f4c7792b518c9fd2dbdd25abd0dd89e76563618cdb92e4cda0fe3ba4597508dd -a880b33af98cc0bd1065767a2600145e6e326c3cee25602dd22d531c26c4b8543f846fadf679e26749c929310779d858 -941f124078990e03310cacd79e4a38667f4dac4dda4dfa3173a03c14aafbf538fdaa01b940fd5be770c1cde0a84bfefd -b234e9d0f04da6efc5aa5c77bf71cb05001cd193178fdd546e4ec81875830113d3d4f1512e7405b16d0b3aead285999d -b857bf6f62c4b19ca9441f700ea6676ffa3b0c7138299533ede59a9b9cf9b94295046e7eafcf1d4ecaf0341898ed6b15 -a2b0d74f17d3387566bb4f17dfef214cdc6b61dc50698fbbe298a7e2f4a82d20aefd719c5e82bbf4ba4fee0e2e35b4c6 -b5ffae433aafad3fd51ac137976e2c22661d8a286b221e0107baf19f5c8f2f6c7eac1e785f145bf7c16a497310fbf51d -a69e9dfb14f8c6cda716166cb69f06879718656c9f46730d94f194e2888fec371a11c9701071bf8690e57996fa91d213 -a1f51ecd5c5d73155013dcf02b327cdbae9f9c2fbc62f73959050cd3a0bd66192213d1f4bb56a85cd21343722ff3f57c -ab3e54b8f4829f1115694a4be7d16e8214c94387ae783263cfe145f965705d51943176191c706f6211c8be2699dc79a9 -8cd6a64c5d30149ca4dae4fb7e8974dce1200aba9be9c8cf9af5d43e40098746ecff7bcde7ff84a0072138dcd04c2771 -a52f6fe24305bcff685f2d047c9a8d9a1f70c2b416cfe55fc137c6b5b185029f3644890418873665712dba4886e3fc07 -b2e8e3d2ba2d64815bafb678dfc1180534186eca415bd8cd32b303bbac6cfb637b17200aa7cacb953e656ad19dd5c9b4 -b5412d1073b3b80bf0d18f791a6d02727cd9c40a86ab0f13ccfd847bf4e767b8b79aba3935194398da2c9cf17c6bfc8a -8bbaee84aca9089585d5ff385dc2ee6e653d0fcb9088f98bc5fb1c6c83db026d9a73d77c33c6cae3268be90805d862fa -9691343d1a8b7fcebefe2584b28ab5808764ed79d8f28168a65ca90b0094e7920fa43e56b960331209f4b8465cb8a5bd -8ea475e12088d558f5cf6dea2da71837791093a622d5cbee608a95b4c8a61296255c1545d454562e371ea0e2cb2e0b1f -951d6b404667ccca099d01328562790d1e8446231d7d22bc2b1c4c6b15785bf59f2099accc58817a06d24d59ff4e6a2f -a5d012687f341eb9c783c1c2040388eb7ad662cfb2b84cd94d270bcc99116939aea80440d7ab726f9abcad22fcd90274 -818fb57b7a8cc59f06af054ce09dfef812f8f115eb2473d06c8f20fc50cf17423331aae1f843bcae57fe4e2926ad5aaa -aad27bde8eaa2e7fb1a9a5ab531eb41f475afdc89b7f02085f7289f8f84d172fe516d0104560a40c89e97db7e5e836ee -b8cd923efac1b09d9c6b1d97a0c1bce9fe4eba1d872eaa3c0df34dcff2e7ea2354f1b31b69c6b266944ec8cae2a16865 -af628e772d609224aa7cd3eddbbfe965fdae6a05cf6d14959c5c26c4806043afd5fef803091bec710c6854ec095ba18e -b662e1d32704d96919f5dbefc3cc40e7d41d4124c5865b46408c2ee5c40926eed71fa3df71fa7ad349d476d9a525d7fc -ae4c5512396f9c26381394ff8e22b1d6267e3d3a5d3fe48457450694520c5e173716572b68fc1dc352761991abd262b4 -86b530978a7e549e6ca014168fa4aeda9438bcd3a29f7edb1f4e9c712c16faa58b81b028c25a8e90b421b61a1766d7d7 -97b32f1371f76dac7a449295365780d1bd03f290a041b3d19db3f14bee6365a614ca356e7cbd6f966260420b451f6117 -8be97569ea08d0b6c4d46e9565ae14f79d1990f192a26ec935a865cedd6bb5f69f608b069f7d645877c5081fb4a68c54 -9733488f48de05f57f623752b80b37c91f6c9afc0f9b4df4cf400f3f82b137bdf06fee82190f2a4ad4aad20e964cc214 -a794f6dbf155666056529748a792be13011bee6ca10e0d55c82c3e84c5dfa1f370c8e8abf2971a75c73a4ddef3da3319 -95ff5d16c0d9bd679738257a1f7f309f257c20469f2fa41bcfadc671ad65acb249793defab591f515bb3d8072e2e05f3 -8d849150bf8dc3452839256ec4eb65cc9ef87aa0f90dfea4d1d486f16ee855d6c480a8fa4b6cf8d536e435f9fb7bf507 -b61c29121dca2bbc6024ad2f487bb57b926786ae60a9e7a721440787752432ba9c7e1df86ef0d74c2592d23f0e89326e -819630a678e4a5e6adbde9b292f5c8f2b6e3f2ecc9bcec60ba0f8502e503f697b0ded4f0f7157b60ddc976ded66713aa -b3525b071e26babf669ae2b98319b3516c083e797d74bd5b9b0e1f67792a2e8ab2c60921812690b5928de66290ff7b86 -a344c6670718b9824ae62b309813bd31984eefb5efee38052cd06812308edcc39fdee165f8164629267bc0e98fb50ba6 -81d78d54738817dadee7bf70a468a51728de0e9775f8779fea5d0d95e55b2004377b4e2db595d420f017af18a384d9aa -848c97b9413ba6ede751ece925ba57b8f8ae27168c5d46347d39e0232a5eb42069a85f1ee2d30d8b94fde574642be5d1 -b020048c5a5a2d186df628550c6f61a204f16e6eb991283e975de520c4f916badc999b3b7e9402ccc39db5c0b510e2d4 -9298c1aec9664ab3fe328f532428e9b037efe8412ccfdd15e33c9c82dc3631e49f84e0d2d75dced85e3a4e0fd0f3f2dc -8c4a78841f51e2f8b91defb0a3844933999f9884e2b324bd89a01e482756758b1b5a278289163409947c73106bf934f7 -b328a9db915c4bea1783218c7668e2bd7a8fa62e52d3a005a43590041d34ff388c0555b044ec5ff85368352a3643b7eb -8a395d89469d374c1ec472c4d571ae670849549d05124907faae5a086519686683c1773d22d290ebdcfb8dab926d10b5 -aec52b8a883f4ff68fa5f418cc91c8e9d08ef324544356b0ac56a7f0980fab6b376b8f567e357ba96b408652b8e568ed -af80f0c5d50ab23d8ad99c7fba504f2f02b7307b5ae5ff529142bead28d69c3d55f4e2226c44549548fdf761ce30cff2 -af73700803caf7b06f5453a620253731de33a458da01f5790106e9418fb59e7aecf6fc1d1b650e1c7b3456f7a55d4301 -8be3ee3caa86cbe21ce9998fe1c0de73ba6481125ef28e312002377676317b5ac4c27180086fb83794efbf86438ad27e -a0439d051d06a7fbd5ab83f32f0f95364bc043d9d934ac64df7031223e731d7992206879d567e77f35badcb7623f03fc -b99de1a16670fbbe3ec26ccd37399e2a23c96813c26428deda4f74dd3afdbd28cbe47e074379f6094b85176f8ab349fc -8a943a039aa33f38d3887de4e77566d446e87225bb8333e3ea991466c15c6487077c6decb9cc10e5de6af03e6b81a10f -80b109fb49ab810121fd411e4cb85773a1004af2d257e85ab5b4c99aad8d66e5803a8ca7b95587197e88abaaef0b8d42 -892148bd190b042fe9b7914b8aab073c0d19001158087077a5946690dd60d99a1ef372ac01e372a434d00b0568a75fd7 -a266dcc9ccbda054e396e1605eabde6cf79a028b697898090e9f34a4a4e0b771c121b8d470b14130a79cebc19f8d6e58 -b1ab30b97c76392712b173460c227247cac50597c036f674361c63c3638a4c03420fa5b7efdacd0496a9b83956cf5d06 -8a33c46084f669455ba089b369b9c8493a97c131f09c66f9347873504f35d6b94a09483b2775656ab32a12c7b9766ab1 -b77a7c1402edd9ae448b7a606ba2eed192a9bb8f852b647b6ed689b0a3ccb81a4632edbca4c113750f62643a0626e2a2 -8586e85e3bb07b07a39ecbd822d2adbfbf1fc66cf2377fbe6b1bc38369f86292c6cfdb5b405a0bc4d584c0600178321f -80cfe5b1b032d5a28662d13772fe112e9b73c997f8ef0fc796576bb39e02189c3ec0228d192c981061dcccb9dd3c4f39 -873c085029b900d1fcbe93f8789d635e3a8fa558766701ba9fee76dcf05abb6cef518f2b56c4ca5e26f3847cf23bfd72 -ae8075937a23505f51a1a26f7f54e35caadff44ffc43465368daa9c330b553cb4548adbdb04e24c3977e35a08841c36a -b1c7076afec527912f7648bedef633ea0e3b02e5fc3fc495779b93e8a9f64eb503f46a1372c8dcd8fc2572c198112da2 -b5233c4545bae360b07c4411776218a1d9040bad1e788e099f90149c58258ecdf01dbf246ddea48ac8fc2dcde6f34f20 -b62655a8376ce1ca225dba04cb29f1a95d09e1a20b58f0330c478c6acf931ae52268779d6cab87d9074a362b9e82b205 -9684e676088b409052773bb740bd3577bf0dc15d0392ea792393a158e643b165f8cbdd91cf355d5425682c77f2a91f34 -a892744cc0c428c97bc929913ada86c36f280f49bd1603e21bf6b6abf8ed195cb05b22e586f0c841ee02f234731985cd -a62c089a73c6dcf3f7d957719c7d452962ee851d6ed8c4b57ade8a1e57156762c348fe5f20adf6d6ce47b4e98f93d60d -91b29be6022d43937df9c597d19e23cbb83cb6f5b764e1f7db6cf60dd9b3e9c79f1f617c3101c60fe6c7af9b5719fd5d -91d13fe99d7dd7b4744fa2fde41bb51f4edbefb2189ef3ca5d337ee84ca3f728e300aec19b96dee18aec090669c85400 -b17a5328808ca929b794dbf0bf3a3fc318f8df144a892ec0ac2163a0f7c3a4614d7ec433b66bc491c05a286fe986d986 -84a9e84bbecfc2aaf8bd623d79bd4240c630b81ecd55a50198de21758255207238179a345700e65d9bc6eec1a1a1985a -8d428be451efbe630740449ab3677ce6f69d94d75c5a9d91d14b2493a838260d6418be3d4658fd15218eabe3adfe455d -af11126224f6ff0e88a09dbc0de6db3c70e3db3f6e154deb448d044100f989ea41c6c0259a8ecefdcf531f892a957d82 -a51716b900a00277aa932bb03fb61eab3bd8e74edfad6153a06f85aece6f832af710f1477d883dd8e48931deca12bae9 -9542a82039c2d3c538f15da884f090622c5af556c16370d21bdd6544208cb17e0a30e511b0af4a618e8ef70d0c43af07 -af76f93250bd7bda2b5e30e6f88416ef6fc8ce0cb614515a1f8d81dec717077209493cb47b79e8b1a62e09e394038338 -8fa8d657f1d584b06d5bf41a52bc2c73853e4092290789df04eb8952c6eb236df601a1c6cc81de420a424d8e748dfc38 -a6e93e27421b9e32b170d240b4cf2710c97b49dabfc0ea25759c5f61937eb3da8d45a6400f8bcfbb42bc9a7ae9b66ef1 -81848c8d66d34d274b21dfc10bb36fb9497a1b152aad64a8f7c874e58d31d5dd5f39e30e6000b6d7b444e573da1e043f -b85692a84154f87869d97cb5f16c81fb0559e097fc37473bb11dc9cbd311ab91a46b01aa9debcada590992c2473ef0fe -b565371692ab0f0d899d8139d3eaacd213e7d23d6f5df6ac3409c961aca019ce861fb4ca8317f462be01e8c1dc7af154 -82ae2bda0228d36343f6153fbc41fc5c79fafbc03c99a7926c624dfa28ed0a1d215e11ab83cfd438fe5d85d7fee50363 -923f38a2f839e165fd197e1711ad52673deed9774e0590ff63ff9a9985f99612aabe003b9a98db2407c2878abc6d9b0a -af8d5e1048de3b813308544705eeb0facbd604a0ed03e66c1d221be64cad35d71748d2a55d1ff3049e1e5053c7b1f712 -a90a4b3b9d3b7c87c34f85c7643fd67dc771caa940c9e2ea81294ce6c072eaed698368a0e8056d7b819ce3d73de4424e -93a106e914d2c6892fee866602edfbf8d03dea1918d82d511e528b99c8423c260c0d103bfaf9992e0e24638b913af737 -864cb44b1adf5a59ce7baeda0ddec3a0ecedd42923205dfabf30dcdb216a7b760d8895dedab52ee09bb09e999486b521 -acb5f2bc1257c49c7df89837502e699bcb9652567c1716513f258f021755092954f2dc65b9766ffd9a10584bba424c7c -86653b3a479bf6e10e781e316e61437af1abc988f59399bed8fb4ff128f5f6d53f50a293da58774acd42b8d342e52429 -926b7b90eb7d81fdad2a8a59e13b1573970e15c10515954b7c232c37955755b6758178314439ee6c3b0c881d4092c838 -ac05f011011a354f0e16fbbfb7e9dff03b3cf403dcc449eb5c71067128e314badf4d4dc5dca4b8616994ecdb15909c93 -8e063c6601e553f33abc64f9553db5a19ea794a1f254d5a5f7b8ff2db4ed9d180f68ec919a0f83142c5710813baef4a7 -b6e891dd4d44fd54120b7b8716292c27d4bc8744d96253a841433cf4b07895606db4a3cc5872c480616b863073bf77e1 -8dc623d7928234bfbb8cd0b4fce5c8d9a9db848ab0af967ba9c49daffdf719cf8b55e1dad0b7e421571b8770cdfe9df0 -b5b53f7d6b5d1af75e5a1720281feefb8c9039ef7f1e1969d83bed5a2f73cfbca91dbf4fb8179d9b0d3bd06d1207089b -a5dbce9e6db637e053b4b4d3df07b724b50d11eacd3327ddfc5aa8f37b9a5bf628cc9b428328e16cacc552c1dba505c9 -acb82d6c9af9af0dd426a07b1aec81b388b61042bd601546cde248730ef85a09016bdc66dd014447fbb56fdcc23011a7 -a41692e96f1d775b3a9378b3634495a8350dcfa52b4b2b7773b39d36f7d349fd5ee9a2b3e72769ca98f2319319890216 -a0b4bd6a68ac5735539cbbdd78ee4faaef7d6488eb7a11e091d94e315cfcc49a90f204f636dd8033857378ddd67cc153 -ac3dab32427b0583159482f73f94236980d69f9f8f781b93f44aeb43dbeaa740c77898c38c57677b42c248b9bbb1d673 -a6cd1090b97826486f59a056ed90cde29f2ed821211391f2f16e66f1e8914398348cf6f0df6d3acaadab31f0382bb5bb -abd1252b722aa56010e3bd4119f2a28a852e9ac1a8ce68c96b6da9d00fac0c9fa70e67cd4afd45e0a8042a810b8e0a91 -9194b629ca80b3bfefc0144553017343d0915aab59faa3d0e2bb3720dd3c8fe07804be6e582c6d57c764be96cd40f2c9 -b6bece03ae1c5935eb38b14f0f64d9d0b4410c02ac309e085a233c74bc3e67ce63edea56ea37f4532e8b864aecacadd0 -b753eb9184f5b30e77bcb5d3487323e0f1178f1ab3e15130953381272209a97c3e8084e810dcebf1ea7b22f0a90b9c77 -87dd4a76955bc98326823cffd653fb7b7eda5df1a971b72ec2a4d25fb3958b9d6092369539361069e7e4f1dc9343d929 -b0f1e8b25a2687d98cc037272473b4e3f33cc8d49a3c83a335d48b8a0d3ca5f84e8e2bde304ade6f7d50e5f3539d639b -afce1c0205adad1ce52fcca71a99cd6df9da5b748209c2ed1013b5b7d484b937bfbb26db9e9f8e77c081e0a0384114b4 -b363d31209c075b94441d1a8ddcc6bcf9eaee78f8adbf0992d5c7e7d638a02d58e19203247443c35d700fc8ac8a1b7ef -a0aac7dbb08a10f6cc2c6a4d37aea6bc3dc034d933f49de3dcc79bc0b7a011b1e27df7cb882d155287436b72092a1da7 -86dde01fb7090c80fb404afdc9ec64ac40909b64c4e16460a4c862c3a3f857ebfc0c3122250306c266cb1e9f9f245934 -8b3ebbbb0ccc466c72afb4c27ad99d2d4e98b5aee9c05bc283ea3332e5f67a3d9263b71d16b20db31ad4d8f48174b0d7 -8610c492ce130e76c06b7e0204617087ebd8f285cc3f007897c253a0e1af50f80a825ea7fa3167f882e146402fd342b7 -b17f04a257d3142005b8517dfb57d28661604eea9050ce39c60ba9a05d23897114c59c55af199ed186034e456e111cb2 -a04cd806847686ffe023db1721fffbc26160582c239d5bdef08f4730e2fbb64c341fbabf1fd831af6eb84a113ad7e2f7 -879018340deed1fc762e1b8f3a8b78a40539d6f917215621b725c0a3aa347eeff60765e5ad6f4a36bbea51ab77f88726 -b421e65891dd0c6641e8ddf479b065163897a418d723fc6dce19046501e01c616bd19c9d5fd6b395e65abe0ef956d53b -89350af1d432a8c209b69f937d2aa20a24d5eb95c5b4cec097ca3dbbb3ea9efcde2a8c56c58f8d7901b96a627c45df9e -a32d6b31cc9efbad4bcffd8b0ffa46b8fa97ddf3453ed151d7de1d03a02cf233f07415584893155d2d7e14b9534921d1 -8efad47caa32277eb04137c92def618e0715c1e77b5053b0cdd60fa03256fa1c9fba9aa86fdf1c04cda9c5450863d58f -8dff9d309f7294ba750158e70474c978d1dd98739df654945f5f29fedc607caa06b2866c93a0c7b830ff9b26955833a6 -84bb00fbaa4358a2563abf96d2434e4a26acda87b189cd8d2aabde1323dc1eb2eefcdaba3b90e9ad1215ee469745b72e -b75acb924159ecdcf49df587d5ac1b1b04291600a4f530fb7cb6231e7fd1029f8cfc957c891a59182518480c2947f472 -8d2c671ad0d442664a0cf267b39be742b1d3760935137e4c50195695bdb99254c4a4d5830634059d96dfb2b4e214b067 -ac27b31843caa8140e729a01e7d0229d7c221feccc89ffc173c11a419af3db0f8a47a41cac358e15ef41f679a3f0b96b -b0b3e33c590bc00faeb83f4b160748fea4fad3e21dfa324bc14a138ee8c5e18743b6bb27cd0ad7c7c28c2b3e92040b0e -b0d2882c5a0a21fe05b522f2e8a4f43a402bfc961874deec962a1e3d039e411d43bd3d95a26d930c2509aec8ed69e2e0 -aded1e47b3ea6ea7276736fbd1896297b9ead21dc634d68ee56c20fae3da90170f30ad0642be10929ecfe7de5ad8ce5e -aefe525c0dd24d6c0a66b43ebc6403ac75bfc322d1a22f76340948cf3536d2ae87290ca80acd3e55d2df9aaf0fe6bfcf -979d1510d3271ff1f06d9cefe30badaece436fae8de70b01ac843850f678aa5f48821dea48ce1c363fa35eec37283f3e -b8e8d10692f1bad943052fc366291c134a0fc7ca4696feb216aed46eb32de7333a9ba4f553389e7e58c8fa96ba023f58 -913353bc585c0248a54d4705b5e29cc778f304472446eb4baaf30bafa30f2ad0643aaf21196a6c4d177b11eb4e2ad5b2 -b25a0e3b9f983c47b8faaae8549fa7d00d12d7145e1b232d1813ff94058ed603957a340beff25711075cefacde767661 -8515151729ce9a7984af3b94f74880a2402ff853b99f924d581fd3935d8ecfc80e2a1185918a5b1c4902106bd1561ff8 -88e4282ded5e2163874f6464236d5bdcc3c484a0fef8ed0da8d0177973e8175432b75afcde2a4d7d6aefeaed52fbeaa7 -81c31113f2a5ff37250f395d6722a43cebe2a267a0ee40ac06faccaffd7d6eb522103f0431a325aa46a54e606b14de84 -9302ade30ccd62a803b9610a397661298941a644b1ee9d293c63a6c3368fa3557dcf6bfd0c9b44c5c2a6be06d1baf663 -b4ff9f1f6a2a64c50b0a16980ca7cdcc297c6f93e11c580019de52f58381fd0f60a66d3e010fa7ab56bdd250e7b2df2b -8e57eb61ed3c919dfa0f0cbca2cf559cbede5bbb1e89ae4849b380339cb1c567c98fc2c671211fff4df1a058d46a42bc -b3d5b45b4096eb088523d16bda1c6aacda01473533314961e6a8de36ccfb35d4b717eeb1ee1bce47ad3b80e9e5084d4e -b933ff4d3c5a77cd7cd32926266d4f05198178ce350f7215e512e71b07177ac1ff89ba183e424138e1fbf088ecf86c24 -8cf430a6e4eafd23bcb5ec8ca3d711bb56ae719c8621ecee964ef3bae7c53044f7ab3d5d0b911e09c7543e56c1e82e11 -8b3c34f5321c9ed48024196e1e941fb7a5975a045a5a9de88d7f200fc7ffaa0b3e500ab7b535e02bc5c35fbe420e2c3a -b3c235b65fbdd5c4c2aa45271b9e51674f9a0383a8ac383b0de53125a67c87261540a95b8f81ffe67ecdbf3955b13814 -aaa93ce79ed6e7084fe906c9a1002435ed6829ee3d1380681b902d35dc9e5a23a214ae12dd4fb76691b0016f28d43651 -b4c9533e50ec58f75ea82e2aa7f735c4257bdc1ecd0da0b6521d1442fa61f19e4f73cc90972b47a762f5cd9af591d957 -ae0255dd70befe7eb979d41f9a7407040937e7a879daa64353c66d524d3d3cf1d5e854886a6c32c142f4673c56a4df1d -805fc5ea840d1c2e6b35ce586309698530f056b41de7a403d9e7d81efc2d7068976e8e23bc0b9ee256f39b15bc4f7ecd -a8de5055b6d2310b6ccb211a397077b211683b05c7e68e55ff05b546c5c81522e6097a3c3b4b4c21fe06667071beaa4c -a4014d39b23c13efb4326956c5ee476b1d474663950c9e3e45aa1345037be862cfa14aa1d03bb388085bdb4ba9d70a59 -aebe9a9ba34d6cd3692a8bc0b0aff5648e16b36d6c123e636e9260386642e29d52ba71ef7778481c1b1cfeca7fe6acba -b59706380c9271918ee16a04e84e91046caf99623a0120aeb37a7a98d4c954d3d880960086de6cb180c8b922ca1d7405 -8dc0713371808850f2137a89c33fd55ec2df6a028e22b2679e09f7084d5c471451187f6488fbd9b5100b84593540e5f3 -b492c55e470c35c7a7efa536f3e7c1e586b623c6669ba6eceeebaa1f81fe3b8b927c2e522fb12e603ae246d9566e4d23 -a5148eadcedab9ae08f5db6265326fa415aef46d0b24155910210338500be6d77bc9fa6f6e284a4c2552dac09167e450 -a0af7b66c8a1319ffbe7a0180795b442cffde153f9a871046d6bdef959378c3068813c516e280371825af06ef2320b15 -95479ffc4903f252fe58632e833d63d963469e89744d5c91315d38eca21b98f1ad6fb3ca77d620a6f97d9ca3aefa1f7e -84861bdb5880f663a5d9b5e89b59a940611a233d82a9895a330464f7e9b7a6965c2420704f3adc61f876584d06771f03 -933c374f176381a3a63fa98d238d3b7d337aa745528e271168f5b550fb703664c3128097b927b5922b4ae8fad30d5e40 -a3ed2c5080c52ad1235fd93c9bbf128b48ba8abe364247104bbf298582930bf3faaa4f4b6103062a4696e68c44f79555 -94668bae91eccfa8ad459588f927bd1a169af834a76132b2f2d5cda26a91094cb94661e3c59f7547b290f827eb43125f -b704404a487a7dce87ea8207dd5d813378a345375e8e2c07de349c1448a39af8672bb4436779b3485adc46df2212f409 -9347dacaf6dd678574a4f1a95df79369e3f5543c565b1580f907ecfd17b5d6e1ee3322d83601cbbc6d6ffe0bd2833a83 -92841abd813bd9934bfe945e428193e33ae6d4dd235a16edfecd6e4184abefb8a1f85015ee83caf9532dda380fd678b6 -95c14a1d3a1e1ea18f8a61f34b85ee8a794c95d3b4b0ce6ffc89013c9a80291a9a2487b00bb3de51ca2e4290fead7482 -962fb52a2134123ca31d91027fe9fb62dff4e0542c66b55899a163e50f6ff2c4c4b9c1f5b5b3d6c6dbda40e757c0bd3a -8aa06ae95b0ff361dea2792e465436d810b86f803ba6121ff93fddd9ba60ce47e846eb2d248b28f2c47bccc9457c1ece -81adde02ddc49b6cc89561716a839fdee2879c78d1ea0fc0418a6cd4a2a8189a2bc245bf2d1e535dde07e93b8a5e18c0 -a7a5713055455728d6d982a6650d1edf1a3b4612c9072ee8ee0bdaa3992963a6fe91ca242fe36f839595d09f6a47aaa5 -93900cefff6f918dfb12ccbb256adec89fb8da019324b811398eea03f6fd34f28a6eac2ce5580904cdb289879bd4b4d1 -820262cbf7864213e768b5a38f39d27dcfa7baa5abca557ab575b07c33917f7b0f06f0a6abd81222fe8a5a69d95d774f -a33114d4cc3cc84258fdf252e754c8bb1feb6a130785d35a78b4b05d0f782424a5ce0f34be3c1a14e3bb1bc0246bf0b6 -b966ca0a11f0361e611ab2a8907f78a3d639980cae405d380f3a080125c734059acb08431a42ef3a60ae9331a07e6a5b -9305d107311654ee727182a1683f322a78fc637bc214eae311f8778773e5bc52063bb0a902a5a962a4a26fa0cba3b06c -b3dc808231c75e681aa2bc4358c41f01e371bfa5bd504e7bd2282e35e72a2889a51747cc008dd4d8b2a070c8e4c2d7a5 -8f05cc76848367abf2020461b6bcc1ecc412ae9f114d44715875f25f34d8cd26b84b01fd6c0640648676b8d2d5120814 -8798c23f0ca8a7b23152ce17086f31e2a80533067f15ab4a7b43c127a5d8af3297115a3cd7978ace811fcc38805abccb -99a917f54253059a45103e15e92e1bbdb03e80584a85b658f231aa5947b29388f5b04588de1ed6de998741d360015313 -8b0ce3f6afb5aa83ff229ae1ee0f986ec4d31b113070c7ef3c1ca3613d74e3f23cc1cc81957bddc709a5c5bd85cc64f1 -9035b71e4cbdc7c410fc03a85543aed34a1c0a98e07ddc933e64886f1796416ff3a0f7754b5246ec93d617aad0f53d5d -87478f69c45394f94c67b7196f60aca42823ad92ea86a427d705576fa6a9bead40b1a4106767b8a20411e757f8762b68 -b36901adf577f159b4263821a48fc5888e7bbd6c9f3857968a9cd02e1a1a788c08a566b7bd5bb6be294fa5ab92b4ff6f -8a738b1392aecb35a5a1f12920522997c9016a0455354e41d2e1b81d8ec9b30a90f71492c7bc122505b2ecb0654545ec -a5a422515f17f2bf4b9b6c4b5b94df27ce80826cc3ad2a8579eb6666c67a96355e60bf227b36e1f082d749ade7a38a92 -b6d0e36a98e0518b14728bfd79db76c408f58220111e8c4dbf5bcfbd7a85bc68022456196f07b9f40158037a3c3eb90b -82ad91b812d08bfa815a93b47bd3656b493853bad52656450eb408fc915e430192ae123fb9daf4aeef4608800e818b74 -b8ae5b30118dda7b972464e14a96853147c4b362e9cde22130250447575c0d8d05053202db4c650467dc16330cb54b36 -835d913a3d15ff205497b98107eca77058beebe1aa35ffc20241bbc2a9b4d2019ba41fa3c9b43fe2265a1110b5c2fbe7 -a283d88acbddb50983356f2aed99c2f153b6a8f489b0597d8db08ff7e3b04392609e01aceb37fe985f59773327258195 -b6927dc3318931eac59c6e21def3ca79154beeaa4c57e11ec1f3362aeb33445366dae770e533aaf33c273eaa4f54275e -a6033a62119e077b438e0170f27835597e21c1d6e4acbd53fec7df69bd1372148f90966732fc5c004857cdd44b8a03c2 -acc764a116e31d63f534b3e0e42a3f899d817d3ec32fb4504045bce7ba3a952ddc81a33d48c5b0499eacbef4268bd5ae -af5d1f6a67dc6361e19f222a24163be388033a3fd0d33ad204f4411302668436f933c4a91c6472fd4262397417e3c588 -a2b1fe93eb481d4fec6fccbd64945a12cfeca85aa8b8bbadc4e4ecab2f3ef65616294dc168d6c955744b7c6acd712012 -acb6d3e123572ec20d0ecceaf4916401874f0298218b36a0ce089acef90329204611968c7397c2a518c0a78d02a9285e -88e4457b1c9b56957b76a08e98c569fb588b081e0e420a0d859b70296f648a8d64ff35ca61a39d1b8ac3613ea5fdc2eb -a7d1643b3bbef49b2f9fff326061cc27a7f65228e40929562de73e1c66a9d164d42bfcc3dae9103b2acf27606f18b031 -a66e3b97efb7ce4e81534453d3d41ecd4b5b6e9bb829b07b5afbf11fc6ea30382a0059c33c97afd906656ec19432830d -ae9a17d0044abbf3e6aa2e388a986754d6b0fa35d115e410f69ad4aa114db1af5dd0389222b838cfd859d436aded1b5c -a4a66a163365528b08333f15c6673ca48d7a9b6d17822f1e5390fecad122bcf7ec5656eed2f22fbc6ccb6dd96ee260f3 -b7dd42c938c2ec50c3b3fde92ff629a571e46f8ce128fde7c2d8f18796ba1b1d7eaf7337212f55cf5cfc540c7d2dbf31 -a36bcad22f3408b3bfd45d272f3387cdfbff57e014226dcd1db54bf3f8d1d896fc4fd16640b5d1484c9567ab9322a37d -8c9831fd5f74ffac203aa6b6ce03acfde8a2fd939b79236a01931d28b424fd8f6b6e44522d28e086aa12f0b110e5688c -b48bc95abd331d901610335299580ecec02a263d2b03bb0579cae3aa87ebf5e93dd110e7fa4306d31974099fe6e8f58b -a15e27a87bcd8ba69ebfb6228c3c48e19d79b22978d3a63af553b3083ad13e48dca496896cec195e63b8a4e2c40cae7e -96f3de6fa492dd2d653888311bc918ab832d6342dc7af9155bc7070004e89ca940b7672dce0a1b4976a7c3018f13e49b -81a022bee3593997f556ea53e2ee484188cfba0be4b831ccc048ae4b5a6df9e3b4d57c436caae5cba92486abb71813b0 -b9d8e46df67e481c84d5520a9613aa92750c8e8a1e8f376b8ad7b71a3ebd95d2d191ce538e6f7fde3ac5943f70c670a9 -8f0b52365d944f59d2ed445b6ecc4f88c687fd281c1913912c8e6075c3a59667060b42f2c1589a5955e9f3791e23aa02 -ad07429bab813045fd909b928ba4eaf262b6ea40b353aa43157e1e683b2752c5bf19eea7ab6ebb8daa8ee91241fbe84f -b90a99ec1f31c43060ef649e047bf24f2fa7fa9daf904136c6a5846d9479966b54090ded7093e481c52d872c6377eb65 -8cb05fab3ee23db24c9bac109db52895b200dd115209bfa41fde510b29d9871907d44f689fa0f5474d12314a711f6fa4 -b00d8f280ee21866b01ba3de3bf943a7d0825ed67db03d13a0b69f54a4ab389df1cb10909e831ec0af8f1675fa7dc399 -b383d14fdc47df80be46390420603e7f505052b1a44ebf595354726f2b487f7f18d4243709d347e1e584c28167a0e988 -aa951f60d1e069304222a8eb0338a94c8b3b4515d7cee833864b6c222ad76f6c48e0346c5603c35a3b52edb6f9381911 -b887070ecae2884109eed80ff9341f5fc514d59158f5dc755ea46ba396f6783b8a86ffd2fae4419cec2ed57f4dfd4327 -b1a6f1e4d25f4aade76714e52bc426beaa7592b975f07d0a6b372a3f94e7a3ab0e8829575bccc953195ba0c9bf46e68c -aa64bc4e0d9502d294f0d3e6a1400dc38f28e87c85d3429ab3575c821e1229f1dc8e2c13f03080006bc897e8fc3555c8 -8f215476d94bc2af7d2e0eb68783292e314c9a4f812f3065cf064f427aae165990dc9665011af502f5713f3664317989 -a578c8991e9e29bf3ad7be44bce3817e1c4af3e4a8ba3d82643378da78538787f581b9caea7602b87619e5f8cfb337fc -abe5453b650106cf65bf2b7faf8ff973b7b3be0e6f42983daaa5359dd4ca225edb7228bcca3d71bcb8d77241b320fa90 -b7ed1d027dfa91d0ca5d797295e359bdb1b0221b1f5eabd2ef76ea3bf456f9aa9788dd00ea24fe0add9e3d9b09ae2428 -96ba0f0c5ac0eae3f0031f8b7a87543ac369c22122681cade0ea33a6ca370cafd360ea6b80758476ab94cb07ad6820e6 -966f6191951b998202b8a63e3b10ece69616b989e9695cda84a450cb953acaf9c4f902200b7492eb66cb9ae0cdc8ecf0 -8d7bf21f76ca0e3b3758c293e66e977f83533d918dc445a09f4f38975ccf7220855627de6460d318290daa03a5f5c68f -b10dcd91d6602852783bb76b0a286523a0942e8eaaca4e0ee5bc76cf19d33bc631f6d0fda1c1ca51bb3d5d5c7dd43728 -884d502d934e2b045357e981506900849e6eb051ca3ecf3079b485b348372496db97da384f8d2b5a52216b4d223c90ea -b074162e5d33171477ed48f2f185b1c83e8fc2e7906681f96ed97da8ee86be7476d65e61648383c2766ad9853ead35b5 -90bd3d8b475da20c6e32324e30bab475f2059cd81fa67840a6c831026cf3d5806496a3a25192128da4b819c1b7cd6bd8 -8da4889258cd6ffdf1608af8325230f74abe6a2a511872c2dd10123b491cb09407fb979d80fb1185ebedf421ba22d0fc -96fe1d9137c24fba18b1ac431ccffc01ef1792623bc334ec362751b7bac73c4d4f7e9bdc2d595ad4731c71808adea15e -ac816ee0b9103f0bbdb50cc05f9c5c8f7ff2f14bb827541c51ae5d788f979c00fe4796b86eb9e3ba5d810925c1f34a17 -b231e98ecb3a534dfda5b40916fd4fda270e316399c9d514dd510f0602cbc29e51c5ed60107b73e3c9721f7ada779f91 -80115e104f22ff2653ba7c4e1cc417dc054663d488f861a9bbec4b9e907dedbb985e6e78f31dc16defa3aaf4f88dabe8 -a0dbc25dde933e6114f2ec22445f1e209836585997b14100f3f8b7e62f5fdc6aa2a85ba5ec39a5197c9d4dabc9a5c452 -8d2deffdeb1f0abed8ba62187f5e1cc06a1e2bc49b3e15f73c3d8e574dfba7efdfb762ab512cce53d7db790a7354c56b -b73f4897e221927feedbbf209e3d5b9c08f52bb732dc0d710822576abb7ba5ef0e728d2d95c802a00eba925ce99d734a -970761c7ee891b3ed08253d2c0d28478145d0776e2429c85b4734e5eb7a6416d197d0b1ad3392b37ce8d86fcaf9de7ec -b4c9e2acb4c05236357be37609abc437612244bb4421d69486050e390d5ddb52887a1b3e1bfe968a90f1695d892ba8cd -87caac2c93e192c34b5dabc36abe26a844a33bf63e9b01a668c90b70701360a0417ae3248173450c64034685d913f4f1 -a16ac64cd1a7ad46cde1c93024fdeff724afe228818b72bb66176c7daa090acf58e7fc0aabc582ad22486e46f0b96c5c -936bdd6d67d666274c29765690f4ad9c4b9203e9bc9dd5af558a8d908dfe8d6d4346f6fbbfa69158cdaccb0058ed0193 -b39af8d43ce9d120497888fba0dc95ceeabdd3d84421c1a30fea226e03b78cadca0eee57db524f6ccf1f6235fadd1470 -847da75509ca07fde2277aac9e7622c5874256903a92f7a56382ad3f79d1b3b0cc0b06b2a6b2bd1749ed567e68816d31 -969407bab3f8106a49be63f17ddd603e185afc1c9fc0ca0e90ac415f53923e3c6a69fe488d33403521231c5008bc11e4 -82e25ef35abbd9b98c55a45e7a71791925639afd92780e64a154ad8a94e9807f2643854250f30bff1c5e8806632778f7 -8e6da5cb8cd80d6b8e2321ba3f034ece1813a7b6ee3afac73371a51434a3e66221188162cd9b9ec035326e7e04e74b25 -9868bc3e60478fd0ce37d35e0e4f7695f1ffb7cf2e05842b3a09e832af33c7ba48448935d425196fdaea9c3e8a5122e7 -ac7733adfeba1da388eee6540a127d0eadcbd23770f2deec39edc0bfb1002beacb9a8c7106baedb22e664f37771c1410 -912581c23e3ad0d7eb886cfc22633fc704e530b6b4977086f68f1d9f839bbca3bf0162acede87c853e8ad8137b5cf345 -a0315fee6285a33d4ec60f6c1557ebe4473e8990ade0feff7e008d3be1a709f5f486abe784398734d9ea1193929697e8 -a44a08d6fe0a22849a8f518ed9b30b78367de205c3301fc8159ea273076488299b35c362530436dbb7e21b6b9f36835c -a591ea6ef83f2ec78a402a86ae5b82e330998e18ce66126a89046f169dee58634dfc531b1286277eed49f571df5202a8 -a60d86619b41f59b48c800a302775656266725b44ff8318014fb668f331bec82b3b543ca848a7d40b2718f29e5ce6cd1 -9420d0219d407583fff43c560964e1da06b105043187ea156771b1e4dfb5d5851d06fcfd819c7d8bb6568fa1bdacd916 -97ba0b6731c78eed331530be7cc374a7f4a7cb2144ac73b7c000ca36036f68754d4edccf73ce373dd6c6be55177d89d0 -b4e07b5c1376900fa2dfef8fd1a5a4b6152df7b805d5efc29057d1df2343f8bc841284ed23d2bab5cd1431fb95f71b60 -8017de31e62a24bed74460dbdde1717f3a9cc17e2e2ca9848d77c3b5c364e7e1d58ac0eabb3daa2b7336edcc8a418b01 -ab6e409231b778bbc1ab74c3062a376c5287c0cbd7d19d4ac1d5da1a8d0571864d0723944da72581783cd7b6b0d529a6 -b5f2fd4ef29a2ac847358abf2b3e7a3567b8653a4b9ed8da70809f2affc6ab44c65cd17f255db0cd8315e4801bb1a408 -91b61d5d047e9c672d7312f563b8da90d9c2c1c1268913656f061028748a351e116f524593b1be7117a46f168b3e829a -b6c10b09ecfb92168906191756cb824694caa32c6f2f9b19c51658d44dc330dcd344e7b04333392a8a93c73346a3845b -9431d01a121e6ffa15c32e724dadcebff65f806c11717b050c106c0c80e43e622130f41224533d13be4a8d14a66ae1e7 -a1248085c85855b4df6eb5a02df0dbd5de5a8a82656e1a5f61214885fcb75428647c8545a848960701d61c3002840647 -9867caba8f4be9483df9b48e2bfa024e79e6797adc2198f2b5115d7283931fe4cefc382323edfa1e850c3970bd1a2d53 -89e88c50c43d7e966e60d49b3afea792429563c93550b10584c91e4a827a3617971eb286c39205e2af4e7dfbc523fd8e -8ed261502f95814410fb081e7348eb09f3a3df22cc3ca82a2f071abca0190e9f041e8714b811418caf7e1753cf284e9e -87ac65370073b6bb85a945e138e4d0a5d71ed88739f72b9ba747d2a03b5d4877e8e526026348d2578c752bc4102055ed -b07de38d07906dc2838be840c291f467d9b695c62175c5afa46d80f34674d061107d6fec6847ba5f17f2d8729f31f5f5 -899348bd385a7c3d38f9d740001c9a543dd8496b58807a6a73180c94f3aa5c15a56cbb85cd7124458e2ae44a454a8a58 -91b70c3543b8e21cbcc8a40cbe00cf2ee0372ba9ddc7f610b711a070110508159e6a52e8778b20f0194ca09b109881bb -8ab84d75831ec1e708ec74eb6d6de2b13bf97e2d2262ece39e5ba5a4a3049c8303023e40fce5e87b237bb1dabfff5246 -914ac70dd91ccb6d7b83a5ed0a9250c66e77a815aca17416f1796fc0e1c26bee7acec5de11e65061a44d2d9c35f5d19a -8867260f8024f533fcb75d9c3f2ab113d349504b40f650a2c92bb46aebae3a55de6a113cb6387bf00eeb2bd4719d87ea -9976dd4e56b16fe11533dce2734e2903a3ec986dca6540bd9ca8b758a59a1e45b1e69c0b8f094d42cf7e015363ce37ff -b48c840786653a0f3ed6b07f8f980284c5eb2dd22e9ecd5a0566754a1534300e129b39a8a6d4fc48bd403b351e714f05 -b1633aae7c5e5c51a82aa4e4bf9f92c0cd30cc1067b03364825ecc492fa43391ea075195f2f73b99a11dc49f670c0e89 -8769a592f503bf8ab03d767524d9ec2223c502ebf15b69eb4b3d53325ab366888afbb668bcb380230b5bd74b32d90a44 -87439671fda66bf5989fe1fa2aa32519ef908aa6ab3eb34eb5b7d908e9a7db2d679170cf3fa0e0a388a355b8c51d306c -ae1ca219832c90554a91a7258ca5598f8bcaaa7059c574803b2688d8026df9083985c2f8f4ad3aa9b122efe64e0b2481 -94916e6dca309d9c7afb9aa4c0bc89a3de875a8537cae1fd32258b34782994e5be5c4987577d697ddc86b8d68dbbcbaa -8c5361b85176adf77ab1949d34edd562d8c16979e33b59d09548ad372b8c913ef385166bae53c8fef814a529fceafaef -b968172a6a831c6ae53e876dc4ef8686879cdadff0aef4147c4dc3ccbc173f89748b840a30ad393eaab69e422363bb86 -8fabda060f8bb2bfcd675803ff0a3f834e2356152f88bc79c23f58fbfa6b0c82850f281f7b8fd2a5e16230aeb4077320 -8e5c887c318335c5561e63fd3c3f64edc669c0b03b217e3ae40ea29245885442864dde15751d7c6ab177a91fdc1f7235 -b2f67f9d64650c6b51b88e7ee6d6a796b453131c93a7791cdb2d0a4922d3c913a4ac988bac5b4b9bfe61469886e1e7a4 -96b836824dc2a12ffecc6a053f7549b7faad9808e98bf20f3c9146fab05098df56fc2833a6002eb39c935fd8757d4716 -a4aa33fa77b62605f751bcad91333659e9345967845226371e5f38d5a7f72405d0e30777b485b730e6c62d8216790cba -a041bf3467320df4bb7baee569cd685a65c9d0e431824b7de93ee47ab8b3ab20298d60746fea7fefb5bc82d3f7e25dd6 -a85842f11f490bda22e9f73409de0909a2e61efc6d8be0c3f561d881988b4d2e6924ffaf0a4c40843481892b272943cc -94de0ecf58ef27228f5afb12496c53b075bb347f900b2df98f47ceda8675bc2941aec04d1c8ca0dec0233430f2759824 -b1795a70651be509c0955b07d58a1b8655a2e6c292b939b6c156f0c0983abd7e416cb0cf14afac6ceec85f2c46b83a28 -b6beb936ea1f1639ae59eaf53015dc1855ca0f798d9ed72607edbc6c119741e10af5354c29571af8befd83b8255a8f58 -9424188ceb15c1b470c4bb17c71a37af56c87625e7b7fa752099802673c3a5a99d16e7d6dd8f8b680e89b75cbe7920f9 -b9e22b5df8318bc0ff81003e8208ff3217ba1a84edf6a0b326b7180208d3a9144c6fa54c57ce6d6071ccb1a40eaf4509 -8e5fb55da49feb7a9152528ad6a6766af75cce249eadaaf4806c6d4162f65f3c7311bcf8da72b96f6636cc019546c05e -a55f751de82aed5842f94d1ba1e29976c3d0146267b11eacaa4fc765da8d2acf617d3a65a2a74aa983130851f8c57d05 -9647758fc596b78fb52db58f2ec31cea186d9d4f68692f56e474961b277396af4a51781b0a358a6a6aa8138e46443a43 -9461f6dc72988b44c662865cdc01c0f970f078637859cbe6314fb17d2cfb3451b222cfb93a5c6eecafd1ddb36de075ef -93b30bbf4fa0926cc5483ba9803c8b001aa80322addcc866bc514f2a10aa43bbd86008e4671ea26d8e0d2ffd4bb8f2f1 -b44020d0f062a001bd6dca2bc3ce61b17efc7a121a9035709f01a8c34708ed0c1c85cfe98c534189e0669eea719c88fb -afabce43f35e0d3201b60226c72c30177c4c5d75bac654fd2b58b3ce9de7d83ef01be60514817f1e7bdb525c910b8bca -a97bbab394253ebb02ba47ad391db3aec1b4d03e88ab3e7505730640558c11fbfce42d53b7f85787cb564208d3dc826f -805a34cb0c8c7ade28c69dfdde46b7a283e539977602aab165316e973c62bc65396b6fe2c96750ba028c550de03100ea -a0be38fdba281e0c248933ed73f1119f90e34d5b4435bb704a5fb7c20805e195518a2a424bb483f16500d74f440d4a53 -abbabc7db0a20030c6e687b89162e704720a010d7ac53b9766a9ccb7e02d4ea1926792f5263d715cb97d67f2010288c2 -b9e471a7a433a678090fe4324739dffe238ed7e9a867159e0b43fa80c9c0798cac6b58bc09a389223f94f22fec43e18b -9818e9a42ebf415c6d970c87261645f876d709751c8629d1ffbcba4abc8e3a2a1db8c4c6a6324dbf433c43fff62803d1 -8290ed53eecdb61157cc458dd081b9e890bed5e4cfb643d11b549b2c65fe68fb981d4311473510781945b0ee763a84aa -ae730a7c69866f22d8f9b0d8e17d7564c25763cc77a5eb718d5651b9c5198b2b9d3eed1c066f4985b2f6d7edb0a109d2 -88325e421a1be440175293efd498cd167dcd0914c8827ebf64ad86788f1fdeb3c16d3de7a681f958b0f49046c54fd804 -a8f592d6ba7fc3ab8ce8260f13f9c4886191530cb1d7505d0beae54d4c97d09712930b8f34ad74f1ac5ebedcea25dc8b -81c0853b0310a96674a92a144a14c48fcee0d72a772451ed046c284f16fd6447f67389ff7841d752a025da172d62e73e -b9f50526ce4bee12fc3fd8f3582f3829b90840f6eba06f37b53febc1d0987bbf58107d73fe4373d79e53827270bcd817 -a2ca28f619d4821f450b9431bdcdb129d4f35dbc2a4976e4d416dbd14e378d4d60a517457aa0343f7a5e60a7e246e22f -b9576225cf7e13374d3975703b3850251d53ccafc6feeedd07be2b0bdea63b899139a1fb446dcf76f62f3c03beea0486 -a88df9f6e95df995345c6265af546158499fc0d89447d3b387e7708fa037f95ac9c4e20ed35b749b8d8a7471dedeea87 -a853ec333af8f35d51ddd6c4d45972b68fb36219e34278efa6cce02bf8193d72c6014ba6961f8448785b0a43a31a688d -a1ead9282496e590bb43908dc64341595cd22b844624e02f2daf597f708ab0d336bcacb5862bce3ce23d1a9616fc6179 -b97398d8ebb52535a1ce3a10b2255d358142ff653def823ad9e9ce4ca5f372c6e7c9301588ae5d914b2b921a0fac7442 -8d0d292c7e9122b8d001b3a3323f9d37dca61de5a595f9402ab0e53e941c83f80237a853abe4aaf012a35cf59df48c68 -830535a5a8268d5ce4e7462fca4f809348908ae7ee117312244e0a9c30b09d91b6f798654d8064091078400346614e04 -a44a90d3d307ee3a3c3838ce43a873311789a9b9292c62a01622bb813a02f6defd21b0889cb6dda6d7225009cc6d2641 -a219afe00a9327f2c937afabdf5f10bca0687f48d8f7a2a046a52e6924af613f38cf82454df4f412f5991ba20b7db74e -b448ed4b15ced4de098781793a6e850ea1547d514646fb8f1c137c86e14231ac4340b308bf07813fb813cd02e47c015e -905fb68b8f5bc14834a06d61f3da686bee77b3b590a33c640c82f34e68ab993f8c4897df463973d6d9f0d53f9ac5cf5e -991cb6857dd0b3ee6597aa2fb1f4ccc962cb038228615466964680795587240e6ccf7861ec220a53ede1e2e9752e1cb7 -b823dc0249ae72e2de91108cd4ae6d6af3e464f12a53a46ca583727c7351a67f2d12c911534e234ee187389fcbf1f621 -981ba6bda1816036e75a864f635629a141905a4805c706260e7a5e12b82dfa9de4f4058143065b10a1012adca6b7d083 -8bd8ec0e77a6867057e5393d82132474eba9fcc4bbe025544bab0ada4ebad3d296ceffa3788acfea0a44406e2ab637bc -93eaca3a7f9a0dc809eb9f604905b0cab18750a9bfa42d98d99728a6de6e0f1e05b6e98bb3b0d9862a69eb57ee2e18f3 -90b077d7b7b1651ac0d723978b3e408191c2b8b08247fe2a7fd69afe0615dec09e43771cd845c2cd064b56295e53f634 -847e8f607332129e95eb1f3e00003b087e92ebf1ac9477304b0d54ea38419fe8581122d21bef8d034f788a9c92f4ec00 -b0301becb003dc7cd56ea7d830bf0fb4b85bdb33606d8d9ab2b70c6415ab5c8f4934bb7079ced16081b8f6d16b77c0c0 -9068fbbfcc95fff7ef79ab64063dd9bff0c40b4855eedb39bfced9250cc351b5b3b1bc6c2d038cb6d59a12a41b3db664 -84857e081fa1c6c08bf7b0bcfe7c6d74b57cbad1b67676e99686bcca0b17715ede19f826517dce3f84cfa014e11909b0 -98fbfd6a94ac3e4b53b811e4d275b865486a52884352ff514889313c7a15b07822f76d428533a0f8d3cb42f1e6f72356 -b4faa1b1245aa6339b5bb987f3423d187f6e7e5d4b4b341de87ebdea53b124932cd0e586470cf4a3b1060a126e4ce7e1 -973e88d073071c2cf5ed643d770a45f6be7b230896caf72a2cef10e56ff0a4e032d6ae1ff4c19bba2cc29f29ba70cc19 -8d40b3285879fb9ac0b6c9d92199afaf4716fe21edcd56b1a1fcb6ed298b5ec5b3b64222eb6f0cd1086d41872911068a -b5e338a02076ad851778d590ada4af1c217d035c2505b891163689a554e5a957219410bbb435bbb38c8a1515146f8789 -b1d3e990d027a38fc8a38579e39e199d9984dc6d857bf51e2ed5fae061c8723fed3c74662405378c29342bc4f1fff7ca -8679f10f866804b19dd0b14b24068c1d32908a52149d33ab03394990cc60c0f388eef02bc0db819f92f8197b1fc60c17 -aee5157db1cb7ca8013b0c19201ea1e7af32e4117896b3f8ec0ef0b2a4ded6a5e7c893281865cdae7deff4532a6a3fe0 -950315818b710d3903b679dd0de0619059bea7dac3bf4edc8fd4a6dba81b7aff9bca7cf1972940b789458f287609439b -ade345a6171b8e8afce7a455cb98024d0d91dfa347632e1a5a40721868bfed1c1959300f1e1e39a551d99a4e1abb563a -adde1719c13b3ec224bdb6b44dc2c5f2daad54e7ee736209653a0198a769180019d87fe6bdc37ec1b48f0212ea5a8927 -a3397eba3ed2ea491e8d0328333689f66b2bbed0e1892d7b14b2aa45460a12e4d592d78a5d0ac20bd6d34c88b8f1f7a3 -8613160aca85f0154e170b1b3f1052ba984f5c422c4c25e0771a53469c274130a31f875a0ba9650f77fabd910cb10467 -a91ae4d048c56d5b2383a9d8f6396837543b609d8b0be139ebd5fd31fe4a90071656442ca7f14136cb8205734d929b5b -8e42732269c77887f105d1c326488025f9938cbade678bc6b39941311360408ea6baf274bbf5ffff996756cd2390bf1d -b96e1ca66d51a186237fef402bc4e14f8f96a138db377b7e2c3243954b6f47ca75cf4fb5dd081aaee634b5e2efe2a065 -81d1c20d76ed054923c17b362b50205050f185137ea10559e35ee7e191bd89383b68179c0aa4531eb61abdc239ae6891 -a350b5778e26ee808466619f73900e09bd387849d072c0c014517d16adb4e3394673238c4f4e705d30b4ec2edfe5a695 -a13657433e39c0241d48075ae8ab1efe3680c96d078685c5dc0ac3c49d468db98f2094dd4204f44e8e90bf54059b5807 -a96255abe489be9d42ce6fa76ee90e4bb6a36421fb78068432cc935632ea5b5bb2ab70790ef79422f93d35d1034568b0 -b745d643480edb577b1f92ded38a522236fa1be2944ad8102ca64c3d55f6297b7e0aa1beb082261af1cc334f5a723614 -b235ccbf94e2bbd3c794bcaf84266141c0e04ecdcd7d2def83a7eeb86a2ff4dd3ddbd8245296b27344770f3d5d332f90 -935f3e4e9dceb4f58404ba1a489985001827e96bf6be227a8ac4e2eb8a950d4a446320ce3a245d09d2d74776c7033a3e -99cb7f3d6256ee8918f40642f5cb788f0047a04c482146e70687c3298629bf082dd98d4a4c222fbfea3afa3d7d806f00 -ad6abd2fcc67af691e76792432b83b8cd9b0a9e5e73de21f89ab54081ea002ffd904d77ab8efb6906790987e29c53ff9 -b6de4c3a45ed7898abc037a47507f46f7327c057a911529d3a671286f98e79a421f4586a7ff3235f1892d0cbbd0e7bff -9120311b071d38214e39f4b48ce6299ae9297c7b76ab364353d3816669cba56592fe4c7f1f93507bec7ddc1df471f0f1 -a6daf71681485d01ae7fd4bb81a326d3d2764bbed5d3be45efcbc04aed190163ce8f9d04a84bacf25ec151790f8fe917 -9534da45c2a497607f7440f61943f4c16878a18f0bbce00dd644de88383470705b489225f5be4428d1f988256b70c926 -b2d1b633b4832dab1a530a1d85415e7fa3e4a1fd383ddb898a79c7ad028f2dd8fbd56b83600cf481eb14a073cd65431a -8c43dc994dfeb5f22df9560518df32deb1af43f254acb8e6f93eec3fb3ac80081b39610800d0822246e130e8c5f7a067 -a18174ffb85d13b7edde5822f22872ece12383d79fbbdb8c02bcc9f654cea904ed8c03b8709d70736dd4b308ecc1607c -a54e4bb27d6d561261a3fc48705781399f337448c0afa68c074918d2c14ea7d51263199b01070b7161c3db8b9949717d -a7457cba2c5b455584980ab6d0bb5253dbf2cafea4efe5bd769020b970dc35fba4109d002f5934610b8b4a158252ebdc -877d4111f50f77463b60e07843b4521b2c44629a7deff20dbabd412206a4fe03f976de1a3897b9df7eed16217f03e2c2 -84d1ab99732fed1470f69fdb499dd3de795b055354e89d522c6a7df4d6a5375052c8befa4dc7615d29b3d92ce7df2f24 -93bd139c343d8b83403e04547072c3e546c67445220afd06c119f7119730288629439640302d0628e74fa596e305c0e0 -8157b5ab48d026684f6b51b802b4d8e7f85ef82583d1e8dfeca042b47a0e0f58e30cfdf4738e6d51394b260a4ca7e19f -8f03d5c1720540c29a1dee44ef5c7f8b209094ba8376d8e5eb9b52537d9843912b68562eff742f0a7a07f5faf6abd1ba -a15e4999a0028b8b083c2afbf4968a1f0397c26cda8dd7f6c134c6a860e740ac4bf1a1936849a4f2080e0cc9f8e44387 -8b71fb85363158c7afc3c41422e9a32ecb2d1f9d3c01fff00b77e0ec6a8661e95b552a7f05f4acebee751448ed750684 -b34125432d0704c0638090fc4566780d2d8038d803f96e19ff748325f8b5579cb8867e12491921feaf3c0df949f36aab -968196e10bcdc6cba28331a229acd54b59edaa83cad0f8d14f39d787467bd5ea725a3dc3d50accc334e74c81fd762cff -968abfa40af365986e68c47b4eb3562a72793fbd66a7d1b3804a5bac8137f0a3cbbf5cd306097cbf1a3b95c3414fb061 -85395fa84223dcc16b7e620a7ef6f902f7b29dce7760f57baafb37d985755e65623768b8bd745c8de7d00e2035aba7ab -b57ad86ab3f5cb00ca0855088921865893b6e539edbbd504238df2f9b2fa7c7bdbf2d6eec6ba8e2a70a4c4fa3f459a97 -a2f203ed1f07cca3f8c0d35ccf7a63216ab98c9e71557e829dea45e2c723583bfbaa7a83d66521b08a0718c63973a6b2 -99a3522974525f4ed10623bae83dddace6f9495687cb9cf4ef52c8530b05672c2b226d3fc5058c56462ab3737a068baf -a4a50d127ad06067f1eac2d61c0a1e813fceba2e5e895467b5e6045c9b7308d3678bed9212b98e44c19a1783e0f57bef -a62d103ecc1d5e1d5cb98a0bbf9682ad65774d63f67f95bcbfb0cdb5e2437f2279043e4426d490f534961a2487782cce -b12fdaa5ca77456e6e96eccf97a303ee2d73f547916ed67378835402136c2aa03e63912edf5a67785f7ac1636f6ddb51 -91315750043c4e08c7e4359b9cba25309eedc9c85672851f05a0651dd9b9329bef00a79cfe73ddc308d97cf548486b47 -947115aa6cb3c635bda7f3c5fc3dd0e4881500d74db4c0579e4b9039b75b131eb5db54174b1bb970064740551e6cd1c7 -aff091a9c7e86c80646cfffbf154ecbcfeb66877c5b773b6e8759649ada1094270e57970cbf2b0a4bcde9bbfa9689b1c -81e3cb9116f81e583b7579f9af06931a5337fae0d57d9ef777003f32e0eb619b75b74137385f9e30dfe0e10c2120b02e -81ab49647db2a5a6f47ec757d8427325fe721142377a287c547fbe04ea280acb32d71f3dedf7ec0f67b43ffc5d748342 -84b0e16d8478b798694503ac4a87ff31affe0ef6d2bad47abe0fcb3a2571fc8e4e9c966276a5f4968b2675827a115818 -9567b2edd65974393cf2181d235f877f5827a6d5ca16e77165ef35f6c66370f0c55a2dca5387c02ae73a66b81f01798c -af19f841026271e284548b2cfe9fe7d6f9acdb4759ca76fc566de7a8d835408f86627185fe32e705f94e6a719e463cd3 -83883e1c9d215c90948d066d2210528552093a726f0a27b8342b611e4b8639f6d2a5f95bef8cfea4312c1f2203f34986 -a48019b2da37a232b7999f6b668e2758f82132e15ea93608bb2350d3188297c8ff8c791977f2a083ad9773570bb560db -a1fcc29974eb065a350cdcb4283b2a813f02421b872eb3c15056ef96e2d5ffe2fba0e10ba19a4d271937cf08838e4106 -86f9ec59a1f5a5796e498247c0ef1457ea7ab098247f363329a336a1ee57afb31cc18d35e008a5263e7c401fad5719eb -a903f95675c14cc618b02f7a0401ab67170b4a143925979791d76aacc90ad1faab828fe904f13d155425b2ffd79c008e -8f652c4982220b8e9868a621a91eee85279b13b0c2974472fbba11775e6bb1d8d53309f500fbdacdd432170bc76c93a8 -a9b02cfa052b5808c1c9ee65ade446a6ce20174bd2e9d9c7388a1973b0290debbb6fe82697f09afee6ed01c9dd99b905 -8b4c700fdbcb13854c7b1d257a781fb7449a9e3236b962871f11b31b1f2e69ecfa6039e2d168ebdf2f142f93b91f5882 -a9ba2295980603515f80f0130993f1be434281fd4442ce7e68b2fee12b24e440bc0282df67707e460bc67a4706bdf8b8 -a382b85dd64b70296a2d16d1d15d6de80687dec9cc074445fac8de7bad616a95972ec399bda7c2cffa4247bd04413b76 -b6adb37da1c6cba5ddfaafa3718aa66fe2821b43923ec371cd4eb9e974ebf3d0e94dff1ffc1347cee5c9e19af7c76be9 -b5b531ea7f93c4756e5799118654ebc478a3ab57ea51125fd31c012053c759c8a52c8830b53208f74215e437d059eda6 -89c88a5ecee1931dc027d1553b5aa82dbc5fed2a4bed329809467f79f2712fa5529c0f80ce6891817927d0b66d356db6 -b4ad1964f73d3b7bc338909df2ab8889c4faad9b3b8a5959ea81f44c6c4bec95f0fb6e8fea1fb7e09789c690423e2b85 -b573bcbd8f484e350db04eb263187ae4e99ecd03494058e68221aad8d044db82957f4bf23f71a9634b2ef9612a78ecc8 -93c3dd86f7c3105fe482f62b0a56fe43338aef50f0d10f237ca774f834151273aa653e17bf919e54aeb35343ed790c0e -9069c429e7c6507a755871b301b31c3b4233006c51bb66ea2c9051c6caa52e933ad81a8e879129e0c1b099a124bcb295 -a22203e5bb65593bd22cd5bc6e95a2f5c9a9aac1e14d948a7e0aebce4f009a56623026e0980bd194a633b42f15822ad5 -b1585de69b3014634da2ba76218321ff4ce8476b653ea985a7330290b1bb1445db3e1f3c510f9ae7c22940157e2df36f -802a70ea7fa057a03d12538c3ad6b348a8e694bc6b483cd62c97af8809627a161223557f1d5196e23f13eddce15c814f -afe8b0e94d8d9b44652602c5ad15bb0140456d90c95af4ba58cff528e2834e0036572af867488f27cb2d27d81cf02e30 -93bb332d924bcacc41b4b9bf726647d7cbb642847fee5ee7dbf3d2a0489d71802d959a3e905a80ab1f34097328632f00 -8caad1d29fe712bf09d505ccfc724574c8edaf5fc743953b2771cdae006ad9792a889e0c8136409b8f92e2cab5ba09f9 -8678be67412da4d43d74660df98744c54365cf10aa59e522c59afc3836d115380416cb1ae497ba4b50ad31a23ece8b92 -a48e64a5447ebeb5f6b0e0fea29fd5845b378e83f6b06b79b604081e5e723930a0d4c6025627382f6baba8d47425cd27 -b8914eefa2f5613dfe99f11212912dd53d678ed349fe871781074d5b6eed1fc7f2e5bbfad3356a685c52a3c8a26e7963 -836ba66155facd2a1839f603644aa5520cecaad130fcd5cf379139056d3e163bf35f172a4a1f015924b89137f83d366a -835b70cc340b57a09b1fecac678be381ffa4c4951f6742322c2751cf1c748ffc2b9bee8f155c007d88ca69c12bd9db20 -8e98b4ae7c68941a48a70f703c3d5bc9a4cf6c20c61eb4c1338095920c4f23aa9eeb474a0430dc28d355b15dc6e83b22 -b24be8171a105f203c5bf2ab0797dca8ce61ee07307e1d82fd26fcc064bd8a8a5b6bcae8dd611f8ab650176e694da677 -b057bec8ca008dbfd4982ce4516a4925a61bd68e7a36b182575c6a4044c7a413ecd1dffa66ae3cfe2213763dd0f55a01 -8d270924c541120a18d587cee51711486f09a39444182800355c4193a76789614c6925e6a448f46c1891106f866f08db -a0ebf85c44453153764bfc817364493166833b0f84b7a7c505a955cf3a7d4c1b4d2dd00145220d8a3207758a82dd8e4c -a56fbc83a3f1034337ca0d5aa89a0a18f900c3654d171d47ee86b0720c6a965c09c9b06678e3f25b151b115d129ff7bb -833618f5d13b7919206c8e9666997ef26c04a74844f57150e7268bea540e30b93eb785803535566765bdc899d4f10667 -987daa13c00dcacdfb1f0eb13c38ddf773e7e8e19af125604ede42c6d0907f9ed1e4b8b8c9118b14f9449026802a6200 -99b6e669cd7532b435d01b20dfed29211042beea6de58acd68b6eba26baa1687d80aadff901b5607a2553df047ac51d0 -82c81899cb76ae21838558a1946425c719cf68d07950b0f106b859048107c13e4e83b0f2762ac8590cdd044c3e731f6f -8f1c5f634e38f47cc6967f2a80a449f5bf69585622c333d784263e3f6f027bccf8910da76435a84155a6fbe9a8adc4cc -92d3b5515744115dd20742be1a72a455c6d481855f4366a0e960104665db4ecae8925182f32d4e1d9dd7fb9aa246726c -ac86e14775cc4ef22cafa8ac3298bff27fbefa9b7004ccb16d2937128492a2c1319641062f609d27b9314aa225301d14 -a07e1ac19f4c374d68084415fa4a8068c0be540c8b9d81c0837347fe096547d8318bbd804b7642820e43c284af663258 -839266a2fe6dddc446d4b515eb538a27b5a3a5e1a8246f6df77c2de8267e172bb7522aa7985e0503c68db9cf93399b95 -8a381fa29e553fb57e3780f915a86048aa82a8a09059c80154df9490271aa6b99baf6bb217df43c8ea1265e85f07adfc -8d8806db0093161d7f83aaa2cbf0bfb8cabf823cb54bec094f886da6461397f41d54c39f216d7ff4a8262d12aa8ebfc7 -90aff3f98394674791e194b57c3f4e6e019471df1a74dc47bed725d4c47399e91c88a955612be47e89002f451ebacb55 -8bce2d60f3e82042ba94cddd02543b46cebb8770e9b7833b4e79289d4c491df7f4da0ab69778cef92dd81e5a6f0eb71d -8246fc9424b5d5ae0a3344acd7d6962fba6b68cde09332c262d7b3f379cac2c650d80cb5ed4baeea16a5557efb6878d9 -92ea8547fedbf440517522c687f1d652ae4637cd072147ef31338a40e11017bfdeac42a32808d33522a71136cc3bf26b -84f6a64600184c54d3d5c320498282947b8a8166f09ccfdfd6d285cff374312da57087fec3838a49eac5b93315f03b80 -86dfa1485e343c861286c057109119ce8e20abc646a4411696a3bf4718ce03d37fe14b6ea1600d8a7b172fcca6d08ea1 -8dd3404facfe49c2f096d2e74641c474c9c54cd6121771061db3c1757cdb1cd6813d3ffd79e3b839b348d34b7b4f1ba4 -8870cf255b342ffbaa2dcff41910a37afb29ca6a721774953dec182d95b426a481eac7bc107c4c2ef3df9f70e04e0b88 -b0b843ccc630209b9ab35a69f3aad58c76b2cd3cbe94579b5757350460633217246b342fd098e365fb3ae88d5b7d13f0 -804fe307b2d477085f8d9800c8a11c2dbf6f662d684d6a0d2fd415cbe4a09255e47535a08796a805188e1bad779ce121 -93d91029bce430ecc5f41a460c02cefd3fdcb8c3e761ba26a020e108e06520cbe2eb0c04139aad0c0fe58ed34d8b2215 -830867ec984210b314e7f23dc5b10e6d9ca53789cc447e29ebca229f4c79c9120618a540a9d21e4ba2ed8a811d6c456b -8d7a89ae9d7318d6578c1fa75b3babfa7c9df7099eefc2a9983ffa96627f4e7fc99dfde21b92fef5e0034dfaee35e97b -8eb68f5875dac63cdbbeb5df2fad7c1426939ecb6e3b6a48f737bbac1179ed4cf5a1e6919529878169d6d8552fa5ad56 -861e26c9a31d21839735cca8a384b981f7346b026cab7d60fa95a7ad7a4a370cfb409812ca285090c3f1c3a95e5194b0 -a02ab98589d48b2240209f54b0be78edb56b614b1aa02095ab5a9cec6a04faf065eb7b81bfe45aead551b1f774c60161 -88124374273a2425bd5932a6b446986756379c7eb93d3ba0c5d7cbc3477e6267d9c67e5e956cf6df841bb263d1a8e224 -91a766128a4c718a45db571606867bfe6e1b1049f0ccf71a01138d5443014c9758000a8be4dae0caca56321e3f992e99 -8dbfc433e2477b9d86f221e9c49fb8db67c85438fd54b670ce44b68b62d4c0a9cd56c37a2127fb2adef22c07643fdd3d -880cb650f01191db0dbfe63215d208f70f924380fa22baa0e5bcab60f61ece3c6d4cca0e4363291f6a10aca9649da69d -8532214650619e201bd330865a3228e9ffaf1f64ddd33d206be5616c691b1965814f8bc507fc8a695c8291c2f8713dae -90e81d5a9d8fc976a3bf6ee6d3022107d3a9441ff212305cbc7c35bc9163321cadb352632181ccdc1450f91f51872b00 -94d656836edd68384df1fe61239d40a36a0fadd59abead673e4a2ae58de5e2a6bcc4b980dd9b517e7212726b8ac94ee7 -afa70edfed2d81326f26f111982aafad55f510de95555a4d05d9916a600f3ca6c1e3f66d6b092c91c1fce6c407e022a8 -95cfbd616c2a59acde8152578737d3ed329aa82a950dcbb9378bebc3ec8beef9be2759a937381ed5aec1a46d486d1afc -a0a1ae94bcd07ba44c30bf50cbe0ddca2fdb5db82ae73e53c2efe9446c2464fea8e5de31da4afb99c6405798f0f9a59c -848e10f6c12a6adcf711ae3af8382178c46b90b9ff9970350f14b1a1b565a7efd91eb96871277b86040d26561acee099 -815e749e4a56c3b982b50ef5ed249c4defee558647a5c6062022c3ef42b5ebb219ba770f0de74869bea14a98eec02360 -a4d88794689a0f2e194988114ab96d28f77a29cfff606228ebe030a62eb4fba25cefd59d3d5f2fb66acaeda866f5c24c -ad59a8541eb9641c3045d5cea6e3930b35886da4c96906f701ed3ef90cf74431df3c444174d9071a1657efc8cebdc739 -97ae83289d535707039e9df8ebc73262f881ee8e288f73b9f0d6fd209385d3e2b761fb87ca852e10cc4818384ee155de -b47983e11702462a23e26c8d6407b01b67ad532bce3f1e0626fe3164886603bbc803c688729a64a69d119b15235389bd -b447011409a07a2d9074e08502e882098799f3b649e947de44c79ecf86a63045a19985857ec500638a3baa2b228a79c7 -870f506356aa4f8df7d61449a7c7a8689705388b8b81dfe08fd79e8a734c998a7ba71f1f6e9df085b8aa5813a4ec4adc -a07abf6abcacd7612338b455c1461ff484dccda7430d4e9c5f9b4e5c1cb65055f4be650e6d67179b2c62709cd52a9b07 -988b73c2a71f3b1d6b4734d231c089ad6cb07f7ea6f4b8fcfdd34aa33f09feab6cda91232c06b47e90ae9930ea46beeb -886443bb8d7d6c7634f55da1c5695f1691750fbf9ad2d63621589f91a0205ed4adbd4b905c62effaab235e740a172040 -b66caf1ac38a8a66c43767e8597ddb66fbefd888989ca1ed56abb96ab9fb41937927a792ce422577c68286e53bb4856b -a84be3b37007cc932429ba2b4064ab7fabbd0b77400bbeaff09f8c6b818b5cd127ff8497e131dd8bf4323e092c690219 -a99e9898b6f9b7b1b9ef6f28f60fe2ea71e961b64b262cceae41003f6aaa16fa3dc1c2ab63bf63534718ad812e882a35 -a1cea8f3f5605a5c60144fed53943d3f259e3e33545eb0dfeb211a9dad8d99cb3cd3b2cf5031b85778ef6520700eac4f -8b979026924097a06b3827ad28f3efd7f0e5aaf7920ebe5347fabc61b000631f0ee973b61b7468fcc60ba6e4381ee478 -b5dd7393dcff33d6d337328167ceaa7a04a98e0acf1dcbaf454247e85793fcc9a7d280ab14693cf2cee01afdf44506d4 -8580c90d72c0c83c6c003dcc340553ea547eca5989780493c2551ea9f04225d77ea76acc1bde20fef1a0bb7ec01685c4 -8c77db66f09e76ebf7ac14fe2fadabd41291f7ec5971060580b317f6af0daabe099f9db2c3d09c4c6edfa41211da0c4a -b6dec051200c25f150d3b9a7802f5b7c361b074528c79dccefa77d26ea2f67562a6d9fb8246369c6a60f832fec6b7636 -8620173e19eac12fdc7796df12bd3648c66f78fb83a8e6f6c9077c34027a3acd0884ef2e3455a3de0fbfd4ca130ed545 -b44e3ae4047f917fe1af378cacae2813f8774307c20d54c565b674de197fdf90e1a6da0733e948c3218353c613d23fbc -b330af874ac5d749a4ce1a23f4fbfa67f71e8fd16f6da07c714218be431b2a30cc4ad2594994a7a35f5aa06bf87ea3ff -a5be67aad05a965685aadfe03d66ea1136e6979cef00605e92912fe8f84be7351a6acf6b73c567a20ce6045a703cf557 -a1672ed63df30aabe34e8eb81209ff31f4e5eee620b58074d92d9cf2687e40217169df59be8af7374aa5a9107c5f51c1 -ac01de17b74e2dacfe3db539910b6c370de94e646b6f2dd2a828a381b04f2979f8a62bac473659fe7b6e126f15ed7aed -b978099cd3aec49300ef9ce5561aa30da4d37cb5c697e0b5cbc3c42ccf2f96e53e948fc579cbd24605101176a353a962 -8c8c439d9da3627e9f74da784bab8191552b945bb5bf9abb673659c939a60903e11f37300dddcbc8a495adf5c038234c -8b4570ac55ea349560a4e7043fa17f264dbaae15a2f3dbc5ef8a6579e1f9b5a440aeda94122982fe564f78b615de3e1f -a76bbb163db2ba26f5dcae8267d1a890815a76196af10444d3a04c1debeaa3c7cd51102fd0bff8944710c743f5393745 -8d3ba2494b612f93b4ebab77e6f207b636e2d09a3e4a9666d4ddd5859fdbb9747a88eddb7749356b141a071584677ec5 -a8bfd973dee352ae653f7c7bc7df2b32d790653a3f1f2b239d71677992938cabe941fa609e915e607809b5fa954c9073 -aeb4c1ccee15753d4fbba545ec4ebb05c7428427f087fdc0852a18439b19b1669a3c744a0ae2e7f74c46905f520c3231 -8fffac3ff9de863257a836aff3cdb705fe7f4bf604c2cbe10180d81c0956f723b69438bb8a3aa094fc755e386234dbf9 -a583153b241d31223ebec9a95e11ebc4a657b14056b8ca052aebdd9866140dc4669bef4f02b5ffdf667ddc9a87e0bac4 -93177005082ccf2143f24c063d20068fda393948bfac34af57ca58cfbcd0bf9a0de46f8f41312e83a502b7ad69b8f2ce -a79b0967599894340ef2408b48f42e6ba4f406e5ccaff13b46414ee38e5329ffc145f6c34d8e8acc6aba41c23e57e7f8 -809a356a76d54a05e5006f2cddf0decf73e5392b57ead32ab56bea9fe13c1ad090cd69a8e297fa6e017b39361906360f -b051226cb44ab1bf94a9cc0e4f246751d68f32ffd12f1d077d3318de642f3997fbfb0f2ae1dd103264542c2bd0293e57 -8cac28256b1a82d0be373d884d00e9ff2e384d5afbeedda706f942b1d222694f126ad44f9453fc8a985cf69fe11ad70d -a13b073290de7a2f01a65e429e1adb78cd37eb23c24d6fd5a1632cce2275496179e3c22e0b7f59fb51d526402c0f3f7a -92dab68d1dbf07e5b058120422ae610806809ddecd2aeb9d11d8fcac738c72eca584b88ff52c95817b79b9e0369e3ba6 -b24267fbee28883cc8649c243b13905874e5d97a285b9c6abec749a53e106db0a6fd6fd8671d5b7c9a1851da75a4ac5a -99cdf977dbfc10084b698c81cffb431a9eabb55b1323e1b15baed5984a1ed212ec5f6c58372f965fe18de0100292e26c -b021c697c56989bc8c06636cd623c3672e8885598fd2014f5e560fa2f721f9487cfdbcf4adfa34c178ac84771fbb77a1 -8fd7e3ad3330d4eb1a0bd42801d95ce40a82b43c366abc823e25311aa1ed882446d60b6309e1a1e201e725326736257a -b1b3c641ef4cbd5e9c69955217f53373cbd104916e04d012eb40a24d798e76bf05ed0a218862ce02619ef694c42be170 -a376d0296c0105789e9fe539a5d22bf62ee36a2de4c9aa0f5e57210ae49e2cfc5209fe0f467ed19dc95b9746595255e0 -8a0ec125a145e373929ae33efb978bdaf16041eba684ada612c244bc3e28c7027886e6308373a5ea53c9c3d8e868ce1b -93fde45cbf04cc386507b03eeb93c885da12bfe519df9fbdac5ada735934ea6e1a6cce066d033be66163b078e96e2100 -80c1839ee1d2ddcae1fed77d5f8091ae3074409461e04153db801e05b44a7658c6ccadd33ad682e51e211dd9e3c80f72 -87112961553b4a243875ac8d46bb6e274325699ccbdc40d7d9b7f7e58d3fd164f86b0b1df5df5f980785cb3918dc9b33 -a011463964a319c1ea11c7c55c607bffe0116fc834b8a1d3684df33f77f6e51dbe16a891307c9f51d5b4d205c4530072 -b316c4be33abd10400a4925f9d20ba02ab1feb50af39b6f6120d6dbcf1bde0a8dff7e08c64bd1f5c43543b013e242483 -9555b696d428c4b74806a7d08b9ff17c8512a86cbb13040360ce248de241facc42c042d3779c28fe98dc3ca96a47b2fa -819f54bcfc58a7b793d185d8ffe411bde6207b77cf22b0d5e1b3d9843e4638009c907fdec1966b485f95870da57f131a -82c3f9623bfb8a8ff3573197497c175fcb314addafadd025528f805b7a63c87b0e54b48d46c0322110b0043f7f77153c -abc023b35318fd97ec81933ce55799d8c36c3d55cf59b9efb302b276a76a37c517d5c690287f216ffc5d1fc082e116c3 -a6579226d602a7ceec06d402d38f217b836c8804e9da202bfaf1f3f4f15c24762ad6a2414ac022d8de68fb76ba8a725f -b701d6d60387d4e2308a77cebd210e868eaec10d86532ea18c0c6393475b3976a3eddd79e469458bae4f496da7398fcc -ab202a2acd4ff874cfc147ad1b02d4515ace254f8b828f619df2537698f4e1b2687e004c70a152d605a73ab1ae40fb3c -a7e09ef6c86ec7475eb3ed69e57e0cbe86114ca5c0748069d00b6e3a1e2ed74e4366adfcb4d938023560fd91d0f64612 -a9fc42b05ceaff4312d5dacd78fd2394dfb8dc87d52efb0529595877727747827c1c7e3a3da81255356033fce1f97513 -b0150a1dadde09cd60ec3686256b4378f47dc6a55c092c60a3a3f0bbf586013dc37ed53ba7a91c72791c0d52e4c49c2e -ac88e91b48f031df297c29fbb2cd0d2bcc767be5e0a7db87acc87fcc0f4300cce6deffc0b1cb6fc7e51c6ab13ec2ea24 -a8fb1542a956fdb1dcf90da2672d40c90a4aaa2f1232318b4112816bab660657eb97e3d0fee9f327793f6ba9bf8df2cd -b78191d1ec4615b03b21d7730d48fd9643c78c31feea19866429073f4cbb0d1a67f7d7ed210ab62b760c679515b20acb -967c20d53d46011f59ae675a26aaadbb7512d9f7fe87b7a20c3a84c76569d23920121063235e37cee2692bca3af69039 -9766abf0251cefbcfbf85ab1322f62267c22e6556b7fb909413a7819f635e3ac1670da6f5f72d3bb4b739e12eae5ccc6 -b0e9c5c327fba5347474366eed1ff60b986a41aabab00abe18a91dec69aa54197d3f5680603057f05d5efa0a48dbc92b -ae2f5defdbd14e2c7eaf595b017b4a97edf521f561ca649b6bc2e66382478b5323aaf84f0b90f0147e20ad078d185248 -b841bb6e04d2409a419dff4bf97dd3d4f06f6fa4e5e23e4c85f23533b7f25fe3da9285ba033c6eae7e5e447e35329c0c -85e26db850536cb6d3de259f662a88d23577fd56d1f99b3113ef1bb166456324d3f141a7ff63dbccc639cff68e7ae5a5 -8cc36d89424da80bcc2b9d9969bbd75bab038c0cf836f561080e14bb691e8e0c17306fd6d42522030d4640a01d5c0704 -817e72d50f68dfbdfc9d5611eef7c6b490ef1509559801fe1ff916050429a5f79c8d03c60d2bcb02e72310b3c4c9d068 -a15ed72881c49b545413102975fc69649fd5417f5b7ea9091f8209974024785496fa0682352c879953cd1e9edb3fbee7 -adafd20b962921334f4be2188f9ced4a5914389d0afcdbb485096d3848db85152e2881aed0fdfca11f9c8a9858a745eb -8d8aaea706815f1ec45d9ee470698ff199c40b1ff2d75bb54afd4a29250b094335538dd41637eb862e822c4cf0e2bebf -b8480d2a79cb6ada254435dd19d793598adda44f44a386ccb1a90d32cd13fe129a8d66d8babd67044de375ee59d8db51 -97c17d6594ccefd8f17944fb760fd32cc41a9b046f87893bb7ab2260090de291e8260ffc63e774a4b6b1dfe0e5107ef8 -b5b7e1d4d9683de7193120be850395762ac9a5669cded9226f5ca2a3de13eb13b2900af083645ec35345894de349433f -9405d473872cc9f9b9c57bb9976d3ec6892ea429cbd1b12f22962b74d88448d4ccdfcc6d5c6ffa068d560d7bdc3208a1 -b99cca139a3733b365f4718beb4ff4a5fd6aada0173471156640d8be2cc69f2a70d959b57688f927bca2329c3b30477a -94872ec872f19279fd26abfb132b4a7fd8c485fbdf04515c7b416fc564e61a7b0fc5da9f1a380d2b3db989f1832ac1b4 -92aba716538bd66e35a7bb877cd364c1b8dc3055a9cba2da23c7d9c0a010209ba8afab455da99747fb4bcc8fd3144cd8 -95ec4c205be3dd5df181220c96bba3f4e3b526fe5369035edfcf706c1eca43f29a4c95cfcf94cecfc974e01547e55125 -b48c719d7cbda1e79b3f7ee9c17c13bbac197bb015b344f79bc6785b28a1e9484e2349178178a2fe94c46132c54983c3 -908c495c355a0555544ec6f0b8e0dd0926ef2c5c640fcb89049e6178697625b85492722d42bb5c966aee2cee9981607e -98ded9cdfa92bc8e3664ae90af87f88759503715f6eaccfc983e3ab53f7b3af6802999da93caa7eb3530402ec4d8901e -993266bb366ba46d532973391af7204aab46a3189c83ce7cfd2713bc11e99066b1a5a012bead2fedb09274e7b362e8be -88d462a3a17f84326b1e4177799d6e9c5f4ef57152cb83ffff4353a8382ac8be7d50381723aeca77d33d8f07fccf69f7 -80438d9eadea15c90008ccf4758d4e3fd5a7bd02809eed5b683f2c96a15d24524ffe75683b7167d42a47161c65d533a2 -b9e7dbbd3d3d0d86e347831cf99657fb269930087920637ac6cdf185d5eded3f09cf3eb27759ce3f4b46f41411e2fdce -8f0215f23b4945470f74b99607c12c36eca41aaaf99747f522d8531244b668d6ab8c1096b9b5697208c3931e1fefaed4 -b2c8d8515ff16beae04c855b4365e450e0ebfb423acf5da2501fea76259f862bf29738a858a4093b98c2a444396249f6 -b27364a7258c30a59d1f13d358eb49dcef298a92bfa699b3b91817d2f324be8fff91c0b71cabf26747802a92582e7dea -aee7d6f71fd674cdd8dd1f22195981e7160990c16647c871835d988e881a3d4c52345e74f7a54768fd97a65fdbd84567 -91356cb2024f7703ccd662f50baee33409c28ff13bb5eb92fa93f303913e9bf31bf83b0babff4b5e3649003ae95492e6 -b744e4754043d3ed85c3bf6ccda60e665568dd087548ac70670b90328509d0d5013cbdd07bf603949067e54d8094fc2a -8146cbea5899401a80676850d0b43b02d376b4b8f02ed63a7d92532d13689e2c02846df79cffa0f33ff81c3bf492339a -94bba8a1508c6296d3dd5d2e609d6d732ab2541849deea5436a4a9034e1e6f1c8d26f6b781fa34dcdae7cbf8899d006b -80260b321d932e1179667de4916428c1b77ee1ea537a569dc64a12da5ddc85d09896939718ce08ea7e0fe8f8b115c408 -89d4640cbbca5d105dd67250f3bbfaa96d7ce19a89f8d6e188353f3a9b8737f2db1707c506f8ffe1d3144dd1da371920 -92f5962946ef7190fbb7bd3935427157ffc815a52ef44397ead3aaddddc82e5f85b1edcca1e9082a500960e19b492614 -8b89240c9b7257cbbfcd6e415fd035ce33bb46c773569d217c82ecee5dc2d66eedc9333e0b043616b0cbf21744909b60 -a3d23484916d2c0ad1b81fc7df70c97d711040799cab076223e0ee02a45a0fe9ab564faf7a225982468f3e62e32424d0 -b31751386bcd471b5858d001fee15d566215e34d2d62556c51ddc60a834d3f1acf18c415c23a36b581cdf4791f461ce1 -860a99003b841221dc5ea2bd7e226e5aad72db8a5959d5d4dae8a86114d30b9e8915b2314ef867e9c2a477d9424a2d94 -ac925b330cafddc7d95d115a9e62b2c135acd22b5e35a4aa789f4318f03aabef818805845f2532e9504bb19f69171809 -95d8180cae0815d33bf8854f4590be652f95f72fc29f0c519ca9bf3f490ba4a724b23d9054e08e3d31bd61d609a8f0dc -994f223740ff95764fb88de1ad6dd90c9c58c0dfbf8482e1dd9bafc20c099a6772acf40569c54143f6697fab72772296 -971d93cb1e7aec5defa52815bf202b11de6a2ac9c5d4c0eb236cf2c4941460731e12b718f4a5b980ec6f4c54c3d17deb -a341095fe5adb96dec2be367f09804ef4fe77d553102ddf7d643b7277992708e84be9a7748a97a56f065002a97dd7cbe -843709280fba29d446779b1ac6e31bc3ec8ab8082e8b063ef8d2f3733ee77a4191b55772302964bf867fe1044dbfad65 -b7ccc71fd0d0c9642c32d292ae88ca369d1fb5cabb97b1745c621aee41da8f94bb580c1ab23664c1baee65e97b21f0b0 -a9b41f31be84f8ba061570633bd9e5f4d8af6fcc5276c25d9ab67b2b88c1f8c2a87eb19280cd4fe7b4c04da8b2d02d7e -93eb14ce0632cd325429e1c23340da9655d3d7c2b42a4594bfd5a4e07815afc9eb1ac737228771492020f6528c0b7c61 -959aedea532471b9610150657b895c5f51ca950aaca910df137dbda2d17184173cf2638a2a0efea3f61d82b6ef8a7c3e -8ebfb50bd48fbf9a6f782454ea900acf0c7143164de9b5b46c1cd072c69b76143ac4c99bd43139b5e55f847841fa6a1c -851499b3a1eae6da530a47d3e8bc068e6e7144b744d5eca5394f96253df65094e5f3c34abfaf7c7d78c4d5a5d4863da4 -a8d68bf15b900cc47197739856557b43a5eb233b6c095f21a14a90ac8c36caaa1a54690c95840f0a4d2e2ffad0874a2d -81a6ff8fb1dc4d4042089d4cfc10cf826e39083aa5983e53f4866f8f4c10cf06cd8608c4cb1b785f8d309bdb9b2dda63 -82f658bd1a95fac0b65d337efc95d856aa65541d49aa993b094d70e527e7d478970eeb3daa2904a1309d755e1d677691 -b46ba4f3d8f287eb92390e5d930df4f1a40abe500c9aebf62e2eeeb2e5ecfe5296b09fa22d6c9cfdae28d431fd10a00a -b5b38508befa4623166f6213cfd160782fae5b7c3c7ec279b42a83d43a7adcfaa6c5b34cedbf98bba357fa663eec896c -89b8a0fb37a0c45eb1f234ae9c7be65c8a708f08d431728572169b33f8288b1e17b7d4b18de9fb76afc37ae609290623 -a7d1f5779c043900f3ddf29b6b7ae4301699c0ee9e70314fcd3bb2643f912fb1225a0164f45c47419ab762420bf8e5ad -89d2a69fc014068aa6d0b79784b8953f3519f563b5c9f774f4b148334d822aa645b662d5efe7dc6f9cccc2f67268c3fa -a698d3f0b1b6b72b72358d5fd5e49e928cfde69bfda10e163b9b43bb9604362b32af1909d28da5e0364abcf5e96cc226 -91c12dc25c48aee56484172de8c6aba0d9f5eae8db848a7b53d76001c292d115ec57d816c2cf10bb9e901b2707dcb71d -b0740219e084d56db4829daa30b2812115b2e95ae85ee96a140b7c4012860e8017e19b482e981547e50e25bd4ba76716 -8c84d4fa255e2de7cd23b0bbd110687edc47ed7fa87bd42658fbaf3831c6d68cde3ef403ed6c585f8654d0cd32074bad -a530d3272aa1740a73e15cb9b31c5e2e54c404db72274b0840c19b164642389acdab4514b9b2bf9688ce51392d8b6793 -a601f52bf7b3226fcab93c67dccd95c1d6673270671c4a099b867bd5578d5711fe9acc9b935b867ca780ba4a394279ef -8a238082dc8ae33314fe1257e7bec69e905c194ded6f894267bce97443166fb443628490755e1d453545f389b5beaa2f -88a9737f3e9ded874681fb6cc8abe0f6e1ce18a05ab599b2f855f73e6fe5bf804de5c5dddeb11057aeca6613bba72c8c -8a5cf70293eb99ad3c34992c47299646c8702d1035b75e4784cbec67b28cd4c88eb8c721f4cb8982d3c6a42d1b9f7fae -8a62228b84fa7463a6a8392a7af767b661382175633c5e00b36979d816a53b388f31afedfc47a5d8cbcb645e8d5928b7 -92836b5a41900a1c1ceec83cf4f15c6177dc20f95eed23a203810116ede2a072a8d6c96532ef32c93ee21acfb14448b9 -b4e538d7bf40c263dd1ede65c81883dd31f9237a0fc8d134a2b480a1a681dd89cd2edb19e63070ee69e96cd12069ce3f -913eceddd4c9939cf82c7e9ca5ac300cd79dc5a72b8458cd69e9f8929168eb19e5f21eac12a3b09eb8d3998e28e3801f -81f4a3e7195661b174aa2059796dd88d3206bedeb7d7cfbb7e61aee335a01ac50bb8edeb258a68949492d4ac6215d95f -913a393eba8eb88d1076effa8d2a30258d83635ccb346f1bfe099fb5fcc69d0457ce5a79363a618f9e8b43f53728433b -b11d721b08be428254665bd64a8864d78c5112e252feccca113631b2818fb729129fcff1e739178507ece41b807ffafd -92603fb7d50d11b59fe376720aa57412b866fcd5da90195a5a401e6222201b30c29f8797dcc1b41ee2cbc6349bd5ee1d -a466c5d41cd4a8d1f47a650ca67b529ad3873ba3fd3a36db27f7a5869b74b42381788bb1a1c100ed184118839b9879e5 -85c50607a86d4f76826220286784fa9b6ccbaadccb661fb3489fd35a3a8917d6999ac891190f2297afac3c37abba2967 -966320c2762b266cf7eac7aae39221599df4fd608036f6101cb8c68192fcbfd5f61c7f93172aa2be0934486fdf4816f6 -ab69525f1c77b6706592cdd5b98f840184b49efc6fc2687d6dad3b014f6a12c4d5cbcb5120d8869246da010823534d8b -aa2c9df15c06b58d7b9bdf617df8bcda83ccaaf6ddeb8074db931f7f03dc06a7914e322777e297226ee51dc8268e80af -97035b62f8db4df6e787cc2c940f2298c7d26c2127c7a76e4660d132a14f43c8bac8dd4e261605611b2e9c08929f2bac -8ace33e696953806f594427f137e84ea6b22ca9b48c3bdf3830b3e951e5a463d4a7067c68d2033eff452295a741fa1cb -b621fe49b12580bc8ec68fa39d5133875da23524a5ebc793c35040fa3436350d0f3e4bb4e53eaa23d312a7847e2eb2d6 -ab7d6ccc0de9c7ddea145e83fb423a535cf26d470af3326d1d6a9a579592b32ededb078bae4613028557877a9fe71642 -97528eef76389dd77d33ee7daebbb290814911beb725ef1326c3160b9003c3043be09bf3f84e4818bc2a7960ce1acef5 -a408eaf5c675b50dc1c655f83b9595dabed68e74e6d2eca5a4948252667413cfffb46358400df5d35f92657811ae56e2 -b36537726b26b474e184dce0ad868a66f0944b4105ff6d35a2cae0f3a520fd14a66630388aeba178d400b5fe104e521b -b2b88518d10bdcb111c82a261076367e34718f1d0a1a06b421891b4eca1e3c1f904b66e65dc914ff1ea5991f6a638a02 -aa3172531879a5c8f594ce96277b2c8c8d4a2d0f4bbe567ae40d5b36fa6108e00f0b1dc94b81f36c9eb6d1e9ee1896ca -a53975587f10667a9474ae2756faefe43e7f81bf9e051049de175a8ec085530fdee3d5e3db15d4be874ecacf49f31691 -a1abdc58bff4fad0f6562338daeacdac8e37f9f3212aa252b17389bd9c54db58706129a63bd0695d299d043b5ef0e2d3 -b8588fa1090597fe0f6275e5779da11a4d128c52fb8954e475c4940f1a3e10fc23ce1f61e9aabe8a75e82824f718a94c -8a1981c536747d4cc06315c794f1536db7ab3c9dfa024a0df854b948d93bee72083b6c9c4c4a7ce999c98b904813a659 -95b2b1ed525d629eed454bd6bd059b01869423c3463a56689a7c39cffbd3453c962426a1126ed631b25ae8cd7538302c -8032c60f083477693f533c2d8ae391d62ea754b8eb41ce9cd59bc469b980dd959a8ac840ccac54b404a9d08a6f9e4b98 -a72ccc14eeed758d3d43c51d68341fd7e98880c3687e122238d77dac8d987c8edb3067bb63baf13a0e57fe02334545c7 -aac3eb536a5061a8ec788ce131582dea691957ce8b9c6af5ab7224bdf0fd15c77bc6bc63ad037bd83e0ae52fda738361 -97dfa193800e57e6b19d1b7fbab40da6dd1463f043eeec34b316ba6bee21b6bb633ec0c4fe107c9dab6e06e07e0acdce -966ee3cf2f54777968fbc34f08c8de121ae7c1d6b2cdf1f1f9c675828d22ccb909bfdffa2e3f2ce51b0cc85bb29f8504 -a9df6dfd12f8c43c28b929280355cb23ab0ddd2cc2e4fe76603a2e5dc2ef5d1aca2edf89b304a27345cbb1f24a86cad6 -abbceef80c744e5a1194313f7b84b5dee1c9861cd4bd3d0d12c433e5f2e8c6ef6f10b860abf3b788aa04896f708426bf -b1dffdd81711e9782c992c4b14583ad9d6c39ef88974682a72e717e21923da6892490d7efd121423fdc638467e62e064 -817f30dd799c422da33e13ac2bada8cce3930233ddad495f714a1c789b7aa8f41ff6e688bbffc5f2e8dfc72e5243b645 -96760a79e4414ff1d19fee65b6e65b2dd6665323981ce8b4ee93d0a9c410b018ac086c08fcbc7a71720e1e3a676f2b3f -95445cabb75909262975a5b06381af2bff5c4c6cf51cc84adbc0b7f2a985117f35c014e33672cd5216a9737d3f37e067 -a279c905fd9d49482d213f5eb98256d020c2b90bebac45004d6f152ee4ddcfc72a7e6b188ce3b6c93ebb9ba9b8be587f -8591e8379a78af8860e6a0e002be5b25aa4b93c5e556f5ae2e40400f828dfa19d93a4910823e230a51e2c1ea5464d437 -a6fde17d41fd9f03605ab6ddfc992e36535a23b2c39608d30cd6d72588f1ec6afb9db193e88eb609e104e73ddde779a7 -93e2cb6352a5eec063151e5c9a822f6fd475a072dfde2464af4afaf6a730a6af1fd74c424c09727328a7f23505b91407 -a7b1e4f703386fdd16f5fc9b59ef1dd682bfe5a23bd42b3c4b1385bff894e758ab09674dd6d0ded5b32a0a0526aa6d98 -aa7f01c450e619c4bb42d6cb1a90a94dfe132a641728a642997b71e2c3b02d09a7695b544712b2e14416e7de0252fb11 -ae840b870a938668d0d4404b76f5d4d252d8ae1e3619661df0890ccbab900e3d8dbd5dc9f96013413e3f1e30dc541db3 -ab7552930ab07b0f5d50edea3a2e5ea3ac1a05cc985246ca066fc3350bc58949dfb99d4f6a6408d1bba64d3de47a3c2b -8053634d4c730b5e90d68c2830a73e93f1c9e522ae0e00a04e2ba15a1b7b4fffb8b25516ceea61719f886c7763d46219 -880c39ca4cafa622bc767d3127d62143434d0a1d7de8dce1a2f94cdcaa023a7096641a46e6b97e1b1ce9c233c873a519 -ab9d46e46cb2f382ee7d21b6da01578b786b7998e0fc2b5d5a4e1a0d93aaab997b5c481c2d9a741865d6460ceef57a5b -857a5957adc3a888cf93f144aa809c70a211932742a258978af5e657f4f57fcb6d9e39dbe8d3128fac6c592dd5bc4ddb -8c98656861fb8c8a03d491db45077f1d136a759177842ecf6c1ca36923088237e928558433d5b631590f395db56f96c1 -abddacadd7d536e91d36609fd0047f5db113be0f4d84abc7631ffc5c00df919c085c049c013a05131150b0043d51f892 -a8b14af12cfdd0e11c8487334efbfdd22c8b4fe6bf350333d42ac8c704efe54f50a4bb51d9d802e5185ce72e4b21aa58 -a8badc2bb3cad0143db1bb3cc81751f9974ff3f0e2ee35921d04985409def84ac2803a657571699eba34767b773666e5 -a6739a05d270efdab18462e8536f43dad577158e1c1655fa130da97e469adce9bb7cda6f9ac26f4a9ba3f9b22329b066 -842ed6efb4395603e7fef0bf92326c0c63992da4ce7912f850c4960f7a19e0b2ecc720d9510f15ba6f73a2c5ada8ea71 -8502ede859944047898d533e1923ef90e1b5c17d985c9fb4c6aa39d50636de4c5a4df278f2f62cfd3ad08bba4c5ca6cb -8c738573226dd5617b3ca1dec8780000a77f3fa8de241cac99b0d9b1b6c90cbb8aa2009668005f2c5c7abb09c0ab3f99 -b101335c403d769313bd05c755a9196769465f7068fd6f9e00937f3cc843d48f013f5931f999bb5c0082d4315134f5d5 -925ace190259b321981fcf8bcf52c6852b206099f25c0f278439ef6edc4320d6f926cd6fccf1b4cd224bc52e5c681612 -95f5855ad1bf14224e51f7d5e0d229683c0d38fa324b1abe9d595685d3497955e30289618c4775f6083bbf923ff3a37d -a3d3c7100962c8b60c40b830af834ddc48858e7eba5ebe2874ebf74e505c25cf52e661b49d7619f2f2a039e1df02f5c8 -af7e66c1d5dca63e6be117b210c616efd533e77199d67d8f694e4278841963e0a46e4e44f0416e69bce6a7156e1872ca -ab796760166d1e1fceb20f9bf19b1b7cfcd327650cc7cc35c161ddbb3cd4846e9a971b541f303cf62fdc0124688fbd41 -b920211c5b440b3567942dedf62a65ffbcad1e3516f58d14d8f8dbe86f45c4b9745fbce43f5219b7052b27a3a04df12b -ab6d5d25b9fc46b0824df1628993e44535febd7c62185b6795550388185035ae12bab60fa34848f465fb4f4a8add3544 -a6539b67dfd6f3976cb6b304f4d152532b3f08c02bb97730c03c746da0f7b38ba65536faa43953d46e5e7687a86c356e -95bb225586b1c82d894ababea7e5dfa8468bc0e10a2ef34e5f736fd1611114cddaf1a5c58bc9d664b667adef68b5c25c -a16eefa4e6161a8e7bac63cffb2dd5cefcae57144e63b3fded581abf7ce32016a654aaa582fc25bfa51c83f352e09372 -8b742428f6af81261a47a0df061e480ef9176694d361ecb57967bea67e11cd44df686e38e35b7d4a6ee02ebd520aa1c0 -a2a4f2307f646384a0238a711c2dcf7000b4747b8df1d46c5da962fdb106c5339790b48682e8ec2532b8d319ccafae5f -81910c1d72f6731d27d3a4059ccb0316faf51fa58e0fb3d1287b798ea8f9b00bbbde31fac03f93c7e9a1cdbc9502d5df -b846b933c2acd71e9f9845f1013cea14d35cd4b8f7a371b9be9bec9d4b3c37a2d0da315ba766c3a126f8e2893f10af4b -8ffad59284b41b75064c277ab01c5b4b3a4f3c4b355bf9128160b1a55ed6b0d91366f7804006b4e6991525d3435d5235 -82ff36a72533fd5d6745d0c3a346fce4f62b6aca0b8eccd11399b482f91cdf6a5a4135c627043008cb137ef4ccd935d0 -a11c27f6eefe54cf32fd86333d9ccb59477a655bb0c35dcd028eea58d4cc40ef9a26cf3432fad4e9d058a27b419b8f04 -96642ce0eea3c2c0fd155a75bec3b5cd573d41e8081632c56528464cd69a1141be3180c457213128bcd37f5fae47f7f2 -8349a9e390e05150bbab2351b77a3674f1af000b6eb6752927ef838b6f0a1200e6fd7201dad8565e3caf3802f204246c -b8ae7fea6275ea61935d3047d8156e8fbc4a95c9fefd1c36439b2111b9ebeb7ccc306e0f8c875fa772f7b433cff848aa -b366f056e23905bae10ef7ce1728b317b83f504d128f5bd34701ecb0d25ec08491969625e23d5a2fcf0048af610664df -a3d88d506ba46b73bf07729aafe9698e788fd688647a6b4145761275257d262cc450c7889b8a40d698455baca55e3da4 -891ebaac7a7a408aee4ba61605f44f9ca5a6d5e046eebfd8f5108b6dc4479482806dd01686045b4c7760051f22bce468 -a6ddb74e3e3725e6f2d9025532ee3f357ee35289e1cb38dcd5b2ea8ebc0bb697416fb3aa73e1eba632d593d40fdb030c -a7dc097f440ebd31ec1a005648468c702bb77073ac8cfa32b050e90a9e1cf388f138abdd18f07951c752f7e19f706af1 -a200f25299f9a0542c196adc2e00289f453411066b88b125d3f0e6b17e98efe9da8096312a2f1841e01837da90a65440 -97cd3a9d4185d77d4c7bd4ee80928def7b660d8b949b0face798c62a7cadce1000997af29504d28ccf9070fc3016dc56 -b9ebaba1a15eecae6b1998ae6d08233d05610dc0933b16922076b2dc4418cbeb4e5cbe099bbded3139d8a47f2b2eae10 -86f5fe8fb36b419fe6fece1c5c4b9d64468b4aa0154bb5dca466a243b6fb1227c3b8bdaf7ce5c2d4fd05c061979f87df -8050e011011e7918ebc25825d9863c91046fc3756703bdedf936dec2815cbd10c2403ce6f4a0b4f576cdfa1347efdb85 -ac22132a482d2950be9442167be214ed9d24519073bf5ef1c8e3e6f4a77065da198a851950330fe4d62b2a1272835015 -819e2e8e3ac43b6ae4885899346f3b558bd7658ef7d380070588154694957596695a925a001a9fec7cf3655326c50c2c -b00f40c084d2eafa36811e0d822ffef874a0d4bebd4817690408a737624be05c920a08307cfa0c1195505c5e7a5fd878 -8355768c09515a593c8fc8289baa3b6cf7fc10d302abc93f72090ad99a70a1ef1107eccf839be722132259500a565d68 -8bf0615d2cd11b03546ab7a0c90c0c938776aca8a8b989a709c367f0f5eea7b0a7cdd78f96050cdd5d0a123d01b99c53 -827c2cce458464fdc716a2198fc67b3cf2ed7802a1f53f7a2793b2314789998b13ea61343c723da8863cb63def6a285c -b609cfe6acfccd632759700bbb0a06fc7903a6c0c5875c2c3bd85c65bfae7b29b03e77092f29d565a6a89b85012396fc -b73ddbc330e872363bed36578b245b666d42923393a1341816769ce0af24b700c19ea0f579e4f9aff1c3ff369e63da8b -976d658085e5978807e13b150c7aa539b44ab8855a386bb58a52d9ec9b5e21ddaf89a18b043394d6cf47bd589d04b240 -a213897312aa28cbb2c572e643d3aed003c84bc2ca571dc5fbea8a0b642313be94db0047e293078d975fbc6800751a87 -b54f2914f6a7508b6686280d3cc955730458ff035978be29645fba161ed54ef3d4086f956e68d2a48c49afe904edff5a -af99e470055062390904673e18d04427c16afeb7b9f13ad83bc2599e9a92314bd91d6f1f81b55419a4d668bd889ec8c5 -946ff0cff4030b73a1342a9173fe697ab20cc5e43ea6158573f2def601e12a174da431f8170bd31ceed4be48c90b4f6b -abc51f8bb5f74cee819ee383cbab739026c453bb55336fdf423af2c2ac6712ba90006d62dd72d8cc1b2ff6cac900c8b6 -b43623a56c5fd1bf28bc356fb4a875d72dd4cbb00c9c863646a3376937088f9932a4a0aa26afe2ad69840b06242ec76c -b0f371952f99eabf7ed368a142ee07d06bf2b7ec1ff852fd948b8c53eaa52300753fb9ff6765201e35873b5167583f3a -b3906488172c09e148c571ef0712f88bc9f1ecae0db95380f61901660fc1aa090d0740378d5b9b76883507bed100093c -945373b5e6ffce11d39a722df7b24eb929b14a967d211be3b969f48fe1ad3dd4280317d1ca772a69b033f3bf26c02c4f -b2ad3490389fe5bfdd5ac7eb5bd61facff8d57a8f9969f4938ea56f4a85eaa2c1179a2e5b4f87d9e6409925c75b61828 -a4d61547e405319cbc20cad16a2bfd9e6d093a064522c332dd22134ab05e893bc84786b21b4c71a6265bbd06da2ef4b1 -86749c26715d22b185e1b25dd34818e96aad319d7add22a98486ef9f9808b5e4b938c6320d391dc4e0fb5d57bd41778c -acc554d5b866693a453a9ec46d422c8b410458fe8397384b927a62bf5f2b1fb9706c8c21af9845050fea8a91786e3577 -8eb7e763d297cd93a7a54dbe4654c39c0ebfd73fcc34d3f1338de0c347676f445d32f270664fcb7b33347bd377c9f867 -a1b469e3f9dabd36b13149c83aa5b7b5987eb0ecc1ce6b68c72acb39ed503a11ab4451e658576a92df4aa51d1bc709f6 -b1ef105cd0259486be8f265a73ea089d5b7fab7bd7547932134539963467fb917b2206aa72446e2fed5a8185b04d345d -b3e211c1a14925f6de451271728a3c1e555ebebecd4bae29bf666927868039d4ec99d9f9aa98d835da7845a5c863dfaf -a416632a50500f29b6bb471bf00b37558975ac91e5c5b5004b67e130be1acc954a8ebaee7efcaf6883187ee9173d1ccb -8c655a85f66b5f28ab8760c94b6cf01cdc36fedd19a09c261e432fa7eda7928c3c88355384e689f1d2715d419fd8d898 -b1fa9f82c9866d4f296755bef5b7c39fadd09374f38ef9954aa57b1431a1ea4cc17a9750da844fa1f5848f0ab7ca295c -b45cdf1a9eaaf85c0b07bfe239da618ee649ce90b417d90b08eb518b1fd88c0d25cd29fa7a0d8058d6616627a3dda306 -a2be1552d3c4142755e0371a9543032ee82ad669d7edd24c4e2941bde3b78c5c6df427228fc45812a55943b3663cdbda -a28feb053e86dd9e2f9ccbb7c38467e2425fd580ba0f63190036fb47d01eb198ba8590b5cf68d1c0f47638e9dbdaec74 -ae06b849e080efcdba86fa03a0c9dacb38a15ba911aaec624d15787c3e11ada6909b1e33a2e3de928a23818d833eade4 -b4888445d86bcf4d1f6a9c2d253f277596795084c3d45a4591b307b7ae4ba177d6ce871c2cacdcf9457f9c132f244722 -87a568aa2f5471214f63932b0d48e589898e82a1f4c1055a9e73120763430537c233e9a3cb6cc178df53768e4c58c993 -81e0ec97cdf91ae66d065234492a1119198c396e2db204b7edf192c88eb4238e0a45bf7e245f3714bd864244cba0ebed -a954a3785588d4bb3cfd7cb27df45c82e6958051f916594d76cdb35bb07e4f88e2831a5cda35fe1f3c99f32a275f0668 -a9c9f4d54339d414342e87b03679baf29c219d28b6548f01891cf94d0313a64d3384658d82373d6e838d886235ac446d -8ef46cb24432b419b4cc803e60b3ef5872db8ea614dc37643e4592fbb2891cdff61f6b2a10653d9e99e6c7359ca4c590 -b23eeb458c05ffa5d58be21cd0699974694dc61a9a928fb1eb509954a3dfe7d8a71620a2d4046a448de0fb213be7e97d -ad631be8e17285f6310fb72ba913c564fc66d14460c4e8c4b0c68c572a5c2a45b088ef60eaa9d317403bacf534d57a23 -b7130f5607f236374f5e023fd43cc6dee38286ca47d504c9e75c6504957ac2bb9134fd59d8bb1010d545c56ad9c71c4b -b83cb511757d80781e26b5e9b3e0597c4cf9a976a3fb60c84efeab2b6793e46282612da45b1bb8b45af4b7f39877feb2 -a0c5f8b0027ee11cd5f86515698f689ad514cfa890ac4ead5502b5ede9d7d7ad12285f5806c9c85ab58f89bd9f188938 -aa8e8f9335c6e34bca3472b5f412ce93ab1ed5f9e51c3affdf986a5badd2ba3ca1ee69eae53ba8144927f082371b4cf3 -b2a4f775a10cd9caa776123771f08e928ecdb22dcb91efc440c69e37c6b467acfa6112c2776d4a530bfd6df3b04fd50d -a0c553d5d2a9b0525f71a5a0a539d579d937275df9220a0c3c322d6c0ac7fbd2fc55335a1a283e687856e2b30398e4b6 -8ab800ab4c810e8f6a9d42d2dae9be89841bc7328bab06b88bbe1256f720ca99c056fbe4e1378d7cf805586ae18dcc55 -b9a8766f4f4bf796e2517a8a7a05bafaa6d3ec601a85c466d33b8a7e0498fa1dd4e2a9e42161fe2362c81d4c8ee1fbf3 -8cb7d054162e9f41245b0914e7dcf6108ec11456b39b473ecf6c40e56b172fe5be4e7b0753a3685667436796a977b977 -9131d0395897f5591ad56b62ef83a3ed9e7b3951080b33ea606a15742f78a283f924373e813b877f32762dd69884658e -8d784d7f0884cce988305d314896dc6dac2d2934cf5d650904e1397f9b9dca397eb7f3accad60ab5e34cb2e494bb640b -8819629608ca1535bfc156c1e17f8fce5821d81e6661bca75a1754a5919d0404e31e65bd509387383a4111535e949f5a -820a6f46e251a1e6d92784aee18fb0d265d7e2f0a5b7e0b15180273eabdefb34f1d575e1d8e93dfc2be1114d10abf31c -8d10d0e0557beb8db344c2d8bcada724e720823fc37ee7c51b322c3269559ae932bb2ea07e50d7ada88ede788839dc8f -911a333e2f7578a0ff6533284176cf235036047a11534acb649a0043a326723662bccddaf1970b7c37b5146977277b88 -a4be2104cc5d6fce4a46de5de8d210559a6b743b6347b8d9990315bb56cbf80695ff936afadfdcc415d88b23ce6863ce -87ec5877ea8f1123371c49263dd9fedfbde41846a23e12073ef80f7afddf5a0ddab298cc02e861a90188ef1282139ecf -a3f1dae70745b8284b1353aa6902ebe3cf5580e24e02490d42b2f509ffec7e8e777fdce4f1a92d83bbb23cbaeaddac57 -8ed5a0733b42482d88da7c24e85a841ece65f6066dec060bb267a8d1f1ec165ad5f7964c2908d3fbdc2999c580eb8990 -b124a1db23f4875e0caff1c7f4b9a411564b93a9ec3ad8143bc7a70b8305d380b934c194de8201f7e3699e905a1f0115 -8af58886d4ac5578a29c2e309a68f19a62edef5285d0757c42f0ec2550c633c0e991c4cd7a60df4523cdde40c3909345 -a63fbdbde883f54667c6cacb356db1fb976bad147b790064ff25ae72be53bb6f4d74b22ca803996e0d95d216caa3fa81 -b99fc9012ad938b36246a4471d29f0a2b37b2a3be6fbfae7ec9fdccbfd14d48fdbede0d88ef3b6cc273f2488f4cab55f -acb6cd4e1672eabf530d38f50ae651db8bc4025c2557c59ac4f1a278b4741f1e2cda978e5d1337f9e5aae77c95ccb872 -8f8f6964534e4a9294c61c76206674d836d4d56970e9c14ad6835adc6b0d256402742d8a4879764569d9082ea6a750cb -969607ac6ca9bbef4fbc2fac22b12714a31f5d6103dfb998c3b6f2776283ebc7346e81a22da168af40752f28ff60d97b -b633f60cf6eb8ed588c545c04972ff156cee767edf31720c9715be3cda8c8de0290b623b22cb8fadb1690bf3665a7be6 -8235bc2e818e4d259bf2c9fcc9646ccf83b7e238044e26be417d1d0dd5283d7b38c86e8c88a5447645be191516e2993c -b503052246ea840a4083bb4a8978029af3e242e831518bcca015f2c2df504e98a48c9002b6b9fbb97e861a0a3c5b4b5c -a145ac57d7c028c3cbd2a2bfea25caa35a9b5d69cb491b13eaadc2b0d927a590decb7c4995541f8f29089a2cbde6429a -80b4c0938058fa5d03c948777f13c70f46fc025d4d6c2f2051915b476eb0c0bef902374d784df57ac368c01e1fd51c00 -92eb253e3b1770b36c4b2869a944caeed7b5c8a5b8356b25dcd4102df79fab8dd2c9d01e3253070f1206d149c43f64e2 -b7979ad6187f7921e725787b0a99050f4c98762c63fa64a467f7f110932f6d07556453a95e3a2c0162bf1c9c41424c90 -8808ae4c7cb38202c8c8bca0321e827580155197a700fa54b6a15b0f14b001327d4c9a0923168bb5afdd1b45d6a78367 -b16a4ceee9de5f49a99430e18aefc192f3c1ffdc4b41392069f690893bccdca760e6dadf4127539a763e4f60aef37dde -8ac113da7ca59ca97d6bf7d6e03f1e9570867bed27230515475f965ce9ce0b424c85810e18a584ae5a3d5c2c80c6d4a0 -847ae1b0ef5cb11be37320f3ab5e30f59d7910ba3d7cbf8265c74df25f4b8f56f1ac96cf49fd166c3b6985d1e8091e6f -aaa9b04f50ed6778e2481842cda30c7dbc7d462b40c7602a438ca9f2c1599e83fe6423f30d7789fd240d2e3166836f5d -8c18492569faa8cfa1c2a05a0edeea3f63d003e38d9ce23c4a5b31cde993a4ec88c9db83011ae15b578e0d0f6b72ddb8 -838b400217af9241755032c21a3ac4610f77f3ad76abc43f0c59a59f9bd52f2251e46fcf1552b6ee0220f4f2902e54e5 -8675f8de084c6c05644deeed1ff45090096c72c0db6bb2ceaf1c0d070bd10ff1e83b2dcd89b6f99bf132d3e131ef6d0f -89611bc63c83d56131bc2a8653278b234b4635aa7a05033d71a8377a5d188ffed7506a50a5c37a33d199a42b9e55fea4 -90c290c17f1687a87023fadf74b1e10ad0c0414cf08629b2a313347f0f6913bbe511e5d18d1c3264b47f65dee7887d4a -a590bcb6391506035466dea82617f11dd9417c9f379d32b4c3bbf723840e1a3124d2327deb28849aacac278470d7ae20 -97c55f459ebdf94ade7bc3bb18b329bbe2bccea345f0b4dc38cfff2839749b8f9365e8a1cf31722649c165e265344c35 -8159d02fd03c1d0b3c928658b3df1a27a57699ed8a573e0c3a179e97f50b6c1a6467b7055e42f9f9c6c858459eed517f -84d4f009c052f3bf76b2b972b3d8f7a4b2d78605a566478670c33016aab06828a1737a36d3c9173583e7bed0aee84fcc -b99d7558944ac2d61f5a800c24ee47fca719e69f7284956be94596623cf434a214c042aa46d54019de3556540ea53236 -8d1efbad46f69b80efc5776d8afe95dc0a8182d57318b9f2d6fb5b7d5c48e7181e6bd61a8446a553c58f7899ea7a7c78 -84a9cf6a9d64cee7e7d8f0b678d3606c9080ab3ecf62fe0d6f994a681de68b30534ded61db1445a257b2c5427e97b36c -b6a5d2c55a23841a4263b10cdf784be6fdfe1b25350a4af510ca294949716711363ca19f9c44ab1c347aa3fcd60f0573 -b1b5b6dbe6945db539fe7e2de07d222c88d7b91753118593ad9890c55c4c3d83b4194f886ea7f66ccbb348f5a23a2a22 -a8a58169edd3e58f87fe8529f5cf7da7679807467ec707ab96faedf75085185a78f2ef912d9180a5e820adfad32ae4ae -874c1f416f866756ae3e93360342848afdea0048a575f977fb1f8a57325e50da122d3e9f423e308f0acb1b28fd47a6eb -95cbe8b47ec42a5c72ef7b1f91e3de0b1f648ae8069416c48d5529c9cffb104ba4dcbe87cc06e4e798a1b23bf1595f9a -a1b6e9c5d63ab1262559727872d1140b74a4f01c12366ed2d401c64007faf7917ec591b631c6bb4dd44b39aa43c7f965 -89e6f4a05679c95d45b54e760056378a5eeacc72624eec8b5f19aecf8ef0d8acfb2d807d3b88c6b1206827203f219905 -b7f7b30cdea6377d5f16d200b987e3b4a6f28387faa701dc579cf7b3c6887d74ca43609c5bc36414a6dfd0317ec75448 -83474b58135f3e2c5e8355e31ae44a77721db71cb2919c3f3403f44903622d4116e812ea9ee9ca073938dee780f4aa22 -a3e4cbbec770630c5e2f3b67059a55b1217435bb70ba5b5010244e241ad6a3e6b8d9261d8a0765c4b42bf795fa4e96d4 -87d3ebf0fc03ad67299f3b9cf9c9ff0890b1d0d2d1a0ca2a62147444922d207663329e49898d79bd8e09ee48a1560fa5 -a1d33282cb17c7a4c5cfeab4dee8875d324aca8d0513567c4e5eae180d1e8ac98b2ef16b31afa7c3f2ec25cf3e8bbd11 -b10b6cfe3ba563b41ae0d66813105948416ce0848ba3b34b8e96547e8842086b632a52904e56eb61d93e0cbdd402d305 -84c4feb35c8d3583ca17245e6f7e73cb488aed515c2ef671b09a04d8eebe6b7579e5b1fc8634fcd4c3bf8100d2cb98de -918d8fa2f52a9b3957ba412c24cc579dbd1f0b0834b909a6ac0da5dc602ceec17046f61b3d4a2658f724757ca8041fb9 -87296e4775fb887bb00dd3265f202f31a8fdeae5c6ad8ec63508476cc57d330827d0d241c68091bb724a2ba921694a7a -a8908019d96c506b314c84b22c475157daa36016a9b94feecc4571e869918e4e5a9e39fb7c9ae0f73f9f868bdc50e2af -abedfabf75a93e7521eb339ce2e22e0e887f94ea28d3adfa42d1e0523686c6cbee4c96b2bbab3b8393feda1099b24d4b -a464d6bb17386cb431520cdbb3818beb3951b0255d72f58c300fd780aea1fe4dbce5532f5321e80e16db2f9b9bfe8a1b -8cb8fe0df930e1e19446ff0183c7034e35e33442da346df8a802160120a5f4d8abac236763114a650dcb1a1d38bafb37 -975c47ea6412bfa97db9cf12c2b4c07ebbda436716aaa7253b2343138b36de6c897386833849f539bad7659d9319abce -8cf94457a5a708cc91bca9615e599b0c0afa92a7f2d9c83704e05a3dba56a90c4eedebb6d2d25b3080786e16c27194c6 -950d02a5e41c8f704184c7c59715fdf3b48d86b53b04dff7c21738c7c38c9f4f75349ac1e70ca18a0744b01fb8b13504 -9458faad893db4458b330ee283d6a90f68346332c99cbe8e121c890bfca908f0c91168072aa221c3c078d7fd5e4b44d9 -b0262948c113fa2a122dc6208250b62ff35b12d3aa1e5735e95198424cf16a4829e9211c9edad83989c537572c5b41ad -abed7125de7dc52b0b42cd34fb350d4c6c45016319ab776b52289bc8c2b341a15d48165c0eb09511a1a5a5ed7ff39e4e -b4c352b4a127afb5b0833d210dc2c216bea666e7c5a940a3372988c0b02dfd236e4ac7c124664bcbf353132d6f061f3f -a334c5919909dadca50f3124de06400df660082b527f1f32b386b9216d021d38685f1839bafbaa7950eea6c1cb14bf53 -a52f4534e9de29f91039af3fce055f2f6726fd9b10595a43ae41f7b466cc4ea6314487081e867ff4b5e35cd622fb428a -a68c6ba9673896bf49ed145935773fa50d95ec0103f97a6f1ed698d93b4dd78111325f797e47fe153fb3852f4590ee89 -a5c456d516a557aaca80441705cda63d081181199097e83b22e9cf7b9947a8bb78cc476642f04a5ca3b13032319591eb -8a359a3dacc7b45da2b826dc27700178553f6a52e9705451f24c6d6026a0c597328acaa10b3b5a883b6353eee4eca594 -807217b435d73c1374bca84d2d3e069db756176220a01607b81438a70f69232b82099c676fff361dd909271be8d5d555 -965d0f46eb0804f19dd700d8721349287335c70e992efdfe89058ec424b87acccb3fbb18d84b727ff5ccb6f6783e9065 -aeb5f2a0bff1e6115bc2fa73093019f8c679efec91d03398e24651be187265f7ca80369a1dfa61e8701385dc0ce9a0a8 -85732f872228dd5d691f1507ba00cc94e054baa59a764565401e9e9b3287d2d0cd0f2af290b28b5e3c80da9cf23ded63 -8e9a315c5b40e7cdb866b8a7e6ec01eeb27a52a76a88d5956ac3e66fd9ade3ec954acce816227b57fea6ae9244f1303c -80436457879607efd008f959cfd7507fbe22e417c701f59b5a36e878a04e51e87eb38c48c0992333656b24a4e671bfb3 -a012f6d166cd1d98098544bcddfbdfa956ce60011694b640b012da3a0a22ac8a054a9e205aa9fae4df764ad60c65a6f2 -b8225afd6e4d45520678e243d97bf48f87c2b8d2cbc24b43f94bf6e7f60b7768d4c3b30d28a490e7c8a1c3a104ac8317 -8437fc2ab6d90716419f544a1d16c607173fae5bdc242d8224d7714c115cc54f2246d1062ecd77d5a9cd3ebed3a8adc9 -b113c6c63125930882c18f548c1baa69a26f9f3dcfbedf5be41aecd61adb896ff9622ce038f0ed27a5ac602b6020740e -b893aee6291a3962fe17ea41322de7edbea6ebd51d2c564fe23ba8a4cf4b6270b7ac72c87f2cbca209be1ba607ecab75 -92e6a7494114cb4dcf2b86ba61f57f6db7e4d52895ba6c896433139eb2ec9c9604f3e9100c690e1949e32f5b7e29de93 -881a323e772a639553cbb401e2b6a255094412addcece2c99ec9e1346aea2f4e9eb247552435eab74799ee4c7a927b6b -8d5d3ec378922311374fcb998fe5a42176448b629a6475abe494fa56abd5faa5835af37624c138beeba649f7803a4855 -b1a082ba449e93cc15fb4dc5114351437599fbd4d28eb6b4746d1bd242172518f94b2ca8b1f76c08d9f6ef260d9cfbb2 -8fd2b7728a3c61cd8e0c607cf40e935dc45d52d040ef1259f62e3eeb30bd3a6cd030fcf407fa0b21423b23a795a02b90 -9214aee5787f4666c3e2aff70949dd679d4203a2c3e7b6f88c548b80a3e52d7763f2bc2b7df714eef053f60eda4db331 -b15df25b62c6f4ac9edc414ecacfe8eec055bb07a1220e327bf35c5e452da7620df03416a449197bfc8d948445c5f734 -b41ff69731e7f4308fa18ad286d3ecd7be21afef3d32f5133a0bae877a347f8773c6e9d9b3b850d054236a6f186e6913 -8d9d13d1b7d9df41cf5d30dd62b9d1d2c4933d62b6cf8d1830bd1ae4dd5fa3de36bfa1fc4d57681ae13996f85ad2551e -8011a7fd7534b248db40050edd9752c960ffd89b0300a91520759ad51da1698454affb4aa8907946605a02ca09a7f340 -9159054fbc10164fa19f68736c2a683d374681e6e9d5e56f7496aeebb0969b8eb1a91e377b3a2928879147a7fb60b3e2 -afd4980aa4661fe05bf9040f6551d980af562da69ec5072104d8ea34a8ebd28baa0b70e0fe3c11f631005693fb99213e -a92879cac7940c6d363ab3d0ba7f7f24bad0b16142c78969a737c27ebb09a62071540bec1822ae6224d943d02804da50 -89338d27ba29343279dd83827ae17a53e7d634bc77bbd848f3b6a352fe92f6021dc1c81ea6693b3cbcb1f24188edc757 -a2490a856c273b6eb5242672f817e60a157a1dfdf25b1d32e0f4836a9c2371fae72c93b94d78267b3cb142b4f4d7148b -8efcf5d06107554f896084e32e8dc95c49fc5da3f8c4be4ef6f2ed89914233eaacfea886040bfff14759ce28a1eeaf3b -a3516280b169a6832e997a4a45daf46aeaec1d8953387f493cacc2835a5791d4dcb24a0c0ad5de79988d76f843d79994 -95eb7531a46bdc51acacf7fd9e7210bf6d5ca59b0efe58f79422394447adcca6f4ea991600e8558da8e19e029701c5d7 -b1fcb4177f16187c76b421c29f715f1551ff365bdce9fe17b74425f76dd90fb4ebe828ffff3d20f75ac620abeb9381a8 -886246027be4062258b232926cc82b6a51591138561ddd0173ec6e4b7ff750e15d9ba175f569c266148c653ac905d498 -952c089dd09dbe531f2fd4137c971622fc1d85a78ff07de634f63853f62110dbae3646564addef8f2a070f5a16396ef4 -812ed85f4559fb28732d17c8fd7c6b09a70da454a2318a0276949df0a5dd2714b14096656b7b5b6398f54c74eb9ca49a -9340db62e43e43144e1afb1da748e81a1b00f7b0600e8eed117e92ffcf801b9d89b494ffb003b4ebd5bb4e0eb96c9374 -9287c0745b4bbe24b56784ac28bec43ed2abb6bb15bf11ba2b18b01801da7d162aef88e967d2f10fb9f52f6645d7702e -9615bc232ba6053fe86c6328eead899bd62c4f975273f72595407fe36ea43e30eeac7524bc17dbe78b4692d42ae81c04 -a387899b521b1a89e860756bd0986b302f3c06271ece653425d6c697e0b330a3ed7789efe0e5a1b32e60257a12fa0147 -b4c99909fbb92b1f39e9b2fabe05abf58af834b6c15ab0f62304ccfc5047f187a3ce35388ef293d2857b777f9938bd55 -97dcb90d2dd9291366b557936931550d665cd05bb1b19a7a53a31c2a39d264789477a47ae14f6bdeb171e78941a9d9e2 -81417b4a3e61ab9b48e0ff1afa8b523bf63ef95a6d6980092408b61f4293fb202395b10a5d12dcc54961370c134d5b0d -9135da893ef0a9d45a719207659cad4a0590218303d0e02016bcc5d14f54de5fb8de642efc7826b3b3212f714114600e -a00d0f8e2ea06b13f5a75a6dbd1f2ba7ce3f3bb3e62cd3b53f8b6ab39431fd2ce156a1aa4a1988613d4a2b6d91550147 -a3f8f17dfdda07166a7e5503366dbef45ea6b6eaa1dbe02b8051dff58453f1ac24762c82f6db6de4370869f9b25d6d51 -847c2b79076f9284d9a866a72f74f62fd73cccbe2df18c0fe34a35416d4825d364e24f95f728bc0e6a5215b08b6f0d2a -9816284cd6b8b35e1f5409d3a5899af5f4524a4826470fd164fcfe863994ee3aac77cbc16831f0866b9f0ae561903d61 -8ab1f9feaa8ba2e1691acbfbd5460a4bab531344ce4accbabdbe5ba8cedb5d5fc0967def4365d755ecb62d83b7ffa4bc -b0cb477aee9bd113959ff7b7675f81ef251b76cccbb67cf68ba571fc08561736e32c18aae93fc8d1912e7eb2fc0ecca2 -8cc41304caf0357d13a25ecf66336bece67d5d319bc5a50328a96199d7ca4fad05dbd7b5edda58be73141bb06e269c8e -a7b4d91a884abad5337925c34d7fd5f2aea5a09ff3c027cac98c646b5058f7fe2cbf47208930509e2a4eef1468f64c89 -97d942e97efe46594e8fc86828ad3ed1c9133a8067f9b11bc0f4ee3815affbc0c7c46a91c40f989d50f1d8df96982ada -95a7d369f3ce7f7ad7ddf85bc994667ca25a0c2f11b9312d06654599410d5325ca3ea74f33f21b5aeedfb582a9e40c62 -b0a05b564a754b46fc7aa4f5289f02bd9f19708b5ecb9db5c36bb7505c8b56ec22b53fedefc1df289c0f636c97e8ec47 -ab6e2801ea8bc600f9159d05a3b39e8b0973fb9c2696b3f2685424757a6953a9f8ddf5e29c97399c4821b8d7fd9f1bc4 -a6fbbad2ad3ce8e4f9b939080e9e7049eba9f76b8ffb57f7cac2aa46793a064743239ce287e156d49cf4936517632290 -a606632b62194aec737403ce5a9b6316178c1d27baffdac83981baab63e75d51caa414ea92465ef37d6d687b4fd90141 -a5a99b7bf8f4c109af04c31af9b5f3148370319c8483796cbb5ef555ee1d4858b2c1acb82ab5e26180254399fd7a0625 -ab2b00f64355ad294436339636e7764403b821d4dd4fd74a6bbdc2aae450f14d7dbe8423336e793a393f4580f1b9e35b -a6c98a6ad7f36f16633fc216c12ca34e596b292524753ca1067eb75ab52facd28ed3a7c55e0a0cf1d3c9115a2a0d6524 -84acda31e618eaf0424a37cb3c386585a3870b2c24020550a16134ad8802d427c918e2854c98e5def58a2363a8e1a314 -9911ec15af39af1a18003ae120da8d909ad4bd43ff03078091d54de71de70e19786b2aaebaa5d55d9b2877004da2c271 -8cb5a148f065e36b67a219bdb347a625a7a4be8f20dfb1cffbb38fd4d843c2b1b1886c1f015793bbcb02af04ed91b170 -815d9adf22a36533fd4a3efae3c4326213ba2aad48724ef958cdd6f0dd5059b519e12d91ed5d92f1418a07b62b108bfe -ae5c244f309467ada13e2fcd8942886f563bd996a5c65aee73a364c2ecab49be3ba6bc8a387f3baad44776f4f1042eb8 -a47d93b35f57ad890239a6f2f69ef8760268adbe614d5877802db4b6cc75cc093baf101f75be0f7b4d71ad8724dbb9f7 -a0d089701b965df9fea938e337016ab20e0e567e736e6652955f1a93760b4a9f128be5a594e71df8e7db47c3f88c2fa7 -a9d9a7170a860e2860f785edbe18ad909ecfa489cd3a2abc580869c7eb8e9a2db93c1c473a5f1474ec0d51dfdedf95e1 -b665abdd084abd292548c336e3e6fa1c5ed1a53d2e61a10ad6a4c66487d8a9e101632ff468b012506135907f0896156e -a10ccb363b26beb9622e1d91021d08a3bf02bec96a059ead01961ad51610992ef03558c5f77e074442836c9d2ff44e0a -96d6476066264eb3090ba3544dbfec7c8a0d90985a1697985db0d04773f6d37d5899a9d4fb5a3207c320ca78c37492e6 -b4290ff9213e2ecd30d303b2b4ecc66c2614b8df246e70ece4e55bea9a1f5a0bae9df6dcbd8efdcf8c4b0f2f4cb44d48 -8ef10b2e53e6770a36b6403678ffb86f5d85e3e87bb1b3ce9f1f0cb0cf32f1fe991c565595389ad83d8c8d54a47dcc82 -91f950ef60014e3dd28f7661e6275ab6f085c803988b7d6dbb2cab25f10b0372e271267245761e1af97da6f48c230205 -97c626e7114396daa337ada4f08da5129464d8e8c68a407c8798949817337578733fbcabf454a22b57926485c28d9d62 -b596984b609a9858b1adefd15a546d4b8a417c8b54504efadffcc805caf8935b9c7f55d9e6b34592241195f513453572 -a3fdd36f3eefffe0cd2a9e6cbfc4eb9c3a499eec25230df8786b23f5eb71efddde062940ac23d5b2885081da48d3c1c1 -aa1822db9ee136d0a51910f0a59bf0d2af6819e4ec0b859b790e01bb08c1def87e9613b355525d4ab7d088b520a6a3dc -a9089edfa96fdb7204a68c4ffcb7e0a875106886a0c589dbc57a6709e7822747affb07035b99d056baf11d0852720489 -85664ab9d32ab0cc2d2e61901b2682f88a7259c2da4ae6263b917ae8afc232614b4ee56539a868a24940eab74142198f -b90e06a1a117659b52b364359e2265daaa8981954e9a9c37e3256cbabf133dd4900974a895dde6ec6b394fb36b5bc1c8 -b414aefaa4833283dce85add23d1cfd776567735f2ba9018cd791d652bab55bb0cc0cb38b88fe47e3b4b877e63edbd75 -ae579eae9c0b09c906cc2824eeebe5b4ea031547055c8ad635194f3e864c7a184dc21a3eca9c43c01d9a2f272cb2ce81 -a7b1d13997c283c13f770d5203cb09b5d3ca7d45324ec89c069928e1ed1a17c57510e0ebaaf54a21d27b0f9f057bccec -b15d4555520565b76ec21d87e094ece2e04c7c4bbbf560264da37604f1a484ecc3ce8143b04759fe716411293876d0a6 -810bb0773c06caae8cc06ffc92303d51eadca1e1b0acd57ed23f5feda70378e180619f68b8db98e61d792568f49a8316 -87dee32807e2e5f2c884822b31098e5be2a4d950ae728e3281a39e661937c4b7e9fc025b50f437f01d69e5c33dd751a0 -b46810bd73d077a6b73757d22b5939c02a3632e81287073b00ebee30cdd402e89c318e0b03d01fa331193842f3a1ae53 -95a136a7bdca77f764d2c2d4795a8fc9e5b9097d73bb3956b7a45b42185a99c949db8ac5627ca263206cab9cbecbc31c -967eee3c3afc138a482bd120050dcb9b45a9fe258e5e4b678b1d67b4691f4c5d89cd260210fb50f9cf2d3e2e2802968b -b2d59a9ed0448b88f8eb26d8017a129ebaf27f11e0a031130266796e5f777bce93cf2c7e0fba8f8ccc997315db9aeb9a -aec708d3093b12caf29efbd8afe3ace1de24496cee72270223aeaefe4f0ba3a7acea7f2f5f85c1f274aaf5188616133f -8563ec52704c1c7ab515451a8f89f87201d30a12c95812ac95fde2af033e5019615a07f28b540a92781ed35786b5614b -b1c8f819a4ceb17d35ab997c14f81ae2af9d4510caffc61d4a19e9129e0bf7264482a10f329054908f99909999b6f538 -8a65668637ba24358800076d8edc90979d6e614e6a683dff7859ce7d686014e6de85298f523ab060c9a9a4c4b8862cfd -b4df02dd6f4d3908142654a42af60fef034379b1526c12be66afcfc4f1177991811646495aa85702f3461060732cce80 -8991bef253f0bb9b86e68e81f78116c51097004b0309e199025e45ac7ea55f8f6b2bdc58886899d275424ebd405ffac0 -a74f1048548fb41e57f679d632280fd2e4cc6ab88c81675c59fe143b74dc7ccf050db53dac5611ed6b45b6a0b1b7f3dc -92011c668bff7ea995a71e4774e3fb5d521ee2552bdc33d9a65afd9677572c2a303a940751ffea470af898b01b9285ad -881a0e6042771492633b46b6101f96a48a93aa3860533dc207cdc90783fbe52b4a9ade1eea9117cea004bae802cd3fbd -b3e578bfd77a3a13368ecf8139b69f729cc720aab25853cc9e2f505c2e03e75cb779d685698af8cc4aba8d1c17f5ec29 -a025b6e8dbeb68e7ac4a595b34089fed0d24eb29a7be235048205e35a97634d6015ab24c21a017b5012c3175677fd0bb -b751acd86ead936ed0f22d770872cdb5aeca3b1ec75a5a1e65748b665f8d1c859b5620d761d5f0a2a86331188e82b2a7 -a05faf0bdb81caada6c662ed2fd145eff5db5c423258d6609bfd4c467edf3ddba6480ab95ac9f4dbc932f4887b070c82 -8fd1faccaa7cf1d59be37bad69b7a99b7641cbfe930d778e0f712ae1fe9e78d53f37d7d5d3aafde48452eaeb65d980b8 -86042bc710953f0042940625d8b69ef57c615f9631fc49aae169ca595446e9d55e149c92994d4bce7b544877d7b6f22a -b396047f716c5fa8ca9234c7026f1772d83f41be03410b4a32a376e5a038d252b8f36cb813bc3684f1b50326994c31cb -a2eece2d76db005f5d95f5f480bb3353ec67a9c27896fe54a2cd5cc7f802507d8d518596601bb3d2798842b96fc03df2 -b738c1264d094f7b7edd27b0ddd8e29716c73bcf7b450ad7715fd21e1052998675873ccbec486fe45a8f72d9b006f239 -826c4c5fea1596e353f6c15d91a9bbacd9ea592aba4d22e735263062eac44f073e5defb794f8ae4afb7d4dbcd1ace959 -a8f1d170f63ae3b05ca9996347a1b3987136e7bafd02774698829986d48da3d421d269d31743bfd3e7917c5ace7ce729 -ae6871a8278f24d816657889ccdef509df0fb941fe6c5839cbfb704e81b942ea2a324fe0ac9881b385bc97410fd94b0f -8aa6bb564b6a0354be89c4ac10309f941162fb3a546259c5d789d4608cc628f69ecf814b59bb8bce364162f7552e628e -8ed85481cdc58fc540384213dd1b86f80af8908683d7d2c63ef5f8c4ac2e90f0e5f4e07b1b841eaecaab1f7e091423bf -88741d9c9d875e2c1ee5b95bafa4d8a22d72a728260297d048e4f0cd1c5f1eaa94fc233be3fa15a69163f218d62ab17a -8a99655974ad5c0f27b49d88a9c52a5375e16b9ac4f22b1e1bde53ce0a21589022c0ea926a4c2d7c432a53656ccffa37 -8e2628878858764824471fd613cf40d1bbb3fa84ed081a762da0d6d491d54688723273d87a587ed1d3067976ab74fe1b -8f1a6162bd6cbd2353265bb348311073bcfca5a86f41cd0c63ab91b14aabbeffade5ae8a94f8e91faa386223fc2bf849 -aabe8cd92f0193d12b032a9bab4bf4f02ebc0b24d1ac09f8ca8906621d6c7d4bb436b2dd879a1a1cca2b44ebb5642995 -91cd27988ae8100d48ace10ac9cac4cf1cc8539bb492521a8a6489f8575a737f2a1d37fcdbe88dd651179145a59af920 -8baefbda554bc0a0b425f2e132c7de061fdd120ebd452ecff0d78cc5bc5b15401997231727a37e9bc4abf1a553a4cbd8 -971b12e25b989511477c04602f48f584485a0a0773b46643190263c0288c2434969bdddb1e55dc1f5b1b028c1c53eb32 -a0e47f42444a16e51323af6f519c0dd2271a85746882818d02373ba33c2e2f7bd6a1c321497377e4781f72427fa34224 -b52bc02de867d7b20cd247cbf496e03d940be2d7ca5755145e9a0168889db345fa9ab17c41635ab275a459fc9d02ff16 -b01db7077e9f01e675c62f5095400cdc68a059e1a5005027033ac535a0505f45f89faae4fb9831f7ff9cbad3b55db02d -81ae065f1d55f4643a2ee120bc1245b9730455ad9e5402df8d6fcbb1bec71e40f1bfe7b8e67f96fff76d1478cd3973ca -a1be3723920044be80f398279e2f8432aaed45a36cc4fc71c87f5dbfd52225379e94600793f40aedaac2391caa57d155 -b682f74fe46d4b647196b7c14804dc0b35e36cdff59671d7164ece874107964ff9f76c29b23c190796a9a3aa2df822fb -b8152e458970ab53f6b5bf6101008c5c31d2f58993474eed6bccda074555f7ad2351810d78676b62612e7eba2d86247d -9132a8fab2010360ca80adcc08b3a01658dc8ba8f60bbc45e1144c1219f69b985436c36c65cd7910a8aebd91ea1d3d38 -805cd373a0919de801b6bb7a6ebf55530037fa41a1993c159e90213c492165c42b5642dda5fe7283ac4e3ade6e63a155 -91f20d77fb7a8276174989faed41fa6da841d35b074c4a756c2b4730a7efb9b124ea6c7d5eb150a8b1126636cdb2ff0b -8cda3ffbd0ab6846dbee6cb8c0360842837a65f83b6ba17085161a7371a4466172354e494a8614cf2f1f4726d0a7262b -adc603e61dc36ee605dd7f2761ed568bf91b9dd3d40903eb7d77b11d10e4f762694fbbbcece72a7ec26976054139c768 -a6accdb3df5029f19273a39bc30cb622f87522ca5a63372dfe61d993dd783ca5e918218b5c519d25e535d8b8238339a2 -a188897269053f2494bd0de8cf098e41010fdd01f5a49d7ddd7b294ea748f1139e0d92fa7841dda9f8dc923ed6f02615 -b26ad5dde632259293d91109fad4f742ab74de91f68ed2416ff53c060d1ea4377a875b2ce960cb7962c37a5fd47e85c8 -82cfa86a17b27f375172d66b389df727734480a224b91585fb4782401d6c49d4dd347b8d1e8df6b9c0c1d2f8ae658de6 -82911748e1471bf5d7fe3ff111ac06dcaf5b8a43c76f6583ca491e0aa845b61cdd443613c5728863c163952d86bfd482 -b7b0d4ff87df02b5481183066f6ac0d1636718fbddc19889e92a71a168fbe338ffe780a792ec5642aaa4024d0964db69 -8ec21f08594ad38e9ac365e5246aa5c2c8e34ae66382ac483b47771c33390ccace4d906695b1ac0f1c9204c46576946b -b9617d746596b26b84f2709a03b64fe77e9a10d0c85535d92d28dae9de3bbf6455a247f775dd9f67061792cb924e3925 -abb2ff3f16309fcfe0a3b1bc928ca5cf618706cad3645b029bd54e5305682754e6ca47e364ff21b1750f45041eeeb358 -867abcb8029b35a54552c57346024ae7eea38e9ae4bdbd68bb3c1de3935126880f237d9aa95d6644dba8ddce67e343e7 -86eb4283147a9e595d639f29a967310acbed9ff09d9043868fd18f0b735d8619eb4ee0250764f35a51e00b58543bcc66 -af1779d2115ca7021533bcf55a100b4d3ff4e45f8ce6a6d98df22881526a429d97818fa1867ede09918a438957a03534 -b10b36d0b69b0dbecb6f7efb6c612b0462c346079109970a26541a21aa2b5b81c1e121ed0d5c81af00ea8eb709a83dfd -911f81ed75fed55f1fabc5f86f9f38490e006820e5380963a739ebc0f87a1dd3b7da8c69dff1e580c5ad2246bc08e2cc -8379449499da9159cac2c09c61777955e61c63378d051bd28b59c78409ee5d09c43e7a6c246572bf34233a314511bbdf -84b48ec8895049bd03dc3256bd0d63f6e9abb178221f7d47703b447c709fc5fda47b19a3439f30f10d2670194f390915 -ab3bb5afe824d8aa20f97ead4c40aaa93350f33d980b5783cf56c8552a4298c989b7b188d023711a2eb79631f3a8c317 -ababba2722186a3b2272feebaf2ff46c93883b7265a6a4fba039d5fc0e7fe81b7d4dc2cef7738406f156f693ba3a55eb -ad50302a51eeebe63085d3c1705eee9142bf8717d07c5d87e0e4ef5a12207dd5432994c72b9493f9ceb558a20929c9f6 -8bcc3d83a6b8998e1a1066347c647ab122eac80c9c505d5cfbc370f466349671d8da4d500201226c15c1f62162efc62f -aad6946b5d5df34ee6f7422fbefc6de33dcf4461868ed7ee7f47fe9b8eb2f7a89759c73b7a029d422b02afd0f550e722 -b0fe1d9a30759d83084b4c567b586e5a8f5a080bfa93b4a3feba59edaec33b6a2ebc98ccd82aa9d8cf0bd254d5f03baa -b993c4c2b77fcfbdb213bfd5f8d655d1d41a52583de63b432e2732df2f9d88c4c6779f314848417c06a089fcb970c0f2 -842ea3aa645e5852695405b6ff2184e55bdfcf50be2319761e717b7b52d904ec47ad3abf986850c643003442e302ef30 -8093b0ef1f6c84a8253d086a6fda6be8376f925f416a9d1f44ea72489f60fbd8b53cee616cc5ece43e2a202653c0640d -8c75f10b6aa848d84baa4120e75d3edb7f8471473851326cbd9ed7b29b22c5403028f49430bfe4320c3f4227827e667c -b4fde4f20ab98f76f55afd533f1b09ee4ffbac9486399714514fd694fecd0ad1fdafe13b2b80721829c7a59e4c951a76 -843b2ed867cd8edc2eee84497dbd49f3dc481e7ece69310d06225325ef032a4e72907e16e7b6215ca775f88983d55e5c -9881e5caa9706e4d7ba6ab81525090e29ecdf1808931f3f2b11ff9ff5cc97f83f3e14fcf18abf18159c3fcf4cbc27042 -b6c4acc868c05c955eb36a24652314be37004bfc14283600523729d466c56018c99a45a41ec0389449fcc3f8aa745638 -b6820864d07715dcf4a9ece336464aeef9ce381ca7dba25acd48f60af056a3405c22792cdc57c641e782896c0ea05b25 -a1bb482e35f71772486675cb4ee0fa5709b757083d18a29d4f4344e6ce901b2edb2889b7eac92c498b90c7d3844c450c -8cd8d8d47de859d0c68bdbe1834a1c9a34e92636600fc592a08f96d66426c5f41f388138f42c9b8ad72c596f4bf85496 -801cc0631310656864b25d980c9e99a98fec2316414819afeaf182d3e7ff93b32a989e2ce63f5ea9301745080854188c -8fcc6b2b656f7960d9ad48c091c1ea71b6f0f61553f7695049c770afd509ee58ca8e1dcb403aa2c5acfbbba58676bd44 -b997b9a6b994e3eb2de8723ec485d8181fd674de19ac9c2f50704785d9f5a28fe3ad194eb052b5ce122ab5e6e6968a70 -a909e7002b82b371952ca9d0832f531db15882180e97c12c56da649fd65334904fbbc3f097b6a954469221d181e718bf -acfc712e1a61504814e37b3aad0d7a5cafce5901ffa43c13bc5f70507800ff03ed261367ccd09db7429cc5dbb892a7e6 -8d634a07b69ad87e41d941aca08550ae9cd72fe31f3075511d030c364fd6578a36f3f0f3785d19305a1e772486ca097a -9746ce2d890248002c1bfb755e06f4f4570cefa7636e10319bf491c654b83608766e95fe9c77f1a6a630f5add77b71f8 -a9dfa56bf82297f709f1b4bdbe4bc194bf22c0424815bafa6c1a536f2d15f35bfdebe0867ff20781a49274075622861e -a723af2702c6b473caa4a64142464f201bd1e2f765454fb0236082fe3ad77f22b4353e5981e6bc37e974c7ef797f875e -a42a1a0c50befa6864fa35c25a17f5309684c53257376f8111fe96c84a5e09376fad9c8545e1946f360e16e1e4c941e3 -84231f6bc3038320dc13f3ac014977326dd13e5b2ba112c084d366b5255729b2abe665aca8a41d7aa6645412765887ca -a64e21d651bed6dce8dcfcb4caa60791b9345cd7b6a100f5bb78f7423fba5ea0d0cb3668f3415c27af29ac35e5dab0ae -b8eeb2128ea14d81fec5b1103d8511a3dfdab925212363c75c5cc01515fd94be8db2335bb84e221654380e58e9f2be67 -a92e9cb287981b33a5e697eb1e757bd44f45efdda1759122fb27dd4bd4ce3694f1b6b2082ce4e6e3919d9d7a0b7c8a12 -88f22b83fd9dad63e800b0bef709759f380c6dd9af7058100413e7b09c7517eba258d6367e0cb1a41b7762b86b2ef137 -8353d45a2096fb4bde82ca22381bd2ed93fb58b236b16e68bb37df3024672067c4378d7f04a4da4d116e7d57a2211f7d -9076205bf231de091fcba7f5a4fe1d4a359f07236efa39f5715f206e5cb7eb3d9adb56af8181f63a9d3e965dc909556c -93ab7f56e8d37b47d3a8cbd222f2dab4bdbf94a1152302752f0a731294f4dc214fdba17977f11aaff2eea9517fdd5789 -96d9883ee108c88342befc358325356dfe5d72c521d71e4b3a58d6773ea3d1a1de1a20572aa96ca0e8483eba62466504 -950e0d61ce4e76fe0cdc3d59c5bf23d8e1cfa9d6ee13b9fe41e6ddc0fd52081bb16bcdd973d319c20709ec517fe15626 -88809c1e272b552d46137165e5396917d107547b65059fa646b742489e8892acebeccbb3eb8f2d676e3836c985cb1756 -945f13ff081b74403a19dbb04173780f04766f7624ac6b77f46464df5f4f3b547c459f41fb1842164d8f1c126ad6be65 -abfbadc599bcab1c2b7cf1fc5aac7798d9f617d6afa0469ee23230c0d004fcd3de0ea645feddc74e676ecab1fcdcd8a2 -83ea1571b064d05e1b7f4527b20ada121024a4b2dd8f7d551945488ccfddd671ed2ed3895578afcb3cf958f9a2c75c29 -8fa75050bda001409f2bc0a275d8dc0fefaa47b3a0ae132758bd711eaed0851d6bf3e4b7f355377a93fb8eb02b3ac6f5 -b2fff49083bb30e2661e2d8978149e0d0588dc972222f46d5d120d01dc5c9978830c442827c8fa295f6b8e6d8c786198 -a352c2dbe4f18b311bf0690d77fbc9439a1b8088c806a9d89071b3ea04ff387325cdc04a091d2bde5fd087bcd0f4f482 -948ea89408826ded81549cce823dfd7605ffc2279ca7d0964b1ab3d5f35f4b174e81575291edeb9eaa4baad3610ba3a4 -998073b618140b04ec394ffe4af02df044d923a5cbc8f06f26c9eb4ece17abedd4f72e10c9738bd16863327c0f6ee20b -b3bfdda0d6960af897ab508bd9312d9c166157f78b45157b46fd2e38ab2e430e8a19335d8a611366cf74642bda77bc78 -b8dae3e2ec5eb97ce3b5e9be719bb747e6e8f28dfb1a6b7bf5063822b502a5422cd586bacd87ef83c0af081ea4d30a57 -859713ddf0ae843ba690fd8177ce6c08e2fe5fc1c8893d829d39a199e04758719bd3046034926de40973a992ecbfeda2 -866f150d4b6a015b03ce8ad93a70644b55ca1818a0f50d24795698c62f3abe59d3b8abe4c11ffcbef20127d3b7afb970 -9145367ce9e2a5a6140db58cb097767b5a6e19eb36d1c03acadef612af95eba80048f2b02c6fb46eaf38c75288e3e4eb -8c298aee778f4af13329975754e9b428e127680f26be139307d43268dc63892ac98284d78ced0ecd384301e26d5b63e2 -b4c2cc9256fc33ed09531abd7c3e34f8f24830a8a2cf2d684cdde46155f43ff2715c94e7dfc7377765ec0cdefb21cd2d -b9193113b81bba4ebfe40e97be436515254bc67a94939220e5e69a197765bba40dac3369e5cde115d1bbb65e1c826038 -8474d72b7cb52768c484ff92d014d7733003b511c0c915649f65dfceced47ecd933ce876eae254cdf2f6357ea865580e -808e9a59f947b2b39af51deab4c164878e02d95773dddf1123091e27de87cfffc07aecd7c9cf3e08c0b9f525bd87fff8 -a8e0049eec8eb70c12446596ba5c8a29823704be3753312c34cb271000b6c154b1022812dd02d1352cd263b655437d6d -ab7894a75e40d888a4d0539582cfd6b458da009a5017e561c14d312335a75745ce134b57466fd30c250ca07e0529c8a4 -b30c5c0abfd35ded7a3da8f9c95e3e1c320857be1af317f6ff5e35101d3f31de3735ff8741f6460ae1e63cee543081fc -b15557ec268b4eba9628ccec0a5f3c947e624b61edc876e2ad8c36ada061fda76f69c8afb95270b85f4672171678d078 -b7ec103d6695fa64107f66622148902019ff3acbff7b77ad80993bdf209b73990b0fef92dddc5fb66aed77cdb59af9d3 -b3d002f0a35808e3785d58d0074be620416ee9381bdbdc889805ec2acfd169e1ccb60045d87cae3e90d5da94cd58bf80 -a17c44ade6eca0942742edd237661ed406a129a968fdab28a58d19308d207a1e7853099a4a3c1c181695fcf265107a55 -91fe5c0d672fce368e229e735eef43868e31265502e2876e54aa44470a257d1c126ed73d6df860f42d8e1dd425d8987c -8434fa331278fcdff2c8c07596a051847425fd7cf09af31bb235d208ef6e282cae173d6ffb73c0475307453d6133ae7e -940188d6c20924edf1d9343ea85ef9e08d9d87d2a188f8b69514a22cae10aa2d3ea8e662d43d60b8b77183b3c6e8cb1e -a89f57a730437fc511e1873830b300df7a417493a468afeed2f837f31641cba04924effe11be92d3bfabbad0bbb7d04c -a561550cb347fc9178c875ebd8dbf5d14c0afbefa79f7b93b893a25ca8fcdeb0293de5a350ef63413aa70745cbce9a5e -89fe7dcaa6a10cdbeee9d0d3bc8dfeacd47e1490a6c3b591f66d3a64ed668e6034381e0ea9f5f04fd2a5d9ad5044b8b4 -aac54b334514d41665b80b2cf18285391f47be820446e2272d69edce022f6d7689c8e137e2e9579d0846bf5440d768c8 -a231a04b942d471b32cdd12eac3eba00b8910fca0812c9470802246c479050d6c860f64bcdc6b6e39ed0e9609df9239c -a6bf6eca52b5f3ffd89b79be6edc4f517fe9c9bc67051179157734689fd63649e321d1fabda916a9c4666b64ed60bb4c -a7c4f791a1d77cfcdf34c3b73ec7a43aa1c8ec81c39ce81d12c51973ddb0bfacc79e1a128ce17afc5838982f66cede6a -a1644b337c4398f00e9ebfed20d9b2c900ccb667be036abba0c4d372939f881df2bdb5d40b64354f65c8f2ad9ffcd656 -84f6e86481d3322de791ad01d8c1556e5480534e52970fa601b295a40270882476779301d78bc2ebc323323ad0b62253 -b32eb2beaaeab27e190c9d381b9f3446038391da552db5ded0f5b58d070694f07c737315a465175da29e2a236c539e9b -857029d97cb9fcbb67e194d9aeadf5b25cf8184b3b704ff5da424fb4b39abdf3f7f317b3f79c762605bd9bdd5823e7aa -883926170997ba84cf45691c117912f6be5c691abab77fd18fe114577e6dcba18f8c0a6641ef59affcba1b2c92e093cf -945be3febcff77b4238500054a053c983add7a96ef43cd91921dad908c20d4ae08857fb93a5bb588e9b441aa9a536567 -b9efb8be322722302d1c06640f772596fc362586d8f2e49c41810f4bd2b59e8e9abf3d5369b2421e1ce6949c067f07be -920ad6d5cacbdb46af424141391817da2fe3d463bab8db760026f98e50bb51aa4f3668520c133ccf9622d66eb8a60e86 -a1a9ca07d8d3a44fe372aceda194f15a2dc3d29267aedcfc3fdbadff0bab1c4397da1049bc0feb9097afdcf1cd1ab603 -935eb5fe97d580c10766bfc2fbff71d8584e00e1a321018540c25f6b04791b63a0d6992257fe110b0d17712f334c9b49 -9530bde6dc33e48e05d98b77844766afc0d5581922e382a2fc1c183adf998c8137df29e56b868c7892b2c1af56edeeac -a8cd3698276c2bb8d39ebf7fb5fec139580755adbf81bf362e1cc19f4a8be750707bdf4e1fde3064873495cce5cf5171 -ac5a83c82004728b34677bc6b1fa507687992b5b78745e5820de08f3fd99e35c905608936ccab62ae39f0408334b3c6c -927b0077386a5055b499cb5a597ec3c9934767343fd91214fbbb5487faa4339837eab52c75a627d7addc5cda5ee35108 -a8acc2ea4a548d9a2fc2738abcf75cc0efa189b92a99296c0635d53f2c0d7ee40ccc8ae410d2779f95ac6f2027c81d06 -a74c24b8c695920b12a86ed6da6ecff72f8e19fb06fdfee9cd1c1e8e5f1c202d26fbf2fbedc9a5deaeb2d986425477ce -871251e8d69de5c3117f364bb95d876fb89974428bc167666088d5ff1b83328b675ac2efa2d0e215831e69ee254623fa -946f7a6d3d6700f65088c817636ed3c1349e4f5122fbc22723d131d8ccd055931dec977cd0cb8dd888c6abc51a5f4194 -82f7c1dc3f133725570c7b64e31b0397fc3a82cb4966948803de210182b9716ccd19e59c0e0382c0c970d05c5e13509e -8bc45b43102e0df4767156b1e8ec635cc07fd629793d289be1f2470297e8a084bc9af0d76566cc485a8ac898c0493fc5 -85000f8c8130abca642ae94b4feb3448390745decb1f443c34fd06575f1d0de35bbe649b46251df0a4bdc7a8bc133b2b -ad1ef07d34c59afa37fd5147646c24c03622ae4884c163b80d45ebfb5fa994699ad9166ce1ef727c22be3c28e0838cbf -8d1dd5500229f463f94c611bb2674640d20f2d34dd40b28c4d2a21d3e64ba7355fae55228f1c70095d1b288828a1950e -834cf56a4f2c2eb04b89383213b84bc6ba554a4715c3c1547278e5501102f6ff2af27cce0f876a2aa2da57b5ac6f3b3f -a468d06083d770bb4e484718d1c147b49770757b5b296fc6d6035ecb3c2f5c4155176f12ccbe6616184789350403f387 -8abe730d80ea895705bf67ac4f6b6a36fef7403702d8458a383d04e4859b4c8c7a75598721cc75793d29276afea27ccc -a3890145fa43e6b5c7b8aa0a73a62c39d623c9a75d17c5a05bdddec08d114ab5b0a865c9edb2be6ef31c3dc9544119ea -b2b7c1cd0aed6b776515a12a0f3a86353fa3d3a3b6027422bf7f2c21e6917dab543e189e860c8fd3aab65484b77efbe5 -95215b7d3d504ff83ae2bff789feb6b5919287d354d567141bae68a0f0d27b3e898edd8a9be5a51c04dd28ce9d4ab937 -a93a3da0e101797c690c38a5bf5bc14e10842e48a18c9888807b2233809ea8a34a76d20a8ece0b682d36c086853cee40 -849a7fee901a9279dcc36fe8f276ea6dfc37c30f75b679ddca2cae9c283de19c4df56790e6ae12c4bde33e837fcbc324 -b5c1587d84b0826e64438d8ee7c103119b164bede8d243a0256b5b798240259dd63281b81bfc613a4874a6732d05e143 -97600c536388c942e0a72ba3bc33b3af48045994a3ad0948fe0741391c1eb99693d072d1efdb644abcb08e10474b7885 -94c2120a5b4743496e7ab9bb2e474580ed27d7cf5b6fb132efcdd7bf934434d2be8d6f0af009c637b31727b3ad5d2280 -8a5ff1e7f552fa8b34b22a220eb1cb018c9c9430f0f14a634121923497cdb4a69fbb8b60eb33e5fdf9b0feb3e9f5afe6 -8b4c9032f25181e6fb9f60eb07e3d6cfa2b14ffdd6a0fc1b309b078f8290901e229a5a6ed96dda74e1a9a894224ff588 -a5e04e164ffc46da1dfe026ffdcd99332874a110cd168c44762c461a5560b5c098ec71673d509fc053f6d9064d4ba255 -97d21cf8327a81385fd3915c7e8efac7662f4b39a9785b4a936fe1b581d630678f42a3e9ea7e02bb4413da7ca9a6f35f -806d8462bbf148eb4cff812cab11b3d819669ef5f0d76b228fa166b83727c92fdac98ff3afe946855685b050d9d4c6aa -8a9899b0ddbcf4ba3f16bb006218022efca867a5b32e1de9c7efe1d7039c8e200a406bfd09ebb8921bf1997185e9266c -8fad2d8629c546c5de443b36927b068cfa333c8c4c1328e1221a1f6af7be5363ab8981fee54307532f239eda7656e6f2 -930146a1f6c3decf40198955059f70c98de7c5bb1b25bdc97fc72de3a84db1b121430cf7a7456a692d8bbb6b325b6001 -82987887016fdb90f79f045c16629c5b2b17b1b4702cd89d06b70086e5922cd10c5763cba6f3d30a2c33bc84be36c6f5 -a6fd7e4834f7f29da41170c13d29acbba86c74d5924cd361588cdda26a3ea7f11ec34c31869537ff7ee0b57a24555e9c -97b2474cbfb632148869a6b911c2ab91e4af9eff6c181566a1eb34a05d2ef3fa9da4fdf14e8fd8746a7c3123e20d572e -99ea177bb7d98dce25d300b09bf6ce08a7061360c4ed9a54e30c1aa5a467be6225737b62ae921e91547b5b9d39b800d9 -b9dae836e37d51c9611e6522aa6aa8bccf2644f23113584c74c963d79af0a7ae533af823215fdcbbd8df62f00ec1505a -b1a7165aa1ac480b4eb1f0b3d4284c69907d1b5056a343a2da84b3863c9a2ec4d757493f5daf9ef252a253bb3b2b6745 -a1322eec41b38b8bf3f4566bd12f9c230dd04d085e0526218489e986d59895d471bd8bb08351edf40021efab1d29b2d7 -96d559df46015e62d8876f4d8679f9a9867dff31eb151238cd75b3a10bbb2ab0f51c804a2f5adec1decbfa355042a6c6 -ab55e38cd273bffaa94400bf4913ce0ec1c1c848e8c53be1808d4ce5338ec92b4a4160b8faf0d1d8ee8b71ae751d0ae7 -b61c2987e2b402a52670abe305f8a9976efa9720ad0d7c5c1d0d6d9ec6f1569f51621b6edae84d9bb3fef32bae31a088 -b5234aa19fd9e714c7a9f3ea33d39a5c49f42e7a8edabd8f306083669df4898711d4b50b049dfb91815588ca60052673 -8e98a7b90baa4693c6a1e1c2e556d018c3408bbbb5dcf2c32d120f797fd8ed1373f1f112dbca114863801ec6efc1a5d0 -a7e1e77cbd6274f8c74b37a607cc20596bb7fc35ff1ab4358de15b07952aea397e409b30188c8516676cdd05d4919f3b -a5f2336ed9338772b71e490b1b3916d33df8b013e4d38dd57185b7314ec9aedaa34eda2733c38e06e656a8cec74080ab -b5de079ec867af3a3910fe47628c7d793c7d70b79e25a9a436e0a75405e2c58b740c1b86e1b073842d475e0b717d0bd9 -abcadb7a09173f1eda179ab7e3a5722f020402eaeafb9d604641645c21f1e009b758f2a6fd262f115d80e23f8baf7328 -8694ad59d4cc328b064884d147f66095605d9bf339d09e45652d68de765f2b09d45558d45daf9b4b36dcf881df8d4fb8 -a2cc7b2e812041f17b450b5fa7429cf62e2da06a7bb3c08a63d6f802ddf13e8b73d2056bcd6407476dd322fa35b9b065 -a97b0e7e22214f329fc57b6d7ba882ca563f863c06f1afcb60c0bbc81ef08ec866d39c81a80a7843889fc957d532cc0e -a8a809392dbf35911df8566dc20e2373e2fb3272bd9eaf9f474588a9132f06b5a1433ba9f36a738c6cd3fee403188fca -a3fb0038f83116eef1d6b023e2e17ba2795f7f90ed7c857d9f04337cb4e0c2e7d691bcea54aa72ac5e4383125b74b755 -a80ada835fede8d121162aabfc8c349f685775406693d599e3c288364097b02d96c10ddc20e72fd308fc882e5b70c064 -b6e6c4b24731a2895b7513ad97c0928efeeb0c645dac9fc8cbb0a6419221807073f6996f2b778e1dcdde63acc3a6b2cd -880a2e8fc2eb57f44b08cf4db5cf1751bf9f4aa688708039007d2a198f4e7f0f808aa566b36b15b971e804835102400c -8b3baeb4e1c1d7493bd885dde7873afdc235b58e45b515cf51ebcd02a9b81911c5ca182a9e340575585186c99e71d2bd -a6248e1bef3c6c6ddc155dfe95631a3f00308fa77b1c1779935e76401e750f151b7377f9376c08e8273680e924382af1 -800133df4ea65de3935d98b0249e335a918c44167a34a16c0a4adaa4654f458c376eaa76ef088672d39aec4c7d951833 -8317a6e0667fb524f35672e070f047db29450b06348604319765e4db09f966ad995098cf38acd30346c7fef5dd62528a -81fc2ef2ee0e6f21f406c51f02b9b7be8d99d30a054df918cf89c708d64c34d8b0dd060dff4383de858c0dbff25d71d3 -a28611f96138fe6974e3e1925b582cba76166259c32b39e95702fa0c4957ef2ca32d575b1c08cc8dbe96ddc0eb56a9f2 -86c6773f4e0261413d6d3944e0f7e498a6dae518120e3940d2f45054a912e706b3b615fd160e6143a7e54942406f9af5 -ae91e3db099d165b198d80b6d9af894203949d87cb980f4db97dd43ee55fbe1a45df156b72e3c3e9306975f9e5e62d77 -ad00ceaea52dcef616be9f9815548f8e9b800bc9c1a8832a4d8acca6c8779317d1951e5700e54db070a23db41266c934 -94426f78470aea2d82eded320b45bea09b7cbdf02a3d7c2af4ae4567a3493b352b36f43c3669237879910dcefcc82fe0 -8aad924eb1a30d2844654c9829d82c65fefe964d815572b6c9f902c6a826c247257a7d0d4967e2bae331d52fb3b7c0ed -ac9489ec928e4f43f8d194b8f3ab83382b66b045f18efdfcb05c1d4e67af7b3745ffbb7f52cab4b8895550d10132e2a8 -af8f390c7cc40a08c0143b467634c10e8046ce40466006a4b4297c76a6c16309b50f41a4a022fc838738c4c72edfb34e -923b0384e87a2ddfb7a2c47f628172e8dee76fe812c44a756c67cb20527d8e9029a561bd4ef446a013d4be7db7259f6b -856316b53f09a90af770bafb5c9ea7deb921687fdfcf512840e96fb83df08820c42263c9ccf51465da33f1b03db04d09 -92e8823b523f90ab75ac6e30869dcb257d232b55a3e167769ab5b54cbb83be94cf5d84eed4b1653db17f3f1350ab5e53 -8d0d05fac92079a3df86a72fa399e606fec7e56f81d3443cdf0cd373b3330235b76890197ae61f24d17de39dd1aadd06 -8a801fc71b9b6988a829044060679a7cc3d40630fba81f72bcd15c0e5728867f4bfe938066e68cbb54b042a39600fde2 -b40a6a786ca1a21159b72990b4d3ae8729722cdace4e8124f8cbcc3fa96005563535d28e9d92cda02e91d979d27f8f97 -914f30250d79829919c8ed184c2e471c0d9835f2348e628164dbfe39a51dcdc3f8bf99c945b1f413e65fc5424014e5c2 -8ab8b347b7846fbc7ffe69c89ff67dafd522bec708b7ffea312b3a7eac47fb9d6006cb9038962a07dd89d4688ee6a18b -8e755f8cde0750700252e41f6d16b825e7f02748a13744c004a52b19e52d58c42d1ac32cd5ed1d6ad14cee5174b4ddf4 -88d6192d72e1fefbbc9ab400e5b0018bd300839cf604cfc1034657f62fe8fcfc52acd86c207dad0fa6383361d338b2bc -971fa2ab593578b341076d98c49c71dc7d9eb4ca706efe252441499037cc86fea49af681d8a4d324d302526b2a3e5c18 -b2deac648501d7e284a85c19f514f8744c48d2b5516c993c2111128a9fa042aed34dc371a0cc3f00e918531dbf16c0fb -b63fab8600fa531d7f48f8d207298544d2e03d4da23cfb43d99b0612f1a20441526de63b7609f5969429e763147ee5e2 -a8f30d9b4ac3675d61199e8e624f88b9dc52658a2ba26a2bda5f9cd3780f0b1e32b56c825d9dbc3a059d6c61fd37e261 -8a6f8e963dccbf1db9c839c21a4e832c7a218b00fc31400346b5379fdb8394142bf8f8b981fca3f4d3c43d4e34dd3e31 -b4883e6a4213c799abb2a9b6998ebd4c89aeadfbabbe4c363b22beaff46939dfbe4dd20d113688a293a41daf5cd82c8d -aedb55058fb467ee9556a3b601af86962f99fc06f7eaf837b4deda030b1899f565da07ddc7108e9f5e7024e11c723ed0 -a8185aafdbd22a2df2ea0f0cf67fc88c4c3f8e64040da08cfa9e8075b792406c20d3155d6ea6fdcbe9f5502c44125545 -b2b27ff20d24cff756e8edbd6f8686d202d687016c561e56dcffebc78f404ff544c4d3ae8802b91bed0487792d6dfd05 -b6fba06a70d8b1000555b8c6d791b1db3fb7f57a0f8b1fa8dd00b2ee14242877e1e836cef89be3f9e0565e61a6b4c275 -92b3dd6e18600ab856c276bc787429d42b8c02abf5243f7919625aa1f4e8cc3eca61cbe106b81d0e4909393a5efc021a -a508e1a1d4375f5130c95a169fd1d4df51cecd84822dc28b18e464c2189d464e6dc6a5855e0cbb94500d041319749ef7 -84b3e9a6b5d1a7bc7df44ce760b5b686fba006945f6e1f3f67ea2c90dfa6ed70bc1f021828a0461fe158ece87deb1e30 -add83e686118fc5eb56d79199d33cf0c90fb2a5996c6f453fcd9b9eb3a273a466776adba1cccd6be62a4ea154480fe17 -a1fb58d9a323dcd7862ad4bc6359ab2bae35a608276a3053d40bb3abdaf3e8827027284d964e51ae7b61dbf299f2bea3 -ac901ece7cf087c782f75f1c61371f77ba061bb752ad680c9b1012768e5ebb6241b492bafd9e016e989cea1ff51aaf5c -961b9ef616b7faa3befd807772893c7c66ab6990a9405cf4345ec29cf13d75dbb6da41ec87af5b5c4bddc8787b88b480 -b386f7ba0b94ced118691d883549d70ecd28d1c0d1b718cb82a92a246e61de4ba80b6a76d6039c261e342f9ac136941c -b6415848092dd93da62b5a5307d356d968bd7c935d3626f40e9446573e5794f37a23ca072fe8af2a9355a4b04ad35e58 -843b3e3221bb08122a1e649e81759297d985c7f393c36cc3bc707a7aaf2f53b9cdd449e7a4384981c5976fb3955871d4 -94083ab99a73dc5cd463b5259a0f4e99847bf32ae03739a440f8f48e12f078602c76b3fe4e7ecd31d52a7aa31168c5ee -b6f994b5482aabe833e388b24b9445c01e47fd6e354c3684094237189001290aa77a327181e7e7e756682a04b8b3c56a -8366f418a3fb2dbc9ffb5b798adb968aab991fa689ec24a4c4bde6f046989b1815e1bce5e846f3554028e16799e17281 -b8e5680915eb37153daa9a3a977b47c88b4f30fd358901888a1056e07d2a7070d28a47acac7aa7856ede16bd0c93ff2a -871cc7a122cd7b9ae2199801e6a0974ba8cea64e5866a5130ee0ec926adda24f91b3ff2785932cb55537030bb5ad811e -9370ff1ba27d33080efb22836147f766c60f0a8ca250ac6b2a82bb464ffa543da056284b712dc3cac53dfd1680a4cf87 -8614d8029df5058f5a072716489f734131b228972ea9b2b952ab1150bc50b6637543aec1c35763f8dc578275f7c9df3d -b8efd01dd0016a27a0e2df65b571d405be4dc8e0df5dc0d8354fb187b96589e95847ba0c2856613924125d21193753ca -a86e524431247115ee497c07ca2a73387eb820d293e8bb74e1ef1ae7ffdb21a9dd8ef1a6e3f391e6f02ee0b51fae2a06 -9151e2dcc0b928573421ffbe43b1761b6ccefa4ecd58be7fbc8ea8e975e18d52c264f682104480d590e6f8c0b8b9f63d -85ac8cb79fb8916f7eb5431b7e81606b38afba15895909873f85d9577c87ed2c1d0fd489fe058362f20ac05626681346 -a076dd75ed807bb7afcae8bb9821ed46758c1a8d00e7f3d3c91a18e6b95dff3958ed70441a1f4691ac3268d95e243614 -89d8dbe170b9804de3fff5b6512d04643ea0041c3f9bedd7432b171ced1577b0c0a7bb911852c6bafe154ba36cd30320 -809a63ba788e618a281804ef97a75df39c7115900078a6bdb203bd79d3df87e863c631e934dcee62e28a16cb8735acfd -9727e6720f8b73b6ccad519d8ca1d4f90c2db33ab536f399e2c4ce269be15d99e22504ef153aa26c40d4cfbc450f25f6 -83e77918ba6e28ee01ba6b8dbdd84c53faf65446a90bcef46f262f341dace2e237b1ff8f8d566fdfefc6973deafde716 -b5a4d3fff76905bbb229d579b8433e76f2f070108230f20a30e4f974f12f29ed017aa66e9b298a4de0fd535a0e1a44dd -876d3a0bb439e7da26539b98abd0f7e0b7e8035eafed08df623a77fdac30ac85ab4d58984396319a88e072dd7a5149a9 -98923e83be5b2877ac18415f9391ea792933db718b29b6970001682cc8434ae9fc640427c0a27f6d62af5f78f3901bcc -805c675a34443a14c0098613d11b4c015264e038a8d1adf083844f2e3e3f2414689788423dd0ff77c02130331d511068 -8d8cd51d4146bfa48492e9d3f3e4b845d4ad1442ce6bbd95979f9778ffeb108c641c9ffc2ebbba532f922237e5849222 -839862454707a99eef931335e5c5ed80805ba06bab0337c5301fe9fb92fd59c9ff6620e66de7369352b079dc52bf2113 -b3cf3bd867f60b345a0b91314b34ce1c02e64dfbaabd70782614208d32fcb5d4448102bd54728fb05d1ed18a750e88e1 -8207a421d010e1c5854b8e41460c6a13035ee77f7add0df83c5c31bb00d7acdbb676478a7dfc738b9aef5c29d345ab63 -ad2b14f87281ad6e1d2b713e6e8303f1a45cefe097820d6a1bdf4652364e70d28ca92193e2bc3d0a1e69da5a51c90ff2 -98025be2d7e59ffd3f6c3c2b28b27ec42206968c0f96d09330598fe17a207baa6574aa22cc26555139766cc284224fe7 -8e80fe898b7fee849f7dc8e5eac668c76f1fe18d159c51eaf4ddd8d4d600c852dbf6c2abcb878c64f37db7fba3d56968 -871c0e2dd929ba4e157ed606741a6301aef759e10a3f919166faab23e599d3409b232240e3afe9c0e1622a11cd453c1a -919f7e465b399e2819ec17aacc199421d267ff2979ea8dc8962542ddbae51e2bbdf6cac92f8a35e05e4d95a4a8315cd4 -a6e6667e6127ee4f0224a9a94be3c22831a1ab3b16f57462562b11473c425e7112b33bbbb6af860c81bd6e84bdbd3b86 -87eaa9e3515f2d94acf113d77dc085609d06cb038f5e8e90ed29bd04bd4814e95ed0d6db5a1d65572dfaf73ab2e50ba9 -90b30c66ebc16f767f3f0bc1d8bb17ca1951a616292297ca8dd06d54cc53e5fb5fd6321ce158c04cb4c91a04c01f7fbb -b5fda3715566188630f96207c4253315a9cd166ef96651afa0ae1d6f0aa8856e7642e2f8ef3b1fb1eb2c14a7331f6592 -a54143f662a6946da901ddaa9e514a0e96bd6397020cf5d88084a1e1edc092b94facc150b1c029a508fb3995acee50b7 -8dfdb813296bd105d5813657c98337a24c8bea19bf0d119efca052c018ff5c88f31e05e110fa12f306ae4b0a8498f113 -8b7429599915ffec755060d9cfc2c445df9184ba6bf298bfff5b54c2ec8747a9b65bdc6c73746a94a54b0a62d93b6a28 -8a1d1108174d383465a57ab4b1a6811ab86dc007de4f342d37f4cd311650382e0352d3664ef09cf1626c0b74e2f21ace -98cb860aee0b7251da2d114b2253daf977badf82027a018c956fd59c6c93b716bfe69a132a4778ee4b7168fbfe390ad2 -94d5a0d33a0aa590fe76c71e80b21246dd9bd8c2f5ecc647e47a423c2dddd743010484cf2fa363ea73bb217247429066 -a082b7a109fad08e2c01dd7322625c18f47497b32269ae4e529b1681aeeb3c4a813cc6088ebb4427b486320fbc4b7872 -86c23e2d3b23244c7763c123ad67a41a2dad8e4556cac23696906d1acf5f4cd7f661281b8ab2027d268405b08eee6771 -801522a5c211e49eb96294a9113022d86c84bb8741e44fa7328122836a39ba7e11e27d0d6773550b234531400ba1e7eb -9683d154b18ed641867fe67b2dc70e8b8afba79f73fdeafdf9015d85aa0c74d270b290952683c3667c0202a83626687e -994febc16f8d216a20774955523262966e955cf964950b4b2831a3483f818c20ee6f51cd24f499dda0d3191910a9fd35 -aaa8f12184525e89ce980468fd24e1a9af846246297546655763ecabf0b5b5047394543f1791ba1c70e21637cd815877 -9193a37d5692ff1bacb0265bd7825c479624d2adf33a419b0a71c8a744ca1b0c9828127831302ffea4fcceb1a53ccd54 -b9f3213d5d588ad73b86365cbcf0fabcec5c30cddad418281ff2408dc140e3f6a25afcb6bb569605191665706c675e35 -96aa280b2f0ae5c3ac51edaea4435ecff8ecf8f2536a3400d8c4c9b12c64d16418838dd7ffc1b815656109ca63261050 -8486373d67804e9832bddca04a0084d1976d324d85c22a52ce2bcf7518f014ad00e4795e61c71e0dcad1f23316288dcc -b4f2e7f7e2ed7917e7c5036681e1ceff18b688c1abbd203c2bda0731ab56701a847cef4f753f68119110680913c2dd4c -87dc2336d88edd81b94ef78e7bcb6d3876257c326d28b3f4484465d6c65faa6c17aa7a2f85c6b94ddece39f6736751aa -b4b3502ebe175820f53da8e3fa28160579c4150d79d932923739aab545af537b3301d5b21f5138ab4100e737fb61a084 -88063af42d5845267d979df07be0735cbb42d9b57d3625eb5d0aa7e4ee90ca88fa52aed480a4d60eaf0ab8dbc4f444fe -85cb81247c09e21de6deec42e668b72f513c7b105f60ed478b08b85fdc8a886a97bb7e39eca0cab09b294e4b1490b0c1 -9920fcfcf836faafd211fa1ca78302aa6feffcda98aadb6302300c250fe8621b60d9c214ea92087c44996ae0999eae78 -a1f91af5b378d61ea277e5dac81cb71d71a4ac35322aaf42b3a8aab1641fd51d8da1783bae0e8ccb66d73db8e1003478 -87507b427d381ce3906e372a12f4e61514ad7a102334826266df14542adcbc8bb7c8450a1fe110069d9dc2e9bf0687c7 -b7581b0cb549d71201583e0987e9e9bc6cd36585c96664f836e1b7326e5375ce8d0a450343fe0b106dcc581b77de88f9 -b26504a6a7a64c44d7f97d0402bf752740934ea4c6e101ec131666deaf574d55fd7f96c8807473722b6629dbda2ca3b5 -b90accb5c6b78322ef88d017fee2ae1cf87194f4b3f6f4ba6510c0adf4c11b20870043cdaf45372844f5e801464bb682 -a904dfa6e1f813b4aa0b242f3eaaf893da7ea854efe514487a237a01fe244721482476b81ed75ef1a951fc54802b29a1 -a00373aa8d98f4dedf9cec4d227b5fab00f3af2a7bb4c8b0dcedecb5a04244321d5f25a81d57ed0ddcf293c701d290f5 -91bedcb316698e73f43e9dbe0229772c856f34901fa4c1e018e96eb898e4ae02b19d900e87d01501099163be56db57ae -b84dd6b9a61cfc0817da422380b0dcc5221deb600b4b6a6f6c5ad934110a3b66c59f7407ad68bf8642b2bcb5427e8050 -8507c172e499856675ba69fc1b0389a08e58f8e5658c9268172b926dabb4a67b7c836a44d865f736e8fcb14aa2809529 -86609a1d82d90a971786da9ad342035ae4865136e513559069b6dc8ba82ec0bd1ac695fe8afa5f61f85c2310194014ed -94914f127a645594ed372855550ec0817663224208c127a08bff3d5c4f463b7939cf13a45dee68586b678ae453c6d60d -80b55565972213814afd6ad9b1884a4d8143ae90c148ba730ca77b0937c2faabb23a6f985dd0bbbe05705fada4cb1a00 -930f5fe58dabae91c26c6fcbb61c3e336678dcc35d028e5c958d2ee7d50b80e1693c0693b82d719dfd9fbe2c03b52c10 -a45053c493da932896d95d5fb158869c1051e1bf99658b183c9cf4415fc8d4fa1b6a8752b8bb26e8b706a03a57fc05d2 -af7434b48d2ebe639c8082be09060422f662317bdc136d534b76ee3e3aba5ea8f234cd4936aa2b928f6eafdbe5165a6b -a57a073bbbb3020a92497f0ce854666997a182f2b437e7b06c9888db8acb2fd2128e3959f45c391f0548a3de49e37e76 -a0ea8131b2d8cfb799e806d8cb92cb02d32de37869cf2ac3c82f7c5d9a963d562755b16d25c4b60f4ca214e323790a9c -82f920aed42eb630281919b9c1fa4acc02b05ef34020cad3583a29375bdaee167a47ca3366ef065cd8e658301942dbfd -8415ef32a93820618abb91329224bc46d478ee8749ef42e372ae4ea29b6c05a65d5ef515ffc7d720b2f41ccbc040f176 -a0fbbb0113daceaa05478163fa835b070be5898dd9bbfa9abc582409a7b671c0e41a5070de4cb6dd2072888b11825acf -adfc99221d7f044b57ed40f4ef8a9e47e57265ef8eac654043cf5e777950af6fbdc2c2d5a5b916048fab1c19acd69dbb -b3d8e85fccf623fb3848e4886d580469bd41ec0533975298bfbedc7a1a9b4e554714991ec4238d8ff976a83cab6383b7 -8b09702f3789ae1f7799ce58a0ffc2327b3ebf2b56cd870f2be66c0d6781cc1f34c2d721d0de63e0fe9db85bee842fbe -a935864851b73676cb49f509a198caab467e5dfe4358e7088d2a76e9b8c13e5d20b01eb7c0cb9e51ee98c90cfc393c71 -b5035d76a5a8251bcb18f33968b077d43403c69492b809eaa3e202eef174a5649aee30f701ef0be050ba5026957093ab -b1cedb563cfb09713009b2263975a56abb9932b8cdebf10f7836c5c34785149e9875ff590fe1414ad2d21da977b7ba26 -98a718c23d44b24ac295b328d91ab7a40b23ffbccaa90bc5888efbd32b6a95c530bf5e999ccbd4f1c85263104f336ce9 -8d9d2ee952d5b135eac2f06f0478faaac175f23cb3789144f3a490f2ed34c885ae4d8ad7ed48db85cc6c2bd70b38c6c2 -8155763582ff6c68d7071ba842b6543361cd5f65b7c70d5bb838da2dab2c02f3363e2324307e7d2149b12700d96bde38 -b18b277334ef7f24706b7d48fb764a487bc4e21fcbfb01627b7524e9a5d3253be99d84c417084fea769b550b3ecb4574 -b80db9d83cb1ae861a3f61197a1f14b6c5004a2b3d031fb207adda94d725f3e265535ed7b69b9c801f2e95e1d64c1901 -82cb673ac9c0c124fc546c59505fe4fdbc05a1fece0fa579f6a6df96f74bfa877ad82b6fa768cb678ff04ae4cec58d1e -b2e190b785a4a882939489b86d0a06cb637b7be8b14204645bdd9d6c37626e8623e35e1e4eab5c8fdec0f8349ede8918 -a82237c64f15d306365be19085e1c725cd148702fb66658c7974b02051b685715fb9e35fd4a596ec24d532df4711f82d -ad6f7e3992518ba04b510b705fa6b28e3733e0000a5480e8a3c30fe71394de2bfa43333c69e750bdc3e7092b9e0f7ffe -8c0ee358f37c28f3b80cb9ad5487c342fab734886e31e30c667e616f3aba737a3a07bac4da552d8405ad8b00c03e09f0 -b7851e0b88486b0a858a218f4307e0c0c8c314fc69e2b90cce8ba86d3fdb796b572e50eb4e82f83f73c7f048484b45ac -a7c35abc2e15723a9f395d16d2484b798d098be5414ddef083c8283b0c29823226fbc4727d9cccf96e33b27fc40e032a -8ec5ff2ba7c3ca8a2d18df81d46e93a3bc94ceca88134ea75cc8ec2ec4b1ba3d0de49dcd4d385083c648a63483377fdd -80ca7ee722c3253e7b534b42a8947e38741c542dee1d671b603a9a743f5ba2fa95f193ace46c01000ed20ea05ad0639b -ac14edc2d803b28a169154364dac5360cf0926d911a615077a94858fb4cbbe31bae2f30a6a68b248cd8bed015e0f3b29 -a4bdb63e91fa72995316d03cd117347cbefd14eb1b19a0adea1c9d39f49d82ca1ceeb2a4184187e1dade109d10b83090 -ac8f528e9e8fafde00e66a75d4bb68c99029456ae9b3b7cc76ea4816e89aca2b8b7d094db214bad1e87dd4e84d1c1a5e -8a8d090a01aff14383419735840fc5286e71a5feefb98c563b2d7ee593b518c3aef6654f10da8a77f40feb52e1d31fac -ac4259562982b355fe5e57e1cef574a6a40a7144598c13a6bf07cdd8000bfda95b0b0b44f215e9dbc71be114a1857441 -b53741dc30b11fdc6c9778555c1f714fde60890c191a0effe419fe2b6100228d07cd0738d0dd73057cfc7e340c75f0c4 -80ff52fdfae53dd2410ea556ea6504696439919687d2dcce1e952d9d17b6e3699816ee623b0153bb0e0588e36b6f56b1 -a92b34d785a71d10e6796ad07df788c6878717cef4f1f0623898370725006d46fa00a0a22a3934fc5cf323be85fc7767 -ac1cc08cd1a8fd6c946bbe14662b18e89725933a79965c663b73ae3cf5f5ab87e794559ed579564884e430e108385e18 -88b8b2264d84106d38c321c3a4927b9b41cac172ae27f6292ea44cd9ce11d185d0061a59148e50474d4dad3c9e940476 -b7ac9f257b4f676d69899a181b45f40358dcaa70fa2dad38870d52838aad9001f3a3145f6550fa2826018952431e4cd4 -ade67b3d1602ab0af6a256f25a65b621dded7a0adca65c526ab34c5ca3088a549b7ccf76c586993cef0d2d38af541617 -8fcd8bdc44ab42a70c174682a1e8b929004834d4962a902de460eaf8649883c868cde1cd660d14d7d3ce589fe3aa83ab -b914f6ec60f1767a12fa34a4b400ce102564dac4c1c42f1497c7bb824bfb9000c9e23ed7cadaa16ad79d5ac906070710 -abb1683b313612b583e87228384eddc3e2e7539e0aa26e825f5c27da222941b6a37ec47127cb0f11b6b8e0d02a6f66e9 -b01efb31962345a2fc71b7c370e7d3117bb1d1e1a9b6984ce11bd83c898dc127fec2e821669deca7c74d406e4678a736 -92439394c6c811d908b05c626f1afeda3a0f8c925747bedf66a4a5895ee76e7445a1982e99d8658117128df5866eb64e -956bfdcb00837be56d44f159bab9bcc2292295ec1ca7424615e3b163b5d14f7143e214609c0b65ab74a0dbddbed4d782 -880b9a8dc9bf6499f1f71828e6c906e2ae59660c9aaa824a6f36116746406351b4e364b6fa26c45e9d90018555bc7dd4 -83f4a0dcf523d414e023075ce0dde10161d65c0abdba522c811f0e446980cbc21eb0bb42737136bce30fcaae3c673b6a -abfc5593e02dff15161c4da67a806af3170bb2bbc65e3a0457b4bd994ecf5e001d02bdd417655c2b4433dec270a6273c -99c6d8bab7d937a4cb5c272c4bc3856a3cb8295cd77ec9e2fcc6a50e0545999cac4c413c3ca8e5408afdb60388c82ae9 -b08f5d230713639ec98a7afcb2a25b9b2d1c48820447d28b6a3ef448aedc4b9a90b6c5ffc6613a70ff1766b51992074f -99d4b54e35dd3f844088155f114ef93507372ed32a6898b9954d5a6d0743e55d8e7de20d67671454d26561ed5e4fb05c -b7cad70deba1622c79f1ecfdb2612e380e9048fb6146760ba61cb62e98cef129d3944c5f442b15fc11c102fcc6e2adb4 -95feea870c86525ed214e3e0ecca9f66c5e0babf6da8473e5cc5e2f305c26939f6afda0207bf5855b6a6c928815577ea -ad6e77ec226053ab331f3f871d7fb770ae78227a85096d263bb42915299147a7a7b57a4f8f929765cfb323267b94865d -82339f53ab7344f8dad554fd0270c2aedb34f7b0c630f0a56ca9217c04f0e4a38781eec769354a44fa90f556b388ad01 -837d4672d73588f19b872d81b7993e5e0628139f5685d0520b1b766d40e71b9d83a8d2bd65a03987eef89b3d5c254683 -b3c27e19f579133f1ded8c066dbc3e4edaf449a1edcb1aaf215939d63a7f2b250b9b7afb62d4cd7cf37c28da81898a67 -91f669f9db8fbc6d7a5ee92cb67c2fc1ccef6dde622efa455dd7535b11f506f4e309a8878b859d6605a3917f6d7d67e8 -8332dc636222829a83501a8312904096c2984cc0c5dc077e067d8962bd87666226e3324a9e5057c1cbc3ba700a3b22f3 -97e81e20bf33baa4412d6b81c5fbd406dccbe70973bd73e956d8ce85c99d2199daee5fa6e99fc6d40071b352b5044865 -b716066fb9e470cca4546a401048c0e6c6408c8c9f4cd80aca6778d3f4121378e11cccf8a005845fcc8dea2e1b9f16df -a7b340eb603da43f2aa542dfad1ef3d3357f583c46040f2dab234c8246d7c55d6885f9f7a14f319e22355ad498c22a04 -8281ea97a28ade9a0cdc73a077c72a92810b70912006611a00df8e7d2ee1036af73c0f062b367f3d4d75be4b9bf78aa4 -a481ffa0813a4f2110c6ac535fb446282dce73c182eb99baf786ad42b804ef12df078b2f534e3cd8210973880bba6a63 -b71a581ae08eda0437f9e9274c1f9431d6b357e4866e40d4c2470252f0888978497af823dbf464785479e5f35eb89aa8 -a07c9010308bcfb0c97a1059d5213980000841ca0565697d45aa46e82fb36494e4940aa435ede417856d24f73d374757 -8fc353fa8733947ba067ca2bf5e14a6c334e4ff30efdfa67829dc86f49424f4548e879b153e79dc75f1ec00afd6693c6 -a663faca50e1fe5d00f62abb0b7828d6b761fde9f5a54f27c0b726d8d53281f83ac165b3d3db87f970913350a7dd07f2 -970535269744905640d6ab238930dff375ea7efb2f391db324724166f0c436e7a3eab7ef6eb2e5d6724c58d588a4c592 -800f33f5936498e16fd0f58210a5a5c104074039db7d9d5d92dc62cc00d796ea0a3a22e5d368fe269cedcf30bf6149fd -b4b921cc901a7775df7ae73e97cdd108d98c54534015a1469f0ca6b07989827e0d3f9bea2ec015fabe9d309054aef802 -93295c8a7e5c0bd9decd99ee2d704d814cb6bd0061404fe00984a8afc337e78af11965a8560288529c2a722e8b54b488 -af43d382ff7951bea94f4540a3a2dbb53ed527e966d0dcd117d5212f36112976e1fa00a47bb9870d3841cb01621c5d7e -b4d106b21e4676556bedc6e7f5a7eb5c2ad0d5fe8004a1d968bc7806ba871e241d38892b1fa73e9648b23158802ab57b -a96cbe38f86165288a365efa796b0e2076ae9fa94bb6377cb80c7d5db9d376e9c18164a8a3667dddb3f5b847f52fd319 -a0bde83e1f3e925561c481ceb58c7575027f9641e69f14242b886e7fbc532a2bc54aeeb94ca39bd7da3ac984bfe8cced -8211c4a70d08fe052246d3ccda60c9e9677910a93d9262d572606d99e273c1ade353eeeadf5b1e3c1ac3c4b9019d5f61 -954ba6744e3f991580b6633e5d184550e44400f20f00149d899d97bc4b51b01d09bb4f82ad975cd55189320523fd60f6 -b7e3f17ae79c2faaf5f3cbe0dc528c6aab0035eb3f38954820556bdf7c3546585fb9814717302c5f45fde7170748ff63 -880446589f33ffe7ff5e105fa1c380d401d6c46e80526948fbf4edcb779753a594f3891461f52eeb3f5f2f6051c361b2 -a26c06cf79c412d49f39e0e27e37c82c4cf0c8648638ee66a97d22d822e064a9a7cbb0b1ede46806ea0430639769cb88 -a968341c5e4a3e6d2a2116222e3c58c2e558f5bb0a2877a27c69fdbd38dc3892f9ed7d7c114f557e52a351c73614fedb -ae9b8bf4774ce3b84185be77723ec62b9a415e21cd60e86513c1500916c96d62519ee8cc061d81ac9db9709d6e191649 -83a30c1ebc046c9a1ba911ecf6f147644f58f54e32357dc395388e6bab66d71fb9b691754b11bf414d43816af8058828 -ab5b804fcfb68b6439f311d0420005b083a84da15a8415cc4013898806e67c47698a9d594263fd9be42bf48efdfbe2fd -a41c18185f8111ddd551ecc8f6dcb87036cebb6eabbce7faba40c6c5c8af2ab59ef027c6fb2dc523eb0159335a1ab189 -b24cd94b7c6e161e651107769d863fe5a3d7a847b9c60c7c803846bd782cec0bd54e6278a318ed23b90cd7ad25933fa2 -a5ba23ead78d1678414d4e986b448e7a24b23a5c0f529ba604a51e4ee0f87baee450fd121b43a954be50bff6c0d7908a -b89c17de4809e722527832b90b810d9691b437f19db9cb88ca5cdb67bbc6946ec1d454dc0990b66093ebeb6eeb6896a6 -914f436fe0ac7540129c3deb04d51bc61192ab5d0d16eda77ef70ecf8cab5f55a13492f54e8052f2f214186a113d8949 -8e0b3d1dd756a9008894028d0443083c21e99de69b8d8f4e7eb3ca7fc52ad540355d4a1081774a6d51a093110f4bc838 -a9c1730eb5c0a42deda9d9b39390661717479e29007f5f8499d0645b8b85bc0ff12cea2ac4328f6588a12126f56284ee -a2318a42c99f7613ac78cb110656c6e470cac6903a5bfdc1bb182af21e0f0f409bd39324a13e2790f0facba04459d3c0 -a11ba34521434cb718f1b2015bbf451ba1a7c60e59b1620ea843835c7e75bb42b6ad29263cd3705f7f6f1e40a0ebdfe7 -90705112b625973e1cb35e30f9e15e3c752b2e972231b4caf53518f44b4a40b8a6bd15c4af2adbce5dc194169b860cba -828035b0e70af8db1294379b4b70e56624e1138ef49f7be81d938e8b25aa5dcc03655e045a95a79e0143c23a77407004 -a7abb1836282917d1eb9886c79b6a36d720612e3b823d9420a4a705e8add6c6bfff2f682e6f992a6af10ae2f71ca8828 -81e97c7f980dbbe93df9efdd9c0a8172ba0f00378e9375c926b9e24758e8b827037ba67e06e994fa9d05942320353d71 -afa640b2a7fb997cffc5db74a91dece901be4a36415786190dfd17a77ac837a2fb2d73e973b8e60582e71824c57104cc -ae860a6850068f2b0e1e5a03afbd08b667f44c4f06e431f1f83269e754f37e18a764b00e100dcdbd1c1d18af9d6304a5 -9443fd7e1263d5ab9baa8b1a3c893765da1dbed0bdf62ac9c886425ea9f05876df1920889b707a2cf248e7a029883588 -acb38feff88de8db3477ea9ae3b33e0c5715cfc91cc71926dce26f4f290dc4f437461a186cf1bdcfcd6d121e087bba33 -942882666a9f49ac24d9099facbf1e65484ee76cfdd2eacef25e0f30260654a7b5c0cb7dc37aa1601980877f945c51dc -ab2c9035b2ee9c5e57d8de70b24329cfbd247324309eb30ac78c404ced268dbe2aaea8d417300c90d87924a48702b793 -80aedcea9c5a9911731ebb444500eb95b519e2d4650c1d465afc61f4997879d60750ae3fe049e54654a06eaa2db7d8c2 -a63e1ba5fac918c8bc0f4364b5fc8d26214deee825aa1bff111e03c0ed43baad47e8bae154ad580b851a0f66be85c88e -aea7f5f8c387c21cf671246803cd5baac61cd6359848ad4fd685b1350ed6298a129ed74dace279fe7846001bd6577dfb -906ad36bbec72813b368bd2b79c1c9624966dcbe94ca9dbacc297d0d8af86edbd80cd702ed04f0adebb913a6a7bc1a62 -a46201c20560ef2ded1ed3047fc196bfaef445c4a716890d9235f3a06d6993a8ab29e816eba54c6a2e2590dc8dd61216 -b37eb2c0d765b044ed2fa2923160a19e11509e764025e43a62b4ccbe38e534ab59e68c2cc92cc5aff9d97154b8210c50 -91f93b1404a4bfd3fc8ea019d76230637ceee315da0faf366c712c3ba19088cd3efa2dd30172dcdac11e636f8473a26d -b6b905abc4a795bf95d055ea09c3f9d0a8a9ba0014e288492a3751d2aef60cd3b7846e1ca8366635a94988b2e197191f -847529bf842d7623150a3bb91fc4ccbdc66010bf008179a32359f98bd007330bbfabfdc487f4b98691ad65680af67a8e -b3d37a8098d02b5ee69ed060527f3d924c727016fd92b21d6a52fb1c1ca18c7eaf0caf8144e9e6bb5b6a039ca85cb1e8 -98cef893dbcec865cceae01138613de146d563f13853ae34bed5f142da716673c105ecbf4f2aa7d187bdee20702d8582 -97f60078d18928c4d7dee1ab244b2b7540928e20cf7ccbbf6684148611afdd9cce60dbf412c1fc544ab8c356fda8fe11 -872a6758004e6c87c3788c5c11bcc74db78f076efaeb75127f0baec28febd02528c65b227b7619fb8c29cc92d7c8e799 -8d72cf1191629440d7af8daf3b76b6b1bcdaa8d6ddcde52603dc8b092c2ac78d6e24bec32e1223eeda15dd17ba2c26d5 -89dcc8c10be08277a1e394de336bb1b135bcc5131dee5eece80973ef364a305235936a3b6dc40f2eeec2aaf227a86376 -972c4ee3b4b3b028ab683415bdfecb2454d326a19d274f499e48bb2cfd55165b928bdfa7f97c4fb6d27082cb88b73dd5 -ab5438a8af3acf2eb75bea0ae71d8aeae363d6644c54e3b020082c80809ef86faf5811808adc8240c7693515ed8bf199 -b594133dc9f71f72e448796316ff3ce2f8a03c21ef9c54e551d23723d5f197f7fb0bf1c33e9cb3f51188db7dca51bf49 -aee981b45d570a666d0d0b2c7aeaca3cc22d4873812b4424d1f91144142393fd64c49401dfb970c7d5ae91233676cacd -8f978d21de1e264178f88cad7213463a5efd139c30dfce81a7eecb46942870a3c1971f6e6e6a50e0a8b20c379ac084e6 -9153701c8b82ab43fa4635cf677789c9c9911efcf23250bd393301c0be51f14fd0acc4e467ec9682acc89085b94641d7 -8681989a1be217d77cc8e012c95128557de70b362442e7f1e6162bd52ec6e4ebb0ab28f9ad3f67c1d35ff00216ceeb74 -8e85421256fc71a82d35de9645a6da9cbe4dabb9670758c4eafbcf42b26fb99866bb2b4c374601749738ad34e51dba6a -976774296281bbe1e8dabaee7453613d0a615cc6abaeffd8e15ca4484b5a743e298522b2dfbdcaa697e1eea2b2bff736 -a585501faf955b6acfb328d801cfec5b59be8ff2fe46ef0bd73b86ba4c19c1dbfcc1df844d61a5acc64bb5e8a68f6cc5 -a776217e5073714b36bd2ff0621246a48799eb5ae3ca438d1efff6f9f9beb13779bc18ae5ddb77c838732e8925018118 -992d726bd4889f4e7565bcdc31c7b4a58ba44da5f361e3b46e0a67a6e4f00c25e3503c94e7b2bece737d7efd47ff9beb -b277f124d5dd8dd669ef1f6840276c0bb0b60379ca3a0aaf00ca337c40f478d511b1a73e73df6c3b600e6bfaf37a8fa9 -b037e78617c235e6528e535bf13bf5e82c70588d1d0bd08de754d089bd47a4fdcfee79b5666b95698cd98c0e32164afb -aefef9e398e0edb60615713d7c1334005b21844d3f1401903e09af2db20d7b342b8d80796fccab583c8607c533c9b735 -aad20eec7cf4f0b518007ec1df7dbf4935f6f9ecb36a11d148dbf9e5281aab43feebcc8ce9001374be40776c5ffde825 -a4ebd6018e004ac8b5d022cfbb7c5b3833456faff4f198a3d9dbbd077c8752087bda1ea060466fde4a5f31cb8a50a7b0 -a56ebb8ac9901915400234c1c6c8502905765a7224de56b084f9b0a3468a065e78b4daea27d9887b4f44a72fa61a15fa -b0269890863c63203dd4da3a08a1bf06621cca212acb49799bfc48be7e41c951d807f85dd4171ed57c372914dbd2ffee -ae11fc0f5fd5ba488104bfc07fed50799f51ceab4768afdab300325e9a913b1f257fea067d357e54950c8d08af5ecf59 -aefce65396c61e835ffa38857df426f64508de6e93f966cc46b54dcbc5e2bfd72df927b00489fc4460414569ce99e610 -a5a1fed75677dc956c000b9135c4b6138e0cff53770399ffbc3b12ff0c1677ace264aef2058aea535ee1a7195afb034d -8071def0890d01f0d10dab3afb13125f0194e79608b9ff129572b5daffb49cde5bf6d9f24da3f84483612aaac3cb8eb1 -b5e5bb8c0be22349ea51e249cf2159189fb9aee615dd62c5f67cc9f43745676e703abfa6561df4f5f1d79b86c459b11c -978dfc57cf0d3538ef336a25ca7a2cf373f84b71bc06d1c74907464e3e816d834087ee126bbbbd5090a09ed063f87a46 -a2ff4b59b3e7fef169835e67d47218eff5368aed3e6e2f1cacd29a5efe6c1c2e7e1839d87759bad8ad1871b39c481bf3 -96de49b44bcd2f5ac3d07d6f5270af081776d8631fefbaf9fec6771e13d40a4e5158767067297029bd38e8c6847971b6 -8f2f820e8e3645f2ab9a27b3c23b5f656b681264d08e298ec546c5aaf51119893e0dc8e04d6f64fef48d3cece89692f0 -8de2eeac7dd4b53119d02f0ec99f127cbd8f6a57120d94a9a554c04467fa74ecbdfebbb111d9f15cdc1be2be8c2396db -b6616f68b00ea0fb78a25ecd51d3018b9ef13664a7da42663d1bfd6fe71fab615624af863f3b41e625b36a607bb42dc4 -abab5be2ab033afd6d110a340c658fb512bb53368886d8a5ea29e3c916a6b1bc46decb2cd0f508b5667f9dd88033ef7d -8872d0cb09df44c2a75895d46588316a4c9c743080f7a03a384bf4d4be80d341f8dcf0e208383bf3587a3509f3324fe5 -a3f57fda2e8c06fa7ce9de223f5ff56d53ce9fbc48486d88d2845e7011dc038b6f2f270dcfd46ef5222ae9a1557070f8 -a82c4e46f0d1962cb48d6c3d8ed3976c4fd4c174d119470479d9770619a45e6e16e30693b2804a82b516ccdd400508c5 -b53188c6b2907abcfe47fab98f23ac602525e05a5ac6b4421c437025819c80529e9d2d63f8a3c10cb9dced196e572506 -951934cad4c2772aa0ffdfc4f12a55f490824e104f669e4dffc70d9c14239570c87eb998dbb2a6d423bdfe1ab50f4377 -a276bddb27d86e1e70ebb96103a239ae4848ad20c4c5b7de85f480c3f293c934ebe35792361d9767de4333ac6de11643 -b9c8eccc03d7270779a87dd7c52a42c7bd632b9bdf94274b1dc864bc7a59e13eb30870ab740066040aff0beeefe14d2a -8e0908e4d15aaa582dc028e015c4b2bd97c82b8086737cdd1f2820641e65d88166d1fc763bc483f8fb4643339182473a -810c6c46945ad5b4f699c51130bf204e47c62066fbe54fd099c3567ca79aa8aa8b04dc5321c09e03df4bb7c9b93857ad -916d4b23adf202ccfaea7dd124d28573c73b39ebd74bf4dfe32a366f9dd48f4160b8cb0e687e7dca887c4b4f19570cb8 -b1b8fff52dbbd5b9bc6915ba20f3185fa8e23fe52c026a41cdedea5301dfcf6c79c4fe1058f3abf280a00c7b2cbb20a0 -95f9623510e12ddc6f4ae59d06448f496cc911c99a4d5f5c6ff7e434b807fcd4b35ec1ec976a40208ee1a505a892e38d -ac7217596d42d40380fddef22e83db9e6d6b2d0d2e912f868d7fc07bacfb83e8e6f01af544e8f450d31db014fb094c9a -b10855b8ff1a81ac32d81773ce8a6391169902290af0637038b58ab59fc84e3403d515ba7c99e26b7382c2e2d0edcedc -89eebe9789a333f5db0aa9e8604798b15a934ff45e19699c2e7fdb46b6863ce02defcef9f6dbd0cb799ffe2b669428c8 -b9cc540b405c5ec78a2d8fc17ee4a08690e347cc1d860885205bc19cba09e62f25b94ffc2cab1f638c87caf217f7b6e3 -b16d06b120906f085cb183a96a2b635334afda4272ac650259f23059407fdcc8b83e91f2521223f79769ba45428c04bb -83e0a2d9d9f6654d916a822ab1725d58a10efd64e889a17f44860db4d2c77ec1bdde7d0ec8deabc12f8ffa5af879d4e5 -98cef31d7ee167d9c4248e29402ea8d5546288d1b7ca54a5370e80a9ce371bc4aa3f5c7a24c2e4805d8c99af059b4156 -8fd55a0dc38b65c2b0b45c9127c14b9396db4898f14e1559e428a2951cb5076bff9e3f202a83236f15c1d2530539e5ad -b3252594c3060118acb12eb91d002a74c068c0b8f9bd735a9ecb082f787c7e046dd6e40ddf4b3ba56bf89f223bb5d76b -a88446262600f605fc4f067dca855ebc56990a9ea050c708961e486fe685707d9e9ca734068b92778a144c0f3c23b4bf -97beed96ba821515996045a40f17ad46f8f4d927cd9a2c7ce134a60d19ec4a5819a19aab1bb0df886d9cafcff872bcea -98ce98dc7908161ceefa0ac132b63c860ec2e53f7ba28e66c6c5e45c5945e459797c65668e58c0a5b8a26811f17c3f41 -b0419cef96d4d44fff0338132d53d2c03e7e9b4618dc2c6b9f4475368e21700fc08b844a2f140158fff81f56aef83b7e -ae1eba4a4a715f6d077e90e9efb59852b7025adced47fd9f705c2745e6734f2fd2f2f86f07ce24695a06e24e63f00b03 -86db2fd15dd3cef1e504fb057136f0405758f6fcadc391e6f64b3080f92bfbd4537a0d8f59cd1a0e913b2b188093feb6 -b418cff26800f8793b083a879c8b1823285f7a3cac6fa34cf48ac5355f04f6ba74255eaf436739c4d26d0d80d2607129 -8eda3c25b5699569c03b85bc585acf25bc3f9539e9dc3e8707b34520ae5ac53920f45528f0870d93f84647cae36b6aeb -a2622af11642fb6cd60cddcd4c242cf13045f4ce20539d11727e8942b4f9a7fd1ea2192e83596a35c096fec3658c0c2a -80735f92d09dc0af19f593ea118bf52146143c1d2a7343f6e2ab95e00debfbd329d4e887f7421e4a361d815dc1a27973 -a7eff30a31db635e239c8632f7f84263c9a9d82511422f49077823aeb124e6ee3c995ceb846902fcd2cff0f5f219db51 -99129aedaac32b3ec18d689a2589e35fc9715fb3f1a72d28a09ad95e39a68ea939ec5721c501a9e35c60cecb3f4379df -b9995d65636ce1e70967a8ffdf45e50eb264eb64f15ee887781455c5472459cbb309ab58b1645bd6e8f2bd29e69d81b0 -b8049f4c3ddc22405880bf55b5d5d94a6dbb071485f25a49a6457db0446663f8d4fabcf14106b9cabb1b3222d8786773 -b581027c7d9bf7b97f6eb085934b9caa43a46368cc6740139e33e4cb2c94683411710a52d5933a27c9d12a43e75163ae -b5dfce672e670158c259f36fa549aaacb0699da2f13702c81f5a93afb00361f9ca22d02dcebeaceaee6813a3c9bf7aa5 -b8184f3eb809be1986530dffd7464d84750df02196274955769a0afa02b65e87686d915ecdc7e75a0a76be8b7ad8d064 -b7ab837f300f4aa2ebd2d770f7a36dedaaa68e1d601eb36a28fada4dc73dbd55e7f31c88ab2835aeb57ff113a14c5f32 -a72013c811ca674c3e909064777df1484190fffb0643b6b1435892f5dd0f1d09579189fe00c862bcd18d03309b958b72 -87fb528e03f1b6a000141f4a6ee24a9738d9d2efa795cc262203fec10d76adcd0f89968a46fdebac99af8d048300b8ee -b2a1ca5d5d16c7addb73341ebed1f8e832250c2f8e03915a417064750d7deec3289e646c06a09c6a3ae40ea2817636a4 -a90cba4d0928da2a5d8c6935790e1a1f026073632a4c1460fe686d06c3f2933661c2b3c49bb0bbeef386f2bcc4d08485 -a5b684d544500be25136b0b5b95d9f363103a6d08cf49f4934d6c96d43720a79cdffe66698de0ffe5b02bb3c2e30286f -b246952dcdc38a500e64ccf4f312bc7c690d33a3a951fde5f839f6eec77ac78147f1fcf26ff7b990e8868f5cefe1c4eb -981ed33458e8ead67d4adeb884153bb0fee0ad98ebd9010ee706ea1da7975c290f82c492cf16fb42d1b739632e66e50e -88bdec223786c894fbd8f964ab2c92c5ad7fa7ed2b97a6bf31423a6ad5bbb5a946ae3cebccce8cc97af9e788d03f547b -ae852b074e5716e3190593e11fb17f1135d7a5d888986d2be53973fa14c1d4a9887381e648a10a4725291ff062c9d88b -b87050f914c4f09e2dfef845ace5a06504b6fdb815f685921710c7e82a9fac11f864e3e6023ed5807256d6269271d051 -8cbd11617ab819680cfa68e70e205f3ffecf6e469d88dbdb1d9b0c9c7c38746dd6e64bd526306a8ab59cb7e66841a757 -a1c51cbc1a91618b1ede5cdd77fce26b04971081e5cbf83be20c22b9b30cc9197b9bfd5998fd9ade9b665c8218afe94c -b5cdb2091d114847dc14a4c922bfe944021549df2d75cfc08ccacc2d740726e90e20a0bc2bb73303e9f0bbb5192fb982 -8e60327955c5de97f56838cdebd24c2ed4021d9e3d74ab9eefd4543a286c1be82a1e8455f8cfc0a17f03358c4648683b -87f9c1c0987493c631279112fbc79c5f5d7dbf46544119492785f444d063fcb0da4f2d1129735ab77663a9000d9e18ee -a970df3d50c4ef3d76d53dd2b887e9274fdedced7a83560eb1950fed2075879d9fe1d5af811f04ec92d557a0be0380f7 -95a69bf4092567f5b55a401329d5a08220ae65825f05d56043974fb7b7090372e941a85e2d197c46c9165031b3bd36fd -8e62c98171e54ff549ccac5d6d381291d0861439dd24e584d356a862d22942e0ff17cdc0d1faab07e496374a547ee812 -ab62d0eed8422a3172269de0e325eae9294914fa67f1ed8e5d0609afa2991a26b1e1b9a04ccda8436d04ec085957b110 -a3292bc88e2a9dec7b55ae4c27a3a8ea46a7b2dfe3a817675eb3712f95264c08668703771b65afcdf6d305e396d5f005 -afbaf9cc19adf63a0716cb868a970a372d7a1e24a4c78718a114ced412a12fda6fdf42f701ca1492a8f8c1ef0466f7a3 -b41a5f064f9d900d1534a68c74796927e4018e23f949d86eb76dd5b26e5b686115d63d858a49b545924b3941bcec2341 -b4e1ef520119f9a238fc4988ab2f1266606f53079744b92c1039541aee78b67ac570d7839fc9b2331244d734ad4637ed -b0ce754a33a506174d5feaff4e9a79295c743b2a122c8a1788c1427482585b398a750b7bd93cc53c38bd3e557caed172 -9842cd13ee9490d9ca7ddc83d1f7d79495afb7301d1f51f4b007dd2b2eaf15abbff18666126adc25df5ae26b98a80f41 -a976af142268d20a248c4b71304a878efec29b5022199cfc88bf82c081f55d06a89f178606d50bd3f8576f0c5c01a6ad -985ac6f315ab1d2db1b4f2b107eb1652810e63e36b8c14e8852f072d2c8b14922f20d1374a57d75cec62db0d050a0c7c -8c1be9e8317fdf847a8131ac14cedda922bbfbe15cf95537493c4e7eccc7f2f1a56ddd1a8832e6300734d6019d8b128b -b55d129c88d252556fe688f84982becce253736ef3b1fb88328e41300ed0713465c8bd15918386844c725fe7a94e8364 -a96384d2d81cf6a79614c7fd6bb68fec6e74064435a1a79dd8b1533e9c7e578da5ecf03e979969d983da893f42adcd84 -8c2b3c06b7249ef5ecedeb4f2c65c0925cda8877bb4b672afb7a15bb5a7b5818748d6b022c6ab8fe9c5a1499e2037c69 -91c8b2b8b204897741124a37f85ddc45c3ef94ceb5dff681b13771e712f2ba5ac95cb1bd2d3e94a84625d384b51b099b -8bf852945910e9a773120c5ad975f080c07c8fa37c2158e1138162a82983211da70f27e22876741d58c20a6c9dd770da -b9e907d9176a0fcba87a2797651765c814df756bbd1d0a86a9b7b06d9d886d1908d4e74ab27d618129dcde81e7d969d1 -ac4d3b156db2570c349e21f07fd17df935872f9687842035b533c6e4773ad5752f4ba8f9ea4501953f6b8c4232a4562d -ad91c4a7ea0a314d7d1ed7a69a74adf6ad810586c1bf907ae9878ee5f6528437c048c6ae785cc255707ea3e58a4b452b -8013b76604bda0c429e37006b01750999414100d0ff59ff5ab7b233399adaacb34906ee65054abb94db80fc92ac6d2e8 -b26a2a660af34a4b9b8910463d0dd439a3dc563494f5ec280dd5eec0b14b0e9426a0422f3c75370201299d394c4d90ad -8e1c7ea11dd513fb8527fa99b899444bf89a1188089d3bb65e3eb87025de9a48e8b4a3068a955fe752f2416de282ca20 -b6cbdbf2b143330db09841aa0e7d22d32772ee62006e7cee13d8c4ac911ff4a59a9dba3d84bc46ace1760353d847bbd3 -b8f5aa3ee213a44c41f63c11f685e754997cac37b27e91d07bcb69947344d94f3b86284b3b1655e168befc01c880d550 -89f93b37bda703494263b10768118ce998ac1f395d422c0ae840e47c6d649a3ec59b404c164a1ad5ed14ccc2408fc662 -97255607a1aaae89530a3bdbb7f2b7ba3fb9d5dc93509991021152dde08a638bb3152503cf0c896c9c19d61f8eea36d7 -909c7ecafb798e6aa45867976f59cdc9d219aca6fd0881f82f296a83a2a3cc5ed47f08794e6e3009f8847f16345f5f4b -9560fbc2c531571eee5b7389855117644f156ddb00b23a7c2189205d4cc613ec83952b96e941cc1e725c2b574c46ee9c -aaa69f68b6086bd369fd92355f3a0bc632c1b1b4284529c18a7cd4d71d827291bc997ce74bc92dcd6900419be68efb37 -af9ab7e6a27e61a99f37b89fc816974ff916b6a24ec3aa31d76579204bdd5ff01a2eea26e76188976c033db4af167db5 -b026dc8850af970d2ffd300dce6ae07db0ca2d21978e4f3a6797b6e3e81f1d9680465080a983c31d473a77ffb62acb5c -8f82f92ca992ac352ed1e8fe31d24f8090ce6a7f02d6086720422b9bab20f3e3c38a5f63c7fdb193e30d63f08e53c900 -8b896a2ae84c66109c8501cf6070c4da65c43ca8ef9b6b06fc85b6cd92bf2e5397d492796c528c7b2cf29ba93341a87b -961bf4c0b8068c8406a864595e156004d427138e06b390519cef53af8eb00c748bdfdd480521c6aa0d53a78e8f806217 -a6fa456250d20c6842dde55d3884eaecfe8a39f546cc5e4a77f57907192e849a956a33a81369b0f2633c55bd6608eb63 -b1d1d2f3e3e058ee97c9b6246cf073236438ed5e782bb21c68cd0d77b44f29745dc24d01edbce4437d93071b6fa6e0a4 -81a0bec80ecd1b1e72256ed5be7de8deb11046ead7a96e1d150573f4d896e642b4af095735343f6831bb6b7f4037cfca -b48d8e15fa8e0b46937637de3c727157f8073eb8a9a04bf127e68977758385a791da2e9c69fedb89b334fc638ece78d3 -afdee0774369653bf371b8820e285e1b48b40745a44d22cf2098b630b8ac95796a74f79337cb97fc60b6d6b903a61321 -8fcd9ff2991902149db29cd4674d60387d4f65397891fbf91b7699a42f579f6b0afdaccec70e5e82d1abd81de859183a -8af5c73367a8439b2e3e5f1b65e00ebef2eda640bfba2eae48582cdfb244e1b1cc540bc0ef72f9e24399affce1c3e222 -b58cad4da101363bb8d6e8cd0ec7c078f7719462856d7ea573e2bf95e00cc23020031901bd1f2112ffb90d847241e5a1 -a671f7fe2ad81e9e0d5e3260a9dd7808125dcebd970877b000bdaa3207ca45ae1e5458d5ab7bd69b2adfca8b6abd88d0 -a8411cde9eefe73fbceec3e5e3628b159ca4e4c19385ab50b8d7a482f4258f405c47051a89f11dbedb2b15e84d8bfcc9 -b5dd09d5ebb26e341b6df80e836c6de2305ce4941238e3e96da549857ec314b1658f8b03ef069633625b6e4bc13b531c -81bc9bc924039fcca8892b40aa9fe8f5d6f305343f6054e36647d5f14cad3e4d754dd6ce9ded67ae65825adb4e16df31 -935ec74c2dba94b1c5ef2060c31bb5c1426965f68d9f4125cdd891f20495da9d5dca513f65bf3e8c599f1562e81a0c1b -b9581e11f361097620130e753d134cce6d40ddc7c516388fe4c881fceadf738f314d241dc14d4f87be8ff0481e898c4b -b7be50ea49e09d10cbcf21b6f717e0cdca582d57935d72d17e62cdd7bf2071e5d5c91ad7bea79476537e515f0d2fa5af -ab467b7fd32a795411e991417be57af8b62ca199983efc1f744799136ae5339173111465e91083dbce60e77f9f2c0fc6 -b99afb338f747ae89e7cebf069612e22f9704f247d66548d305aacdfae395609a57d4d5405ff0f1eb1045dca4c3827ce -99a5e52374e1c55f65e44951f68cc3d607157e60d52cd088125a81bc60f2009d1b894eff8e1efb175509aa4b57af7276 -87e3323cf6f11b595ed745a9475a6d99d11333043d512bb61d5f9d8c3f0cb6957aa8c3f041688f63ac13a51df29fa061 -96a5f9ed28056138439eedba186b754f5f7693c09422f42ef82a315b7413b418c4971112f4261e1b9793ec9066c3641c -b9b5fd36d2d861d40b947c3c879a42fff24b9ee346163e544ce6c3301d0003cdb47218644fd5f1f7f0d6f19bf647ceed -a8899296b58e5d56d7da438ea48bd76310364ffe666d698c86f20683343663d742a0b3f8c1255e33f1d424cbf61bf1e6 -ac4be82ca78df2a367f13c8bd1cb73a28015853f2745e025626c325a10b778cf4bd9942439e35015cb38504bc02993c8 -ae5d6b99ef56cebd5e25a9c002e9e80c1d3e8e5fb5dcefc8ea7b7798c7e09b02147da2ba14e42e2b6db2b2a6a738f598 -8c94abefc71d245b0bf04f34085da0a9b8d4d798ee7441596c5166ac353425175dfcab0f76bdabab8f0ef5a2b453255d -960ab6939b1185806e9f985c9381206c7032ea8a7a99eae5a66f276ad5cf450e654a6f1e956a2a63f33d6f715064d051 -a4c7c7d0fce514db07bae5582f5e4f7a05d79f7605b33fe2a1ae980bc388b31c056438616bc8391ddc7dd5f98810c74e -ad5df00f96ee6e9e1ee65b562d6311c38bc2a0a25aa9ee36f39766a2a03141e95285dd2850a598385f45b9935d63b78c -b051de656e37ccdf3844a6e095d3b42ea9c5a545e0dc2a5234e2016570375bff6b55ee0dff04ece5713ba8e85629a7da -ac01fad1ac299567a22da6949a011f429bd9775de956dcdc247d5c186ec577fbc12a482ebff3a4ab18a8e35f3e2218c2 -9654db9c6b5e58e0b68fc49718773d44129a0e77bfeee3fb56d27c282de6b75fe9c10f4f3b5d3374443a9fad45c400ce -a556631390e6cecc2ebe390e605e6fd754f1961e4bbc063c31c08812e0993eff5b5b7449b9732bfd3a22c87f9c528743 -b41b7abb971e253dfec3aaec4443e875d73373c70c33e9ea19c1176f8cf1278c7716a76a4eeb641c142b2c6c1ace5db7 -8bf37cbe29245c5e217a48140d7f0374f46596f2e82c1144ceb41c9801211869b96d7f1d0f7345233abcfead0309cc3e -a380a799b80f1309ba326f26ee46ba3081b12b5a1143f8289b2fa067aa3ba80c3690fcefded8534a80368799b71ee9c1 -93dce0a2aee4d67efec1b284142d890d1e0d7abdbbfac82f90dcbaea94eef829645675cf17050af7b2e504a46d1bd288 -b8e90f54bc57ff52b84fa3fc3c3047f379c5587ca18d9988c613a3bfe614fd5fc381106729bd62eda298faaf17b10210 -8d8e4f508c284c52a6f907ec39950235c9443c5c6046762911f4818b98293d7d60a2c3f94c5cf60ccfeaeb8f283d8ce1 -a513b66299ba5104ba633cd68121b9ec848e0c8c5252d04a0bdbab5e3bfe6ceac93ebb1ee6f0274920d84eae27df1520 -80e2db8b919dd2ca33e833270738b1f437ae312b1c53a73106b6d12672a395fc3b941292fbb019d40e31b8e96bcb85c5 -a4c28fba416985d47c947b0669cc22153ce887ec54535a18cf457622d03120b6aca71a45fd8704166f6f7a9ea2e9d608 -850b05b9c7e168a83b0e0e77d16181a52d78aa96f4026c4420824cbd44dea9f27f3336b1736bd545bfdf548eb3f4276c -8efabbd63f3b9ae6111dceb1cffe45dd23f1500f87382816d4192161a77dd0776da2a4463d32da85b802ba7299fa726b -9426e75c6f7fb77072773a2ee03e1e3f1d90878fdb5d8c294265262f5c1cdd74a7aca339b46af8a5c43823dac7e57edd -a1c4d2ed335a3c92d867c5cb999b2b807dfb1d45e35b3960dfab19da43e2d1ca9a8748738380cefd137088d8b80d3006 -987a7e22092931f39f05f5a6b38f419750370a71157d4443510b61fe07ac5aa31cd7f88ea04121947b1c0d0419d2a25f -ae73cbce7cda7cd90404302388d41b49ed7d7f505a9a406f0317fccb29e32a5be61a6eb0951657f2d93abbb497be62ad -a1c7cb4056984c22a57ce76272428a50fd33f0f7a68c29c9438af05a87bec23d8de72062fb4829adafe597a278de0c01 -b72c81a9a747a83a650b58ee01015a8882789983b67ac4f2fbedbbf47dbe30f04f686877d8f118b4634289866aecf9da -91ba1797d6913270ac1cb9c87d9d8440a651e294c45b2301ff8c40416e58126318f0f2d411b7d9c09c8e19f4da8ca0ef -864107657717124339cb2ec06cdfa75fb9c4a7ad5155cbdd03d155a7f9e9026e237d7cf5f4cbf07239e7bfbd79900957 -87af853a334b8cdd10bf5f78753b27a0c9aac9f55db7570e2d9d42f13d0e2f8bfc4ca64b77b21e478f23385f17eb4f6d -8658227bb8733d6c7608d66a748caba761f28da4d95e70506dcfdc18300a559b4a84d11a9a048e82b292eb1b5d88bbf9 -b078413570ead3243b9666c109a17678fe60dd1240caf01d1d344de09e346015cba7a40560b0d68b18df82a0a37ca529 -af6dd12875a891eea9d846aa660a207a527d08f5959976f6cb7585a98b1133f341f4ae29157f6ea8e0500fb6b49fb9c1 -abc0fb42239fa531cf09f7288fb00f1d1587f2a86503593d481bb19b1159a6a9d6f4794565fe923a545d45b058d3a74b -b95966d42c59bb12029aef1da7fd50e9e8aa9ea287649ec3ba44247b185b485260af077e0d755f322ee4ecf8e2c8137b -8b1a2350f9bb0d6de377c00f0897081bfbaac5d47cac852a22dd8a427fd2e3029a1708f452e958a07236c7f35ddeb565 -acaff21e9740b831fee42d80a9a80cffa6673e39f85b815b4f546f538dcd803320f90f4f25436796721c8a11f5a1b25e -a0dd42f019eedba19f4345553965508aa9d2eb1499a363056d95e27f7083c2343e74a0e7dfb101567250148ee1bec1d7 -a08d1b1863e594bfcfa2e21ef4edee8535c8ee69490a4113787899ad8cf2f2ebbdea54de193ded85af82fde074ccd0fc -960912b621ff08e27781a4f9b80ef1014a4064fa3c96f534b67e5a094a5c11d9cadb2b69cd2011cdddb463f2936c7ff5 -b3437f1e0872f6b9ec071a951f26120f27425789e00c1a8d3183879ed02e3b017406c051f32580b78b4d0f090474b42a -a90e6d1b11ebd1f1dec54d7b3fb336b9a53c821f295a592e147d5fd453d66e63295a96ce827c4ad64c37d4bc0df2c7e7 -b357a785f3dc1f9bc1034da77033c0c64b29b78c7381ca59ef81e24ab14448d67dbf84756ea233b9e3539b5ed517d9c3 -9360adb42210abb9d7644bb95532e1f461464446e94cb5047bf8ed5513398414130630866b6980b6afec5401e608f6f5 -9145a7f8b2cf1bdd90b9a860051eacdb937189e8d68793e52bed202fa1e23a87db9c51a18f0bc050dfc3c600780099c3 -ae086e289e16608f02281bbde5a6fb2479e3151a2464b86ea737f8a43e15af4fe781312d0e5620a42a096cfbec885b0a -92b57fb14a0c567a16567f83e72b03b8b564ff6d830a5776014167cea06205579dd10715071097710dbf50b660b9143b -83e6a3f027163e635c2a1a397d2661a2d6c72c25082df129572082db29b1587c78dc3d2e5999112983a040ca46bc983c -b1667d022c8099dac5af4ce3b4ed6f524819240275725c7580a2386f067fdc9b3a49b74195cc6f661212fb07ff133463 -aa2eb0c44df0a80047eec28a80440ed5f363e3d42908506bf8418bf04e9c17a5e9f550bec9c8ab8dc9979736ce325780 -a2c1d257de1a55e4c10879eadd49af8950b0cf25121e8d7de30049360470aeecfbef263739262bf1f97020c6b025f9cd -af29d1afc9f76417e4396c54300773fd283f1bc2cb00308da5e6b1deac7a48cb117c0e8c87b03076c7a1b8414d25dc97 -a44d4f2186f5d728fdb224f10b496c9b57d96204325c452842423cbd29bbb2d07e98013a3880c7dfd63ede725d15953a -a30c45d1cdc68a5d5ab65b57d60c8b386be836c5bfda7e2f0347229b7807f6a97b632bf54ba3711066bcbd5e0831e5bb -a8c3c93d6a3526270ae47bc2628da82bbdb8b2c8e4d6a4cb5e9cf70b49999a963f3e856ff9db12cfd2575187bec668c7 -a03566f1a99f5b82e8243678d0bb033441cb8a2f160c0c66dcebd0b6922a56f895a69b94a9c65f4adc9ed73420fd30dd -a4e3c839a6f4f4317e7bd06f25c5236e42fb0e54bb975f18f0240bdc214780049f0258dae24fba6301aad508ef9abf69 -b7e0349d89616156679d06d1626f45dbc9683ad73ed91f0d92f8f82cb0ea2ae8d3ba3a752e73a39da70569d41e84015e -8c9ec5ff6be4b0d9337c5336b467c6d4f552af691bf083a23f1f9856e18b5a13852143dabf03869009febc443b2edbef -a12ff782575aca7b48844f0402a311bcb3e19514dd4d2ba5b39694c66846b22dc9ba25ea39c3c1bc325eda3afa1f00b1 -b55bb586ebf5c9a3c83a04bae254e22547f37b9090151d96f5d8aa81be17bb38d2763a08cf0519a91878633ced6ce0f4 -b3957203932032fe180ba9cb5347c2c1865a3094d03f6611148af4094fa6a8eae522f2651780d9bc49b41f5c36054eab -a0c865b498e30180c48fcab93342a50ca1cddd8759d6e0bb54e9f92e7b60c51c373f7ab1432aeb5e5c2d3ffcd79e8180 -9503ffb3529c3415c07247211c2a4f35d8ecef98ce9f921e67438ffd538caa54520fc6d248a081f46221a0f1165011bb -906deaabf6e8dd0c24a4b22757b7681bf88268d9b4ff97f2844f9de825af511155d0bbc48dc4c03b87007be94f835d92 -96c2a7f48990ecffccbefe128a28cd5b26c664b8dc9bbae16d857f7efc1b7711c734ba7d1476945d09ace569297ea96b -a37ea083b0a61f400b498ac5ba2360c22e40b688428ff4a02e3cc80206b61061bde037cd52d97eeca175394dc675e216 -89b15c3af439769829ca930fa83c47afe070f6e2d7a7df88e5a4f3a2c0630f9d143bb3cc43ebf9bbc1b91be03d35ffda -8eca6996ba407886d3b9d2e4b1aae1983023dbb1c9ae47b6637458c73ffb7f422b0a893eb0b07fea2c5172ba335595b4 -81df4d7f576930b2865af5ee1525718a09b65d9a013feafd19cad335e4e425485531807078b9564c8db3bad95d23bb0f -b6635aa3ca31c851a0283c0c6356235a5d8de9d1db9780e62087be32089c1c081bdc642f067224e88c14252efb960e3d -a0120e81025ba07848ef24ca9a94699db5274a8c85eb9c2f3b41a81f630d09d100127154ddc3270525961613a41ed81e -aaa8dd063f9f4f73f5a7c440671e1375ca8c224f8f869af736edcc435329487902249c68ef646fbf71c33a8bd1a04d9d -a36bfb14bbf3956c317e01fe744bd9c6c6f526a3881f6800592501ca1d9caba7f81b3b54f53b2ee1b13aa6de42ba06ec -819cd123fd793c0c9aba75aa96293268a4731c68c0a26a52561a695fc4acc409752de84ebd19494bae70849ce538138a -ad4e50ce325477621b6eb4d453b087c3d7df6e3d019ab41239f2ad0615c6030aeaf85e0e020f3e6c89e46b8586b4a347 -a4327072fbcf33be1e57ee4bd5db4c079c5ec11694a25fa2fb30932f8a2a35a63183b24d3ded7f6c8a8d0ad111586dbf -9454f17aa8fbdd2b15dfa6600ad305936a37b205eb554c915adc43aceb4dff6b0d1414e61584d5b15265f2ec0c85abea -80eed3725282c83dde575620bc0d86e50412df5dac3b3556d1e3bd9e7ef6f56dab202f4dfe4ce542babd49c1fa7dea5a -b90d1a07ff760daa23b7408b067c322f126023389beb7bf373f0c68b85ba0ea8a2c03e77e6d3339a01ed3ff8ba51f1f6 -92789ad894995ba07f36a0814fc3289810136f9dbc6c70c57ea80db464772d760b57d5b059d4ed458f256af7603fa2c3 -96a4ae1ca46d3b26029767e02fcf2f623d32c952712badf2a2af721226473f4875c40d5b14e66bf961a5a56aaced3aeb -8c5073f4846df9a0e057f52fdefe01a9b8c9ace91ef5ac253e823e165ae698e733eb936ad9cb04d2c54cd8570f328c4e -a9f36450b5ca66a20e52bc196620852a41f1f40262a2e12c278818b6071e6972c3cc6fdf83a9ccf586db6cc177173cae -8f101df23aa7e353ac1034c38adab8f20b8753aacabd10d70acb41d0fd0b1f34277546b30f64d0a861f448f112e38acf -b45b0779ef1ffbfa86d7e02e89bba0316c5ce60742b350296eff0d04246f1c8b1bf5bff68bc97792c85f1e5d4dcabacf -b7e89d015f6c7122a2f35f1c48b43eb0076ac4269158d52e38bf2a11de11cf2928175f717ee5c1bf543ea38945658558 -ade2a57ebd7600929dcdacc290168443437bc288371ef40580df515012350f3453b09aad8ae9e64bbc3fe6a3456f2c31 -91c2f8de02bd8dfed1eeebc40a422d444e3459f9c33476b55de3e950d2c38d8463c4edf4d4f95347b0599a48cb2d47e5 -8f6e77d9ceec539e0407a8d75d4e855e376838c0f886b36615a9c7715bce56a8669586f6d7cef75812d84b8be91380bd -87637da91b051ad92081e682e289bb904c51d95ee1a6ae2b8956982093a7bb4f8a66d91874265dc32229f9db5bd51ba0 -94691811eb74f2970a95e9a2d64435952145f1d0caa76040f9811c9ea1ed7327750d57d6e8dd63c6378f336421d11093 -884cff4ebea1bb48c0d651bcf0a710ebccab9062c96364aa64aa1275e9364a4c261e40a4b9f7e1e135572681a5a7a965 -93f21d4b6b53cdc1dd41cb1b80ff73c0f1620db41c35aeccc059128704e9d1d7da5fd3240e7d075a2503273e7525664c -b9afe0a9b64dc43fa78f607cdcfe337ac952fccfde41c2e88abe3a8dbb36a51b3445d724908e552ba74bf67ea2cab56d -910280ba145bcb6a99d89d1526f10632206d2ca9e1a8596e5d181dfa37e5f407e1264b9c71c39530caa59894c10b371b -a5f583c9fbed59f99cf5e21b9a734de6d5685b9c33931325dd4b581bcf5aa4764c2a250924e7b6f7931dc5278bd17152 -a87267f2ad292572a1cfc89308c96aec0d12e5f0fc2b4135ff8df7cf83bb1e71d619906d415db5841bbbeb173868ca82 -899d7ff8d7f8d0daf62ec8d28adbfe4e7856582a23e62dee175e3bb9461f38bf8e4f73dffe10654a046573896f6de690 -a8f3601e6787e788d46a9d7592dd4bdd8ea8b5136e3c897d79ce560e9511f6236e67a85a35c59295428c1f9c019a0841 -b180a16448f085227a6f3e363b0dbcab285bf419d438a13be2cac1ac9f97973ff6b8aee38294f70a8d72bb4ff474577f -869038341a2f68ba85f5b2de58d2d794584a3c00a76ad0dda5aec31d4e3ee433be20c197b40618f89f7c8f1692ea3cc9 -8366f825dabdf4f7714c5d089443d0de315198e23fb93c3ed063c4b8fca0727b05665c04beca145dc4c02f333e300c18 -93291da32b501cdfa3624b39f6e38ed982c75c1209cd85630cf83288204032c0a90f013f1dfb4dcedee7aaf0fd95566a -96c95a1e73016fecc3483fc94dfaceea376ac700fd4804b24e9eda7135048e521daf96f8f63d5a1439950a64296d8124 -866429fba47fb691a4c39460031a7e614096abbca3073e9246babd23075e8e5f6051e424e47d860296ac8ac646f8a283 -b817f3d9985cf9f9657fa800ebd36a9622566697ce68f91c509d9ad7df8146532e24ad85c07f399908f87d1206c7642c -8761c3755cf5440775fe00081f79dbf59829f8d400adf7448188b97f756ad35658295649294ac9626c2569ab21a5df86 -aad65ace72ef89783507c9feb5555275d70a421a95f306b7613c894bc24e978be809410b519e9314ac56fdae0c71d326 -8ed16ed07d0e989061db5087d50cebfcd6983fd54be5062e333bfb8f6f609bf1b7b840c91ffe4b66fd674eeae2dd1558 -af3919bbc0df42b1e2e8f62e931701f7c35cfefe3ac3f1985ddb70212476112e8a19d51c673da931777ffa28944306f2 -99a364d8819b5ea0f6d900167b60063f40f9afcf291ded7adaa2d0e46f344751cb312df1c2113bad8d84a028f680b41b -8d970bad8f95ced0b0323f4b7b087efd0624ce21834b3c9ed435dc0a394cc2c7ce58f1741c1a64265c81654eeb6801ee -a5f96a4d794f6f844b38f9b82ee15c2441cce293b6b2ba26b25643165236db05ffa918ebbe20aa89ed2a8ffc8df393fa -8ca69e0006f6a72e5abcc32c3961aeeebb8c0a76d877fdd8a093467485c19662b75f2ad8c750acc9cc12c8fcbfbe9b0c -b5378b855f6ed3eec19546cc21c947dd12e98783164d95a95d3cac36c89a840bcb9f7c99b191fa7730ec28d57e7326dc -884e50d5e20bebca96dda539daeb0e15edaac7fc88bca254a7239f30aaec47a64f29b69fb2d90041b82f8ad8e3f13d3c -abcce1f6149037ac8d27497831acb867cd5e05f637b7579736ba5c384b8145f127c56b82b1876881b782b94a84d32d04 -8747985d53fac369c4a23224d50bdc556c00f406e7ab3e38427aec317ae7c0feee5b48b9386c5764de883cf296ed1daa -a153c77887f271316d5a7185fe0d2bb7359cad86ba80b03434bee8f21b3a5e52263d28cb9d3d2e6d5b7443196e03cf80 -a77b16b2b7b6e999144af6c919e0a74b9a6ff70de41a133f7f820befc1261bf261142717133dd4a99e168a5cca4791e5 -b89beb83489db9fb62fa32d1a8ecb66fe9ed41d318820d13c3e07e1c97802dfd7b05d34652a478a1deb3b17b4243a499 -a80200902da696d0d3974ab29676f0eb67d15166b173fd63b247a17cc49f56b6ffa28d9690841ed4865229248650601f -8210103eccfd1f4be55e33991a831c50260bbabc1f311564fc1c52c3b2755d3e4a11ad69cd95e398dffdb9a0f5b77df0 -9958745d00d8f29d05d97875746d863007b1c05d3ae920794e6c65adb47ec208734fdaed1b49982c4f4cdd1d3043c369 -94a4f28dc7a9d2dd01ebc2f3ed11a5bb01a2095e7c772d2753c022d991da7b2e4c80c2170209bcc4771d68ef8cf007c0 -a6b5c5543ae3de57e074fac82221590a8d771e93e22fffc2029b44e8a1c2c8c9cb0362416de54d00fd5420e5b1375eb3 -875e801265871509c71dce38005ad6423fd027206e6ab4c58d2978ab4812d5720401c1310b56ce9ecd95241a17ce0e7a -b6819bc6497ed57feb41bd82f56216b513085b6d1a560a958adcc06a6da304424ee34ab2580604b0e59f6b0091ffe6ad -93bef0806f21f8bac88a5d6e2e6d1adda06f9daad5cc3c8de61162495d8fcc3889b767a3e2f3380f162166ce40a0ce80 -a1f699cd7446cdb1321a05f970bc70cc98593aaf0145a0d097e60e5897aa311b00d019e09cd533d0c0b7cc5c00a753e5 -89ae140ad75a83db2903a93a3711be90986d08dcfe962aec5ea4ee69656026dce77821993c1defc4464442bfe7d44734 -a4110c80ba92f545a1a7545cbeef997d6c0242fd4d771977192269d626b35c88c361df53bb36dfa8ea7e40da68e45f81 -906786f38eb7e98c431fa2464048ac3f1f1df8f908a25262978327224bc82168f564b2f3e6da77f49457ce49c1a72c2b -b28d92b3228547f03a3f489e09070ad9a1e20a73e49f7ada96ce41c19cd6416ad809b3a3a01f141b3698e85c641d795d -a25b9df9b377baafc8c735a772e0ed9ac007c0b6ebac2cc0f8f2e799e5e6038a616968c9896cea862e99b1750224ffe7 -8085eaabc79a2faf1ed0b9fdd017fba1e46c671c6d8ed78fb089494f792765b0617f790016d8f55697dd0f45d17de4b1 -a0e81b557af74efb95cf94054264d30396121312c643052070ab53eac8e75075f1fd0b384cdf1d96bd39cc98681b2d92 -b8e0ffc7548969ae28beaa9d8bd65872840a03150e2140dd799d9924249f92d962a0089171bf4b311520ab527198668f -a6188827a500b99af6eb91094a0e464e394c8c0a6d80cfcc5d8be89e8810732a03ca75b2befd00d07d1dfbe7dbe89be5 -a4e5a47c656e74107e6007199b940d8381f706d5bb4226a0b2fb13eda725a556530b8d4876dc49c5f9631dc6bfcc4c9f -90330a50442db9a9c459e06d42cf7a69e009332976c3950ae7d9981d99066fd2af22f22ac429850b998f1ec929c82bfd -89dcc51fb717212b2dcbd0fa0da189e194b4ad5bf7f43ab2cc2c96f11c186d0872bd930aeaae01661ce2dd9f94eefce9 -adee914ece15575cc34ab485f2dbdf3979406ce7cd8cd82197f156f373beee6d80e5e3623d79a2fef14b0b4ed1678a51 -87e97e8866002364bbe9b49c5f2b5eb729c7018ec61dff7b8bcee1c1ea349e5e04a3f3781617d46d8fe0e62afe55d62b -b6b7bd0bc652a0bf79aeeea1767f0f17dd543b9de582531bb3e14ba2bfe1b720a6c6b613cfc295372eab9202f5e2d340 -a6f9cd96d8e422d9897d50bf36288bf4c09d28cb0f5c4e13ef7f76cef6c75bb594d0ca954ff7339590cdece16414fdba -b9bc319dc5e55630d1ee8cb48978a256b69c96aaabb5269bed8c5366add03a2c38da11cb03a44e150a5c7f34bb49bcd5 -868c36924f0056b3464bff8831543a280ced62be748d60f82ac860c32025c4589e9354984e1cedf24678374c959383a8 -a6244602362c09b382926dabae5793ca4fc50600193c69e645fe229a471f7cf9e58c4a59124d6d2dabaecf50f1e1fd1d -b42df58ee9e20fce589837d5ed8a938eb83a00c6ffe2f6afc973f6ce26559b8d220976ea1fc18ffbafe739c92dda6618 -90c0b2ed8ed7cd6f6ff812c84ed297b3231f6e2106f2df6d5e4b4bbf5378231025582cf39f35dc9344d9fad3adf04685 -a968386bf1221425cee0d0b926689426fd77e8e8bca5ad3bd07298fbbeef4fc676e0cf7a4f29cf981c682a78a54a2d1e -a3a46bb7db36e0294b509036a40875850ea5ce4e8853cc0a7d85e8455fc2bd7d5b593879408ef2f3b2b2bfa44aca2276 -af825963207f046b23534896086a3e56247d752982417047f850bf306d0cce285b537508747afc700dff6472fe3b5569 -8022af88981249b5da08ccc19e4ffbc35feb2cb5308b34064de4d5bfc8ff2b933363988c833ec70723e3b5107f8fbd67 -89687fe6e424c7f0d2751e5f7838e9a3fca4c0bca043806fe511442bbf41cb67d01165ecb662b1ece1b2adede5a9537e -99c925763420fdac4149a02131831449c1df8be4867a6d2d09e6b14abb821d46bc1fc4fc9aacfa4e9de1a93f9b56fbcc -b819ee6a0724de9c944ce2ca51ffd3f1d93c77ff25e39de8be2a612abe732dddbf2219e839686a4373609a560041291f -b5eabf12513e91139025f1236c7ec235368eb8586522dce04d370acd3d854c1e6676d92014b60ea3e4e21e9d6f063f2a -b82e94f1013db6cc682032c7760aca2a1082826d280801aad9c6564704362e61a61cb52c6f35f769bd8ca191e68e0b0a -95dcb02a676b17f20b75632c7a9060f990e44b0c1fba84ec8e633554f875ebcf6e54caeb9816267e84a11808d68728af -b0c7c401dcc019d2108eab7e87d6494e06399f6eb4fd95b8ff9ba4a56e549a3d3a4aff13771229f4c456283fc3cbc53c -b1a8e3e500e3ed74bacf91a82b39f2b870963dec0b98b7d5ccefa3212fc9f3ef923101887572e14d08145aaafa8da5ba -b2caf72c47870ce9f0524c4b3df6ab3eb3695765c010a27c0f3cda0ee1c1f5bee64e5392ef8b3f0f11e66bd8c9d4630d -a8fb4864bce5f1c48d681eb37efe7d9ed1a83ed36bdc1f2627539b92c90e100d4dd64ab664e404b0eb7b645a8f95642e -a1b6164a4f0467444fd56a1f4668c8d1f295f6e6f5191355dcfd004c34153317202823d72162b621f677c970a3f0bfd0 -b2cc59a2f6f3b7e18064720f93b28801fb684d98ee808ec5c04a5235dc40372aa0e0521410d8f736161470443bd97ed7 -b5d9a823649c09151b214406189d75d7f1ca150cc7431d79b7d60348b6d7405014a44bb7840e35f9c0a634b4c6785561 -af6b8229fe035cbd6a5da3a3aad93e7ca5ed233dea5fe4477dce46ed17bac9243ebf25a8439ac2896c41baa671c0fdfc -b42d9023551d999d2be3ee51f6ca82c3b2d41fce51e1dab52095af6d4b59edcad70a1f9b1e71eddff894e3fe35a1f11c -b868543c09fa9b9b990b276ddc5b68a2415965d3de71b9ac538c26a6333543a7c33d0b432f57756ac0077d0021878944 -846577a8c877461a58a94c5829f2ed9d7ed107fa63a48ee77a1ef1f1d1f940b2605fc742cb5ef849e3cbfc86942488fc -967ca22cc8c21382b15d73b4dd4f6f0a0bdb2056c21e3c75eb3d9c13dd41336672ceca03065d8cd1062389afa4726974 -8e0b872d766c439f3f868f18ef0c173896eac883783dcc58917f76d5a2e8c291967a032d254450fa7f9a12fa7d7a4cf9 -a0236eb36a4ce3b7d649ff02de9279d364ecd5059932328230314ecdce3278c42cb836f547bb9da9de0fc96cda2fbc7c -92eac5a5a88648e6d821d3bb51b280fc106f751d85a1742a6a1ceed071eaaa215a0a0238492ddbefbdcdf2e38e4149fc -88e1036f9b20a2c4b3534175c93d59c1ade3fa6652a4c5c490f21f6c3340769c7f8147d53a92fbfd84c23d7c4295cdd2 -8b094165ad429a339f12696bc8967ca89ec47a4778f387e42e273a1863a38199dd795d120d198d3cbd93203604c6914c -8f8013229eb6bc6a8f93c17d3b4a1b206c258f14091c6dc39cb1ec492d403cdf5f696070ef5a6c0ab9ed4ec141b08d73 -81c7ad27bd7a48b444b2be3d4b5d4845743d6ac4857b061e659d7ed48ebacdeac29cabd0cd163f3fe6c5cc28753148cc -91c8a92749183e3e6f3499d3b0e9b080109d5e88ce8acb03b35f3d04591e13b4c489ae323a149def1edaaf62f93bbbe4 -a6a2d69f012d877460c33095924771065fdcdddc30670ea84576b72dd3f7769f90d1735f8914b6841c7d938a2046ff4d -a8ad4b976a5e4477a97d48a3cfcce16b358fd3dc1ed1df301fad6d6f0e188782c518796faf1465e52312b47bd713e2d4 -afa2bab9363187473a85f7020106b176903bc3a3e3df1f4938feed5145b79b66db8aa608cdda554166ec47e60fb34b95 -af691bf473160cfb84ea517702f3c01daa6155f31393d807c897b39523448c5af09be581ad713c76aba194f90895cd9e -b74f3cbc198c9e4b2c7316fffd57fc749e367b7d1cf81b3f5311d266c9a3ab9598075ffb9230dceee230d5f1bbe3f796 -8c28d21c49a15299f7ff3eff7568b8450e6404a168554b8965a291c03fdbbd3dae9ea6b9760869cb1f2e8c7206183195 -a496a0df4e79827cf3bec117b92b5b248dfe129d783841935363362aee4822399974e6c03a92797b3ecde80b207fd7c0 -b39fa07fc8f4be41588ff5560ed68a33c3020bceaf172fd11e0c1288ea885c6dcfb56a151e4773e57d864dce06fdbea0 -990cd050ab056ea447c114217219d9c0c7526803f63952e22ae60a3996608bfa3c6119a56befc597592761e3a90ef448 -b6f02dff3dc330daf82d1edbd4e6964d2e9c38481e74cde8d9d85a9e602ed22c4fe6c9b6f41ec76582f0a4e4414bf300 -84440e4a7146ec2f34e8099e85c09b8d7bf505a15638aa34cd2b42a20f1f335cbc9f0e4fdaf2e53fa0ebb2dcb00519e7 -af389aed116fe58580810fc474eb15518dcd9746f04a7efd2de44c9774824db79f8ce4c4fa108e7396e1fc016132a402 -b202985e01c62d0de1f6807fe600a3b81fd11f30f5aa033b1e7baf7a62f34fa5342d42ad6a6e309560e3e9ebc662920c -8a07641140db9701c676b2c094c24cd663a5a34d3534fd4f5f1e38ca0c46772d141679730b5d0cd71d056c257d9a125c -99dc01e76174370a741e8e9ef5654a3a7769a010da85de41dd315b674ba8786e6a697b74a79ea782a1fcf74a48e51775 -93fc897841609670a1eb88d4e4498c54e286e25238309fc95389b16e4edfb82b8ee8447a436893c7180827a996b9a0f7 -8e2dd561acc8954a53635c0108ff964774fe98d12b28a0c6ea8b5ec5ea3523a45b81ec642c1453e3b2a1c0e0749562be -a95b0b7f9e53720f4b0394bb6ae8222aa5be00a2050f59ccb595d50e0dd9100e397af9ea77b0335be02d1713c361357c -8e21dcb67da3eaff5b950f989939237e3735a31e346e1bec8e6ca11edff5223e33c1c6f2f79da975de2fd86dea286e1c -ac02cadeba36143767bdb8cd4e1caf8cb287296b53955f33ed07f771a1fea521fd64b7e153c90d5e270c12ab959cfd24 -af95bca4016b2ddbca61c9c854cf999ed59ab4b5d619dd55460f20cde5ecc86081a2586a7eb37f15c20280dd06b65809 -b7d7c81261e8c6a8983442e1e801f5072bbada1eb2e49b8e90759dcad653c52c0afdff9cbec41bf21cfe832e49ef8db8 -97fe8c6d071dc80355bf2a74c15ecb16c59bc042eff323e999f4fdc39e1209803d32622c642ad25673c84761f0d357bf -b37da716119c00a0955a7fee59b93185a6e325bc5cb2a7fb35681fca0688d0ad2d25a0e40dfdbec1a11deadb1cc69d47 -afb8091548179fd2a17d95ca47909d97866e4fe54099736e6414682ad083fce300e0a20dfe3a017c1ee4ee7d271bc470 -9306ba1f3f2f74964dfcbcf9b87bafa44b5e013853c46cb501e10409f3c2af7269aa17c8cab261fe82e52a188ce0d18a -82430e3c25970411f40aa72ef1cda5b2b51bbc7e243a1b4951e92cb56a2f5b200a039f5554d0d1bb44330d89d1ef8840 -aabfccb8f3dfbd4012b9d196448e83f17bd1ddb8c857dbf98e80ffc60c1af3493ac5c70e3a2f1f26352b1ead143dee87 -832cd6dc83380d068c068d815ad0f4677de0ef602890835b8d32b73223490a6f753092d651968cb3d798cbf2a227960d -80e3e7f0c46fe5d962322f3fb2535de40dc078db80e7ef57923d46b742a8e4d6dd35ef74234f2b1637a317364d57abbf -9306bcc29d6f8a478ec085b144161850afa29d282cec756d0d3fcce6f4860f4a4b8c8a5952cce54ea893cf84abd6c4fb -9234c03bebfe6b47aedc7c5452058ca6a8def3c368bdbc9019ef121ad44171d6b31d9bda9c82300b5b396187324684ec -abc2ec6016ee252f5693558b694eeeddeabf4579b7e03d37504c26ecc29263e455ce8f0158fbfc54135600b72dc54315 -b46fe7b51df64cf46888a810365f891d43db5b34ac4d3505f0692603adef04b1d08eadb3e31d039817e7b89bf0789802 -988e0dd101bba7d7e4094cde99eeeb6d4411341e684fc06ae78d163d30c4b585375a868eda7ba1e5495ee7f0a7d509e1 -94d3033ee1926aef656b31192653d3da96d5c533ac2436d68fcbaebf827475778689ecf14fc53042a523e4652fb9d713 -993b598555bd2a35e9a03f99950d09f55a48ba63f9e0e65802ecb95602d045001f82f25c3bb60221adcb8ab4e2709ba1 -a0acd921ea7db9870716acb595c65a934a5a06a07c6e54cd26efc86c97eadaae1522a4a26c8f93b7b7cbc4746ecfc21d -8dbd8f492764bee920e0224dbe39d650be6732b56976a5e1b636b2e7371c1509431175b66c6ca879ba8f915f9df8fa36 -a01b24c1e3aa044cd2598032950755763345534f95f6f71d50565d25cbbbdf9c42e35253e35b683f6c3156f5c998ca4d -b895522dee1ec9c5289e6fec652093519cbbdca7a2936fd1df3ef956eb404f1a24272c9ae6ce58eceeceff36d76d34d5 -b91cea120e200858457a64a60aa876f167b1b88c1dacd9988700b9f0f0d1bd1dfdd8dab56c2e7197a174b7b8bb8422e0 -8406767e4f7cee2e12431b093ce82f633ffc76b451ac8414716fc74fbadff30c52a22869607d5de465d0f4df8a740343 -a2cf431d18b2fa526291c7027d59b18cbd73a9b48d68cfd6e4b745d27774941af809edba06c8534b1864045d6fc1bc20 -ab3fe23aa8c45ab2efb2ca0c593c8644d3f47f748c2f753626289b0b9c761add755e3b52521ef37fd609429b2f8770ff -af4530dfc5b3f37888900d9fd08554bef4e47c4c09a8c82bb48c4b9c6c9089465f98762d81ba4272b6861121b65f3c5d -80f61d086511b9b8b2033921336a68adde99cd25fac71d8f8fd0e476dd30cdfba49363784f0d0578c1f648f93ae23f8f -82ca682cc254952330d1be8c0e53da24aa943ffe0209b00bbf046e1e4f9425886a01d6582e2853137a9c256316e6f737 -ad1d508d2ea2806c351d5bd1098c46ae7ef83f4e49e4e87f83fa2c63f715ec56109996284a541c2005693687b4813623 -9061817ee94bd2895064f4af04777b499a1fedd9688ed64bdba848202c3cf9286b699c92400ed456db926ee23a34f90a -a8bda55cf6f3f9edb78b43a52b7fe76e5cc2cde21e08487ea597cc266e54700ddcea1a287ec6d8f16b738b67caa27152 -b605576e55d1fa4fd9d7fac2ce549dfe23fd6ade41fa859bf809baa3f1497d078cab06a257ccfd6cd59f67f17eb22f5f -a92d22ff5b5ec6dbb1d57db1b740521e82b4bef84dec3e130cab63d0641c3a8fec1f6f86141fb1918dc0f3fcfcbd8cb6 -a0165df8dfd7b3cb58883768471cf485b886ece529d5bb78b26acf9ef6c44314cf9f34914233c93b10b1918533dcb8c7 -88b79c9c721c1936fdbe22d68459d1033fdc986d3e52f39341ab06cc85a3f230ecf0965ee8d2dd54496981fd08a02657 -939b77fcd53a523240bee730c2d7b8dae0b32bc3dbbd31428c7b5fdb4c3d34afe7f2a377b2918497574606bc06cac750 -abbf82d0156439761b36a913b661e3d452dfa57e443ddb61613f80e110acf52765139fe3d1dd59c9e7773b262140cb90 -aba28324844cd19b2d5d07a87e6f3180a3c02c7326bca846c1e7a7c131c7ddbefeabbd6787b4e1e910449f3cd1249ed6 -ab2f71af8596c10351f7ce9c3a9bec08a5c7837cee92a7400826284752c98531a0199e2a7f9ba7ccccc8fa0a2207aa43 -a71d5a4f8af3a16ec9c3c110ca2135c68103109d4384a299cb7ed09d96231c90b04ce34ce12de02a40924d84947f7f31 -b9dd79bf3286ea08c9b779910c84fdd02a33dbff7adc2d6612cd58e81aaff3f64ba021f875ea9e1201243ce353510350 -9838fce2f70e7c47dca7239883229c1573ea97d469f120e4af659b18bca31cb68d12220fbd6e4e9e952b28eb29c1e5ee -8dd341e67e4c567a4ea95252854cfff8a7631c228ac852b33b2ea9211b2a6c606e4b0db28afec61a1a55e6b5f0a6604f -ae9b02d60441859e3e6f3866a9bab8895f0cd6168f8e84dda7c9b1cd7917f1c454f10aff9a8de39909e36576bc0b4828 -89fba7834469a06cb0da39c39a288245e577fd956c241707c432c2590e18e956e8ea3f67e4bee5a5562377617af53334 -b7ab26d79ee65eb9612e54f41f75e22abd83db45010e1a94ce5026a24675bdf670e806c71f0964a33d6ed277d464732b -8a25bae10ef86d7e91a7d686965d17fe16ed635d787d4d6ca337b10ea32082938f4354620a72b5aa43ae62c7a0e751b9 -b18fd9213bf3b2d7d191266c7bc1c31f683fc7da7dc5ddb4c600e1ebf5fa80a399af9e31b4ae747581a07ccb736b4b32 -9968346d8a867eb57f628e2ba00f69e9d6aa8e713377a69413323b1b9b26218f527c0e719dcc1027daf10c3392f59733 -831ee266686776eae4e3de1f2bc37761a5e1b918d4bf0bbeeb20b490902ae97722bcb1c98c485407491f248eecb841fd -b0e949d7c50b852055f38f3542a974bbfe7a33409d67c557d70c1204f87265bd7478e1751251792435fa22097d1762e4 -8b0bee83715e20f2ef832347c926249b5b168e4ad87b2e5a9149ea4e07513e4790f60b1769ddd1816d7126a0f6fdbac3 -84edc35061dbe8f3de90c2f9ace94be5ab4170b66c42583a0643ff776256217bbc6fa31612e68bfb9ab678f8e8e49457 -afb4ca7a4781dd31a7d81ba8a739eb65c43f3374e76b4ffeb2c7048b055f837e6853b14ed2d3224a40dea35799f0e4a4 -9945fd5ecdda5ac952785310e87917126917fd4f504fc5565c236db9b96f9666934766f46a1989c1aa176e543c6e33af -a6d4466b53c48d7facb9cc33ced1bec98897e545b10586857e896d35c850f2cdda65e19bb934a8c74f6def805b1df4f2 -81e3fe4330948c279d99a8a1a4e4e141a039b3ccb7287aaba6f9041c3a8a41db1a4763fe04a36bdadd3d3295becb9d41 -b6be2ef16b60a78b17991d27463e401eca731129843021e302830c2fd665726547240ec3a3240586b01a05ca8206dba1 -b9d7fe5671b220a3da83bfccdc16c0b6f5e9e5c87810db14f070dfee582fa190a360c62acff13cd877c818d705a8a872 -86867f22bf6b859e7f0ae7724a1174a65c4902cdcf74bdb22415875d72b67f49c62ea8bf9ed0d6883ab76512ebb951f1 -ab728a8167b9e82d608d4939a0712f82843f624d08d4013dfd3de41bc526e9d495cbfd40c443f67ac59dc4b5f30ff217 -a5c4d10a04452c1ad12c18ce8ed7eadea1f3cdb34fa5ce0cbd804f5dd92eae2551b771523e711e8037770cb66d1951e4 -8808f69b975f363bc08f8578729a6e68445138dada78d5818d33fb83a7af6cc6e7030f7b76286829861a4534e0b30248 -a280773d32e1ce3544d3ba5025896d21e358592504737de72ae76d164009fdad05c8a1e5e1f8658ca6374b347d47c29b -ace91a3971be87b1ca8e737802918d86375088e74380c444751c65978afba2b017cbd8fdcd3f9a0c19c0782b0034a589 -b5445d816d65ea36c9bc6a3d5ec44ce6b76dcc18343d7084567dcf2603d2af93fa8469a1c493e19f1853c96f89621fce -a238867fce5b09e8695240f936a3f3cb12a715511b7516de995543b2e15aed8860a12754ac8d1c5ca2364e4471a9c5ac -9467528341f5b93b89c7f37c5dac8bafd0af620230a9f7de3e809f01cf73b8ddf70c38c5023a631a1978ac05ca35c318 -8e5f1c3c411f0939ce4b6a5ced42172fc5c3774f596a114e7c5c8ba433c4efd94ca84affc0bfa89a1c5ace5090276a43 -a6351818f7553d446cbe8d3a318841b0607d1f1890ebf9c6220a092bad3ece9ef8acad4d17935e437377af8f9309606e -86630d0fb2bc104d8cf840b0e545c0c149c1a8e4dd6d460dd15a52a5935c8ea5c934ef099653d783894a6d1f68414a84 -b357b5d9cc645b645fbce2020db583cdb68772751d6d11d635f1e3ecf995a55bc374be7750b6e8bd4968a55600ca9806 -a9b659b8cacb73a81093eeec42dd7f4fc5d955f9fc543037f31bbcf456af6476f303aaf0ef960a2df88365c2704bb61a -8b6ff5201c15cffe64bdeb818422fa10dc503ef2a6a4d686364afd0f35b6473e4463719173550d234639f6077e19542d -98efe45bca5ac679cadc25ad0bdb1f8deffba13d2d7eb14c6149d5addfac06b82fbba6d24b323d615eeee1465b3cc30d -8c2329c976d78f1d5e30ac34a3fab1f96436947d85f0dd190301a1868e5dcbe4ce60f48fdeffc3e6a05ee34a461d7dd9 -aec012ad25d99ce014101d7da512fe032673399526435f6e1faca4b63759e8f6694a46ad01672da9eaaa4634f61ce89b -b8d52e530c942c3c7a67bbd0366f4cfdc6a1a075471878516b7a2258aa073eba50a113cf433879a0e15462e82087d17b -b40c5ce16f94837c86e81d98e2130a9e1dd229da5aea52e79cb42217d3b5908a53d76782cbe3934fa8769db58b00dee8 -877300304eb69720f7cfb4f907b4a7e238920fda129a38516dffcbdaae2e46633d31080590d6df05756781224d532fe8 -973632dc791a5214516c3e59b2b48169470678b7dab66d513e35a0fd1df86b992e27ffe6050a5233af20b5d4998d283c -a8ae0e723a8ea6e95d721337465a388b60b92b1d9b1deb0b9f59ea30842de356184fd55d9b8331d8a29ef473c1ac2315 -92ed6cca30f76135c4b7e7893c3460501e92592f7d2d6409c1e1d80074120243a5b9ec14d801991204f5ec4f94ff1daa -a9f575b8518dacdbc5cae766389ab2ec01c876038414b7796f640f633367a5281cb49b48b5e80f6416a33b401c21309a -b9793588283cfdd47cc4547cecfd987f9f8f92c2b408725f39c1d879199d695e87675fa7e5a190ab3bbc97683a0b9587 -8329a844dd67dfd48546791c4330af65501baf9524ecf8ed4fec9ea87067d0afbd33099052c1c2df819ca1afcf25dfc6 -b908eba1b40edc300b63ff6e20e87b17e6dfe975c37ca63c92e8866968070a2c07204264646bbc9318145fcb90c23555 -8123871ed78f46e9eff4fc7af9f490594fd7c20fb814e505481ac5c7bc7588c1706a79b14b85d29bd7b97d7c82b2ae79 -833ed8928f154fe0a88ae98e5d8c74f816e3ad679c1c4ac1322604093e85ed4b9b9c4361ac188f0da5443c72ee4bf3d4 -b9fcbb8a422bd8d996e713d176b7e63edcc6d73b3d1fe3f2c4b59da637a168accb5fb4d227b709f979742cc0af8c0ea8 -ad3759a6a6bac3047935443347e3c63819905f6c01f58f0ba76aab422d723cee10c769663be9554473e668bffde1d500 -a60c1909703211a93d7b5e8b8ec1cf4ca06ada653c27696a7dc9a2ff75cb712918888c6b61b8f792ce9b413aac09f48d -91f05985ff17f9ae20498185f6558f9f38b67966876dcc6981af4d179cd055661adc63155f4afa6167ad61b7038ac49f -95c5add9bab6b9792517772f9f8b21bf7cc325dfd13a43177b0bd982d0f620185d8596c2cba46a5e10aae597129870ce -ac0b4b6e2b3e417166ad9b17de0b3ba775df6ad3a78ad13a1892c0992735ae54c06b1e6123b0c0bc90544441630c6a1b -b0135c25f74ae776c241faa6c91a3f7ed6138d19a2100928b7ede64b79e177d92c5cf921dcce3c614e32de34975fa6ca -b2215b560d5a36f045de7257098e9d75a40122919d4726990b4395eb2bf1ec789cd0c64c46b775f6a8be28f23958e17a -870dc7f7a513728f2b428a3c08b15a6af88a288824e790f41b1190fbe02b59dce2914a1339f7203cdb7f2f9c98d8d721 -8e3895f03952cdab36f602418cd746bc0b6a07629eab0a20bbd8de6c993030c5287fc146fc45fe97a06c992e0a9ddf02 -a4cea15ebc0dfad9feb3d18168fd33768e8ac69e263263ceffcdfa35e8638711c2971697b7d5b2aaa0fd8c5440f3e164 -8cfaf5369781a59f4117283fd3f290b81816abd3124a9486ab1faf7018d36a73c1630efc4ad648ce462e541827d51975 -82b420eb25736126ef18d91e91ca2ecaea8983b8091df88343e8e54ca5ea7a3da6918c97695cc0cd5c2df95afb1e3cb7 -b3c13923a3d46d990aaa6a1eff3ad32f162ccc5186e16a549dc29ad4d63de6287cd05579452785cab32e2485636d568a -ad8a43ad6195e08a36f755dd536842ec88a7d920bc302451c860444a3fdaf294e5b5dc5a122423474d322af5de8cd8a1 -ae40d1a90a77965366b5b5ce87d6fe86eb255cc3d127526930d128ef7763455adb82475ebfb7be31f9c512394f2a22fb -9763bb9459fd4c0de2534767bd99f98b859030b6af5739a7081d889d6875f5c23f0154c30d00b7240baf6450b4459987 -94aace9e9318d79d3c7ab533baca31724bfec839b01187e326b1fdef846968b1b29882f2520a9e237dc41ada01bc3761 -b6084f9e0051be76244ead401e8d2758717e93c4cdac58443261b3603cfee0eaec7d758b2e4357650d2c1f5391edf798 -8c656a798fea470163e70869a13edd30d138bc148460d122a2275df8cb43f2b45a14e0d8a8a49eeb7c1afd02484b6ffe -8ec317e63df2881f49401eb2f6a82e261b07474006fc293bbb54e0fb7437697b16ec1d6ea101fcd56543bf4d69374cf4 -b27d9b3b8c3cc59d08159c765d24fd4660bd0a54b2b7fa9fa00b47e6770e6e8d3ca353d305fd772c8171e20765c8a66c -863ca045abc38ceee09c4a21a3dd18f1c0f70c0289437957aaa39ff764760bc422b748bef8ef133ee28d88c46e6be1c3 -b0de194caa68f5288dc365faf9e9ca3c69b0a8376cdb532cd6f1cc3478671a1e755d0e8afbde4e3a88440fd9cff4e8f6 -8a259f48cf5a45773522f3c5f283a6c01a0febdae09f873e009e4635c57fe5060b01243b2e5e1c9d2ff7490f2dd3b334 -8c4398e1e579778c88976ba12feaeac0c96fc97b4e26a133ae74fca1b9c315c1112ce3977d20fbe9ae5866ca6544fdcf -b54b25aeebf1917bb4981b43f39491918773bacce37e994b74f877d4a636f1b3f4a2f164b858f95259f285ca0c294f24 -a9db33b15331e852da3693f6328bde30b8cdd79c9b9b63107cf78dedcf14da68446c462720b9ffa5a1bfdaa68f5d931e -9966b6bea54405df1dc4edfde9f8c3ed7c0733d5a73bcd8b349035744d5eabbad0d19801a678d48cec84c0335346af33 -a3d0c32b5e3036c4a4b222c13f7db23924bc2b2f724bd908a38db3b8f9c95cf5034c4cda0c5083c0967d34061a216b57 -92ca6b883b2b20015fbb56cac4c4b5ef22e555a9b75f4f020822fba9167eebff8f9fe5c729c574cfa5ac27bae1a83fdd -b72b58d6ddf54c2d37bdc1599ac966c54cb4926c8d2f70d1bd4cdc383c6eec5e4b87efc59466682f8db964d80a4b740a -89ba63ee57a1e6f13d7c66150a8d6721329b385eed92be3ea784eed89c76a1ea88595725612b109a9e4aae41d3f6c972 -8727bb53bb62fb714e4e5de461c6cb298730641e38a0b49b3b3d4a29fa24167c7c6f4ff47f4f3b91e464a581a4181853 -816699bc7c3ed65747d34786b7fca4e35e79907f459f2df0918669adee54a70c03580c4e7d2e410ceb45c71fcadd44e5 -979688c14ce623dd17344e67373e5852bc1d3ea12d37f7b28095e5d578d8c9c646e4b97a3a69a97764ed0a88f62c99c7 -b4539a9eb6578ed3b8dd54cbf57419e99b69c0ae1ca3ae3b4a21f204813b2a78438d6c72f86c13dfa06a0b9244b98688 -a5d957181c30701fe6eabe3e65a53a33dc43df364c45f0c4d882ab88a069024bf04b71015f1c2fbf03f368e63bd82fe9 -b9ce9a54d9b17d4da41ba3135d077c546cf39dc83230506a4ee88cfe39e76f7e35664ff1b571e231054cf1b764b9267f -ae6bf2eec8046137016ba94442a7a0aaed0924ec1558885135fd339d2996aeff31ac29f1de07e84f7b7391fc5355f429 -85c7c247766a4ca44278be81752f4170dcc069f76992b236b40e71e31e08f30de6a5ecaddc44debe4f94151cdd8d735f -a19d41fcac394b750248e575c300b9a96dfc5b3dca07ad6e1d68dd3f8ab94d10aaf8edf500e3fc7774e7ee52935f73ea -b3c959a22fddce5a2e199bc8724e825a6d9776455c033299b5cdc9a9d184be169d807829d5df5e747476d172b5701cca -916aa7bc58f34bb8f32808858cecd3e90ea26c3ec1f80a40e863ba18fe9af6e67c0b2664a2274eca6d36ed72e59a9341 -864d945b7be551926f747406d72057c7a141110f5d269fb6657cf347cfad7178670dd294f6a98c19dc0943a68d7ed45f -b3480f8a42ba0e8eb020c2e1c1284a8a9102fa68b43f6eaf28e031621b9f68bc399899e35a1a283fb52530c8574484a3 -a8cd1cb93974d1a6072ed51f356449ac19b04539517cde34bb7b2ba55949d213ee07d387ce7b5534175bd8a044556ff3 -8e81fcc5fa5579f2479011caaa393f47a4e12828e2e82072736d85ba1bf70ffef9fe3b2c22fd11ce8eaeccdfa2579758 -897f935b4542b9ccf8c0660c8fb1a570a8ba108fe8440e17e6c50e01affc2a8597b7f7cde5244c7026013b52c7331b5d -b9a20f612c74821da05f48d8bcfa7a4a550979e35b49d52031be8bc9cf717fff21db0142b633465c5edafc42b7c73c84 -b88caeb2157d636fe26d3b221143443940427e8722596746bc337679e10ae6e5a9b33c456ac271f8b01db2f5d1b00a62 -b23bbd978725aae647ca2778e801235f605dde17897d4d56914b0d2241eb31f930028904a6555581ad5b2b74ec3c9587 -97a331ffcd02eda1d6e0e15deb110ad6106d3159ea641cfbf424d2e3065bf65c9b14f72a27ff3f576dc51eb068bfb22f -a9317840cd8f437ea97d80a3f445a99eef463a5e2beba3c986da8fa67def4ae9a0e8d1a675a35e5616ee90986366bb70 -8c26dd7451b12c65351d5ede6a00ac7b9316f9e28be8c692d20709c3b4a5dbc76fb914667a2f1e9a654f8d2850b7dc3a -8bf4aa18a988f82dfc54668bd4ad5161f276e31567c949b7857cec331c74c6b68849afe852892816c802736cf7c547c4 -836fd166bb9689520cefd6f23905e4c1260f97167b17534930923107fe934d4afb1216e4b89679a564433dc952a77b0c -94d6a5a4a11f41887eb814acf9b5a031d013d614621642384504eb78e65b6a07c50326632af47b408d8ccf43faf8399a -a213812713128750bbc5311dc317992bfb5124fa067072891f452880183d64d6fdfac8825552cb809178a3f3a641c9b5 -976d1290308868c5e41dd3766447b29ab8c3b72047a0b7de85d3ee5b1e13d522147a02572cc0d1ed8976d411faff5b9a -82a4494a95738ebe56578e1e4c0e486eea66d5cc44141f478bfc5a6b3ebbae6f32063725284df81b438603aa564a2b6e -8a6f4dee79baf71a4a40843437c16b2f304785f3e56b32d9ab2474666fce2c7749c776bd898a65f4a4d542a497cb6d6d -a04a3484be07c2d60f1a90f9dd8d4170270a808cfdb863864377c2515dd71c152920b65fcd5f47004d27d14d7ee7eaf2 -a984f6633ce3d42c75083ef7732e5d0ea15d91e73cf893be3ebac5e56defb8db97088c5cb3acb661e26bbb354ad91ce8 -a5ab5b4b0dab86706d68c9ad921d4917215c4fbcadc8adacef7309c0c853bc3c2ea34b3868d8f03cda6f504793832594 -88f03e55eb028353b70352dbe91f298ade322951ca115972f1207744254fdd01ccf899aa40ca747da8812dda5bd5f985 -a4bab627f7de273f8085169cf05413bc368c5d9e5f58bf10995a8bbd95e511b1ce15d008405728ae8e8a83621efb56f1 -8ed518d0f225b90fe7f01b0fe4c451589390325044f0d18a8c47bf13e24eae8627feb0c9e9514397536f73f33f67a044 -97c73837e77d965f401b4e4f089ef4de7aed1126bef6be4e9002b2b68014b98997213e492f7aabfd2e47cd0917a11d6a -a99e8a55ed0385bd279e11a80255b375f2d59bf8b0879bf2337ab5e3be450a2ec05d1bd8867a633e359a02cece4dc1e4 -82a74b5efaf3c217ee2bb56c9b8e76b3eedfc553c73177e59d982f503a5b0572b5cc0d1292820823307eec956c42b28d -9800ad3e10e8a19d65d5963673c183bd536b65e14ec18dca45e881ff3bc74eac32bef2ef845515ac4fd6caf558a6926b -a2933c78a67cb40489ffb8096c021ca017b99feda1f9c5d702227d7f0a2ff66a539d68a47ad90ffdfb5c31c774946f87 -947b29715258ca20da5b17a8e3d99665b7e599aa5bcdc5d2d7830a2e3cd78364d51a3d7c0d8bce48a1992b27d1ac4980 -86f2e2d3e160d3ff979ca70c456785b4b2437eb64e58adcb78c4aebc96b470f1b8b999a3ce8ce20e3d3f030d163cd138 -958f4435d35932a91eaad0dc476bfc2761a85f336ad2ca6fe0c6830fe54e8f417434616df9e6f07a9454a4403b00b64d -8b1755af961e0f9f59651d56b538ea59af489e859a1c93726cee62649da0e304093d62db9a2c5854c8da1be61bde990b -a5e11042f73f979c8649592f6cd01dafb319344e379a65aa9200d3b636abc569edf822c2bc12b3db5c30b9ee74f2c981 -92ac5584de1adcd38a2ebe361225f224e9b498344521be519faff77f87c1f22fe8e112f9df7cf960b16e358efca0db08 -81db84f05f75a218045d7d5fd4620648bd4a95cf468cbd69787011d615778ba7300b729163e7c8abd1a5b0ea66fffbf7 -ac2f522e9f030a7c576fbe19041f5db3913af58da75b87e8ad64b93bb34850a79b852804dc68ad5e7de66d90878544cb -ade9763d1c7e9f68b5f817cdfeebf31bb3ec1391dad04576c55fbe4bb13cf0d45abced3d51b5512c73b2d0f403906340 -a0b431bdd9641595fe1eb8d96ba4fe86a447a31ccf36cd2f7d94c5c86a7d96bbc95b204fcfe7c69c1385997b1daea3b1 -b3b093bd8fbd84414609ec9a108507f97d7f77833b93b15439423d2a2928e40b192247c8471cdbc12891d83c765cc6e2 -8531a5ce8e0c44e887ebf4beac65352c8a9673c51b6a1edc439e08bda1354d359e1ab2e27b82636c6dc0daa3aade931a -b22c2f3a77ae4813a75004dc2c9593cb2a51c430c559bc7d07d83e95592883b99fbd0f9ad24d2d80d86c871cfaad2721 -8b6dc7d5b8cb6bf36352fb19e42aa37647505436e1442eb1f228b0804916d569643102b2282ef66bc9a4442520521dee -b29a811ab81dba820242a990dc774cd937cd299495cf721cd11971b9f1dd9441ac687dfff0e91656b9764963a56e4625 -805b280e31664008fdd874bc38e870db271027da70fc2246fa82c499742a9a8de1152275e0be61f307dc8f7a918e270c -929f690538a500d238208930b55caa9c489bfd3476f6be2d385c36df3159dc3d8bdeb24a1ffd7b028ff4d881551e2888 -a92bbf103ad851a41e5230e1e37ec7802e08f4610c0db9706806afc4a247679b9525f9a534c70d970a1acb47fec9bcdb -b9f2698a39d6d7aa8aca181fc5d95dec796ed6eec002557d4b63369bd90aa4438c27ab90da4f3ce81168cb42f7400070 -b08703bc97292c56833d8e61105f1431c334f98a7946850c6175f37f703ff790d9a1522c0003f08dd111eeb083235073 -9355141cfadf46f37afb73414c8803f9094b06952c9fccb24a1f8c18a13fa7b1197321b19cb832de3f83ebdf8deee53f -b7c23f7cd8e212108906b7809df90db58d2c2f3a8e1f775274181bd81c74fd7c2f8d68bc7d4aef639ff4e19f86243f98 -92728e009fc3faa08e81c36c268b3ac18627da7618c96c97598b13242286645789c15c99518a07e658d92eb8d2b89c79 -8fbe36d4f2f08cd6245e8999728884c636a264451e4ed894d2116375f3d9eafcaa72ee59cf7923ed8ddacb53cc478761 -a6b2bffd6bf8f54231fabe46ab2c1d014ddaa797d08e5914f13988140bf804019fff3ad07ac2cb31283fc3e74e28d0fb -886387540b5a7acc8b2bd107124bd17d6515697e09c85c4e932a6421965c872f014d11d1ddf321651e4b3564eed4f252 -8b81f3ebc962e9ecd13a11e919d86ce14dd89d373cffa158b807fc91555a4ec1d7164504fb67edd9599b10fac5e32aa5 -91e3213ded5f82e34389408e95d4f7fcd0f50ecbdef9726a289238e4159c6d3cd2f401479a1f785865e91ca213d2f8b3 -99154b88ca5462f62031300177e571708821348e1027cad4867eebe42a6fe92a58ee1dc21da9031002f1b051351b3785 -b5c2b7cfd87f2f65df07b39f8a26dccb16946fef6b89268b9300c8529d730a1469ba565a480d7c5ae9df8600ac50e90d -87df32def37370bf8c4c3a22a670bf5605c78f240eccf8dba13bf19c8a3a9d0560f8899259c4e51c6b0fa64d7d1e4c76 -980a20e5cd352786bffeca1b8a31930d8898eff9f4a6b2570829248410bbe1c78105b6a61cce7e3ed1642e5e2af127e9 -b18b8dbb9eda5cf333ea29fad7734235ac9e7234b49fd04f178136b15d97595d5b415a92455a319ab594b81200cb17d5 -b713a71be9bd22ef6a2747d0bc8f4d008cdf6182e287c1e0274689e915a68150d6083268188c1f4a7fc76d21a219ec85 -b86ff129a981359972bb793a81fd422e0b37f89e76fea70da012fad160b9eb7b029ced81c7e34679f6897a45b4e8da4e -a74a4cb9707156e21caa20b95a2a4b4eae8f773cf679e2073fca2cd3b1e502ef06de8a3c010833d525a7f8bb6bd24601 -b51f06da38a76c2728cd01f6073f402fc49cf4bc5c60113a2700b5bb0ca500e465e541c467013a2804bd7641604bd2d4 -9855dd73307d8671b6f9ebcf676de3ab7e37e7ac1544447c7ff34a213da46123b57ce23bb0f381da8fdefbcbe6c35645 -8fb382c63f4c935462d013a0d3e2321d72fb4781c10afe6e31ac51766832218a05addc6dbb1f644aa61b5da9bccfd5ae -855dcff23e0ebbaa3562fd27c43957cfb35d492837aa71f27cfd1bf65a59a12d2beded9d09f3ddb4f801aca8cc34d2af -b7e7b317f10cdd13bc879c2fb0bfcd137af23e0cb70917e48d53b2bcf8c157ed7e5f58cdb966383ece9d3a4c92012746 -80d2f84c39422afcb449aa68b34fa9d72e9de79a473c3ea5897f6f3576d2bb6fa2d49f0b44aebe5e68b11e85e066e028 -a35b083749f8a5551f0dcf529e845aee189cdcc6ba779f4e88765adc49cc4779cdc2290598908ccedd8dccfdce29d53f -a30c412f4bbc2de80fe5c577b4f94442255cb3061a40649b0ee5357977503c6fe54821ecc8cc92d5056b6977c4695e70 -a2ed0d90ab612fa3526f7450a43d45a2d9e886f2e5888ccb8405adeb8ca3e41c6a94d18a54b3cb1eab5b8f3851841ebf -8d4dd3f8f8a3d69bb217d338e757c814eb69e6a776f55cf51fa7c1b2f1ce5f8e9bce8353dd335e793d68eef676cf7c36 -880d1ca33d5d3bb47b788a7ec64b9130752610816facec99af53b6e58a7e414616e9c815b1bad870d426380085f6b5cd -a287578293da4354f2c3c46d637aa77b91526f9618799dec4bc602305ffd8336d373786eb67eef01dbaab88f07f292c6 -a86d3fad257a64c84954a7530822346da0215ebf4ad9c583f35cdbe16a02fd70d58ab34c93681fbf55d6075db6425cbc -a7bd884d343a6bde5f6c2512d81ba701fae7afa6389389e4776eacc0698a54c3ab1a0e1652c1a7a23d3a1d2a63cde8c6 -8e0653c8b7279d5c958ab1b53dd77b73fd30d9781630a870d0a75681d38cde4fb7c2183b9c5758596ac556578b43fef3 -b76a00c6f5093e7b28703df85bf968dffb70c455c91e75cc81189598df052244f7549d18e45dc70d98d3d86e0094ab2a -b270f2ad3dbc8b43ee2603c4e641be76820f07a4757cfa96be2be9c310b7e39b574572103253594a51fa9243298cbd94 -977b8b86841ab8be7d1d50da7369e2bf71f24360aab8448d7748d59e010ce81bfe79530ee6f6644b987fc0d83df3ed15 -8e18bc59841b7d56f8d9eff8818eee06288cd6ca86200eee7b5e6b230070debaf254a2198b4cd7dfbda8a1d55a916c8f -8e7a328ada969ed6289972b7f43eb5958d23688603ee6d118b6ccd8978378dce2d733ff64c30519b19007a78340fafa9 -98a0fea70a219292584c69546d6d242cebb2f1d84f69c5aa275a257a87de652e721078b983ed67410e3a5eb0cfbb2bdb -a09fbecfd05772a9989008281a9585accba3850831485802f042413da533b1c7ee45a8cc679804340bd9142b2f9e0069 -99890a6b273a2787fcfdd8e8500134efd60df99410e8432664a3e5325e55e78942f4bb11024c90e4c3618a70729a277b -a5f3eb1617a77f2d5c76bbd1bc3546ad1628be90fafa9a8b62c605d04e599ab2eb74b25afe0e68fd020daf4868dadcfb -8b53517d93f42b833f7669c131dc67f14c3b0639c46d3b02bfdb24cc9e642133e0c665236a7ba851c100ca733d673341 -849fd288217bdb154213e79abe1a78672903e15429e37f6846019986e1cc8dd2b3ed28e4cb52dee1762a4dddb9ca95de -954d839198c3dd2ea1ffddf98050e2c52ee81b89f38d967bd30c6863672e43bfc32e1030bb12f5aa424983bfa31dbf5b -b52fe86414a98d0896d7a427d57739da35cac4ee24be565956d15a5c1cf5b4b95e5425dd2607fb9f6d6024549b59a4ec -9586070415a6bf1e11304d2819330eda88e81a88b9347aa866692c163e1af772be9fb747d9281d7aabaf5c9934596934 -a5b78e5bea362df26a89df682df61287763ca1b87ab9618609c99e52e6ba047fba7ec828c0552ee26279aa8a48751334 -aabf36b9dd465ae03551dc82bed9cbf1d22a2236ded28964334f7ad474f317f4fb8515b853354bc06181fc9af82714a4 -910f0b2efc608cae8cdd39df7a5ef9e570592b31df2331baa7721708057188ae96e1b43e2f2f2c8cb360b961d687b60f -a5c5b131205c21ca68d6103f8499279621da337a743e4a08547c3b4507d52d2d6e5014fa5d920b351a6f53a195687766 -a6898dac2d8748b8bae155a7d8c169e7eded73cace1e382c4dae8633f19463151399c5cf877f8ba344a698a98228864e -92919d8be671b4f490efb49bae145f419c84a1e81d3ef78761fa326f67d749ff3530f5de04f984a018065f42e852e1e3 -81083de978e025f0b5995550fa17915d02489344cabf8a79248352d78dd6e893d28a5c5204a65a8873756a34ee3c0120 -a6de92ecef84d188cefe29a03b564b1e7bef2a6afd785b58897f7f97a958573a35aa0767bef12a49b352de30b4f0dc18 -985cb3475c7a9f582c11784cf61a1988240d74e49084a4c0f55f3f6068c4da0b08b136f8fa62e9001e0a265bf65fa3d4 -97e6d360b504991d51119a78c5b647f25d5fcc1298631209d82c2ca40ead0380835fe3cbf8b82148b0b01b8157e884e8 -b313df44b2c47126b58064599a0dd6ea49e5ace9ffa663de03ad30c1e95301cc68eed67d37ae6238469e45124c59bd39 -8a58f70545db2242cbdbb12492cc11ec4d2b2ab0ed8450d21ceb573558d7bda91ab03c98736e13d041bcab84fd8248b9 -9077880ac352a5ab0e5e15ac89b14d173cda0b41b6f7fa66bb357195f10cfcf491fad6bdb49d71cc20d99cc6c8e28d04 -a09b2930fb3b1a60af8c5214e8c3f6deecb3fd3d0a5662f3885948f48d1836b5ad3dc74affc54dbeb5b522b90a17dc4d -9163bd2e5f58fb1d81007422b91147685542fb1c7e2c8421af284c7cbfdcd2d2b399a37123b58a2a349f27b31bfa47ab -8a3d859f141457f9d63818634f81deb5c858ac48bfbf2e1da21f4f0dcd66b3e1d2d8fe99c4cad38206b1e15dad94934d -86d3fec476b59782d0477ff333fa79922fb9fe3d6d6b6c5be9da9e88b006b46b2a0f8f86ba4159c5085e66e32fba67a3 -8041cd57335bcdddd37651de2c3e92edc600ac23041d0e383baf55651b1b0960b6a601491608307160f0d7d48ce395f9 -805c284059f8c03b2bf006b1af95ef726874c5548e93ea965b402931f42b189f9f674b6b52ff09df35320085172973c5 -8acf781a0b40cc56b1013cc1fc3bc43036545ce35591f3b905543c09cb1ac1a70a074202b6d5ce3680be913200c58879 -ae670c448996156c80d063f1dfb03d7770201a35c71cf8e70b38d52dcb5e2bf73d5286d63ba2f561525d62cd67d43125 -b0fcd0150fc0005ca438d6b0fdd6a70b121d35ecd74e62bc119bb0187cdf6bf674ce9fe01eeac5d46a68ff4d4210ad09 -b752c6850985ab13a057028887bc84674697c012e9da0265dd5ce1e48f0aeddce5e07e3e7cb68ae17a648cd1207eef19 -a6a5c71915a980fd0225847b45e2e9f3731c6b2a627cefb1e2c6a0cd7f1d0555dd32b6b601a7ae9cfc4b9d06a56a578a -b7d96f59a988a7a810c25018f7f85cd6e81b335a84504ec76c97d7257f9cbfe88215ec89553f0dbf39507d990b3a7f84 -a7cea7b3ba43cf6ecc488c34511b17fc7b97150b2d265785c09c676ad3123b322db32e043c5961384ed6d90d20c63061 -809dc467b304e9bda732cd92b15c0f9b363cc707432788971508b8d60844911ed4edfca96d8cc20b9874f1e38a2d1685 -a5b6a089e022fe460d62c4c5228e1381902c9a796ad92c03211c855541a7fe27c5a39d9123b001b0b892ffdf0a1fa065 -95d67a21154a49bcdc79ed5f2773b651c81fba1ad82bd373239f09a67a50371a147310623fcbc1211ac57aa154e8b300 -a4a4f0ca8073407575dfd5d04ebf76f8bb467598824f2ce7fa74756803d9645d63c9eb3ed39aa202dabafa4ff0a0bf34 -8a77374f6e449d94a443f2d4593a0c3e4925527e0653e873dc20756396a9a4e5696fe44fc1b49e456711259deeb3f037 -82585a825011d6eefa85cd530685b103862aa0777510d22942d8f77a0a7f489f5d10e5b36ee38f66cc96dc57d13f5893 -98e24625c31d5d97c789eacb91c3d51cc6edb38cedcc474deee459f55de557c42e4d0754ca4ce472d0123638eeafb55b -ad4351c76d96c35ee37362f2384ffb809bf6a47213863330aeac1ff9be2c6cc7275f0f974e46bfb716a89ce1bdbd0710 -afc8f5af4f9c38ae672d20e7bc3796aba23a41eb033619b4c0a06e07884e1e0c7a7326f069068dd22e69fa5f672efece -983d5af05af31f9082f381378fca3526f88309bbe51d0cea5860813bb0fcf6b32a3be110336bd728952dcd6ff8a26361 -ad3b55b67b64b188447a1fb10d027bf7f86ce0a0fac966d709e8b6ccdbb7333964045f0c4719c45c36b7f3c9ff73944b -b410fde230d8dd24b9f1bdbce8338b05110b130591913f23a34c5fd092cdd3f747c383f6967cdb529ade1a264a3ece39 -b3e4f0a046f93c332be07058db00c5182a498987759315bcc3a58d9334e09a59333031c3144b59d03596925703491cd6 -b77e58619c8c471531d9b2e5dce8f82bb8794223bc9459599a911440e64e0b5be1d37e289807733ddbc2858bded1c34c -b450945bc3e290df96a196083a45aa929ee080bf45112e678eac0a939db2ba67334ef782c855b9b354caccd94b3babb4 -9794d81e968770a6e12add60b32ccbbe80cb2680b157d125461cc3db998691e836d98cb3b3cfff4f156b2800d426b955 -98d1284b4c035e93b4ea0431884d91d5a7855ac6c5b1ea2a994e653cf77f0ac1a771dc75899bd1485066da17e40ee341 -b1da89b14efc14d15b2bc967ffab85c41dc447b6a7922b619b5d5b06dcda725bc4530959b70355ee20eee7c1802601b9 -b8e50ae98515dbd9ccaf27192e58a5c34def86b1d0d181e63e64439107c30254267969f6069e0b863c254440c3480de3 -915f0c7dc95f630bf1114b02e7d9936b0911a69c932950ecb7f800cb1aa1a4e1f1b6bef6ff4a23301cfd904c39025863 -85392fe0edd316031c69d90b106b6685bed56a0d8d814db2cd5d77d07b18fadb632694a214a176ef60aa0f82ea14b00e -ae4cdff23859b7570179586549165c728de4ca254a5da29668cfda259d43a387b3caea8537888d43f713d458da6bd4e8 -aa0b6a3e0555d64a5cd1201fdff7ba7ff3019e9ada1d86c90c626a710df3d97d2ed62d2b63e5632963e09cfbedf83732 -add726d97dcff922dfd748eb897e540a2b4b8bdbb4eac1feb74717bf086b1760a957f83586a57b5345bf4c73d791ab9e -9721889b6fd55cf9a914e5aeefdfbfb94d379c6312001ba50ec4bb1dcd03f95fdb45041330da8871cf3dc3c6a6b5e330 -8eb9417573ec6af24a610da5260639efcdfc802a95aba8efa829dd70ff179dec061da9facac95b6af02cba6a8646f7bb -a477ad7d2885e1f081556a98b3904cd75a4ac7a8c27fb0ccf15d117feca59f891a677fb4ff4fbf38203055a9436ebd1d -95b3b2ff92e8a0bace130d165984966637a74280d0e056cebdefa6f825b1d55c9bc6e13cc8f263e657dba3dc7fa68627 -b096fc33c038b425a7a922a4274d01eb366a488fc969497a575587ada74b9452a607992aa2d8b9de66705fe20b4abb39 -a813ef1053ea6ae8a37f4da722f16b6ad0213b0ec7829998362292aef68c28357ee27a406b567a629592447db8ea6085 -84248425c3201ed389fa1b64b9e1d151b5a6f5fcb8f5e28ebd665db57156ecf9b2fa77bca857200df9f54383b7c5eae5 -86d0a3c7fa1e64111115469ed0373dc3dbd448e1098250e9e8c5c7e775fd1f267d49b4123c347af07a28e686d5f357fa -8340b2ef4fc2afab3a3d51b6c0361cef4aec3d5e1d0f779f9fcb258711cb79ba4083508644e2bd182fb25b21523557c1 -b840749c259b5af5874750853b4de6f4d7a274e18fb77f774f5f454c82efc5979a431e28bc8e43bb831715c7fda96db4 -b168d333cf20b053c1b2a915c3485200a7590c3c3661507990390800fb95d3772ec6815d53aec5e2964eaec19833e787 -8f1bb538dd5005384f38f88cd2588228aeb0c6313aede14ccc12affa9715cdb938ed4573c391572f0a7ba6e33a1ace89 -ae4a8ec2eb938eec00e6608c087471128b14a773d75a99634671f6fed95f7b24b14f04b3271d1c32faff7f0f2d98547c -a4ad66552924a6831b657f8b318f303225b2cf29b09790a48285b028bb1420c56dfa2ca0df2e823f694e8e3b27952a01 -8af4eed962eeff534234d7c34f1033c68e8cf798c99880a67eabf38b533570a3776399b883f8658265cd14277b060790 -ab2c6406132413cba89a951d919bbe123fe4f220364ec2282d8ee0c140ad8d48ded0df7ab56f8f18ec7526ea2f1cbbd4 -9154df8800e26020155b98f630e640be97a3ac41b182fcdbcf31a3e4f233810e34e224c97df8ef0f39ccca29a9921fb5 -8f306dfc5b8376a88a104cdf67eab54f93e478ca09036eb780050ba2e8112b400bcc09d49665ab37d21b5a2d8440b3c8 -b768260e94bbabaa527b2af8be423577cec3bf4aec3c569a4fb69e1fb997a2157c59f1169065d24a8aa3625d89d988fd -af06139ca7d240f2495314d941890c078d504b2bc09d98a6156c373de29781e7581f33adfc738650cad0da3f6e07af88 -849a6e458ab2f4101167cbf75bf47ec1f9e481f556b1b9d297a6b4737584011d7881695bbf3ba31e3e4180696fff6407 -b107e7aff27aa19a4a92d1a65679bf40e85ac6f08d4e5f14859d97c170ceb431858fa4c46d00131527c605164b5f7bfd -a00666055e18f34ce02e8b67b6f181327ec0a11547c0795bee61802aabef9a3a76ea138b905cebcff9c4c86391763e6c -a65cd8dec5166949696dcccf031c300895c5fdd53709a1897c61d795dc22bae2f7717e7ae52a9950f9d00471ba6257e7 -8b49aeac3550ef28b5de37576a5d4e2e43bcce82de09f491984171251e26c27fd0a884daa6f3d30dda107dde4544b34f -91666b88be09799c7de9a5d9a9d4c1bc1b6fbc44c664adb15a2eb27229be910226514c2ce22818fd38b850c89291a7fb -85abf4084c735b20333b1c2145571b793f96188850bae161160b47dea7c48b0f588adcbe9cf80e05d17851cfe3400f1d -aedaee73c52d71d7ac3854fa41199615ecf49cb0c35d8203f95175d1ddf565499a8e9cb8d31d89e7cd9cb75a9fb56f9d -9413589f0746d3b81e2f88b280e354fbd63ac164369dec353e6259a2c4acc6bbcc10f2a851901f39f90da7e523d77848 -826121abbcefe3ad431c713a1a2cef336a0f06f69980a14d0a8adae5640e9aeebf4eb82be4621165ba32ce5e16de4880 -adbff68221279985891e9f3fdb7b1dc71db3e20213b7c8e1931e6f75c6f02e7a1f6f05ec0687885de55ac85440f372ae -99ce8b064f874cf028e85281bbfa43145893f80a8b12813d047bedbf88699266652de6ae9e4ef9ce575e67065854fdb4 -a809a71a663b0a9719c0327d33215b63c6ebb12da3477da8534d7e8f79fb81e06adfdad79686e40efb2c75abde559a34 -b26c4cd057118f9b12c9b86e77d370b3fdbf2654a5d80a7763ae98c68cc2769a7cb293ea89b3a08250c2f699b8d76e22 -867c56da9a2ed672f47924cce82c9d7e801d6a1fd18cdfdbbe07c82091c70ba0ebc6008b0b9d505632a97aa23c45b8c2 -8cf14633888f2ba0b02fc8ca7536f39fa290678c7e0840c58c53a9d2fe10628be343a86acd74b2fc01b0c03af0996f59 -86696802e4f27928dd6b0287d0188f8067283496d154060383c5ee295a468df32a2e8e24648d93ba868120ac429b68cc -b15439762d0f7b6c98e6946b3c0a7ea0521845fc68b47fe9c673194d81a6cb375c79b0122e81a027f21a7fa4cd6bbf56 -b1bc19c9a3756098c02bfe36429c0f0d8166a5c9274edc7f80ce65ae7d6c67864a457f19cfde6924d204b81f2a195fe6 -997f1cc78d707f29e3eea0952b5514b34c2cf0720f33a3244cc466df62b13031bea13df2296270eed42b3667c53d6c26 -94f599c9995caffc9b47543b822dd8f84f921fe2a31e82d5d0fc79dd93a4da0b87a0906b82fe7c2a8c23c7829c21dc2d -a7fc8a6ed802660bcc07d3ca454c415da18d798719dc2688eeafeb8971910377ce909de68721fd97c4d9fe439f37a8d7 -ab16f93e6df2464018be01fe040fea08c67e0b032fe1950fa37c7593c8ecbca24dcf0fdb9e1209d5b0def622f3f6e92d -aeaf19b49843e3fac538075dccbb29a63d55d12f8c4150185b1ae62de778c983632542eb495808ba629cd4cbd629e07e -85614d537efaee823452d0427ea3a2f7d5a3c988b10cf7adef8715becaa519a9b5174b63e401946362176dc0d65667d4 -aa08d8365e78efc1919cbbe562be7b28c57eb05c36e8da89378cfcad9f21e134eed923559530aa3f62bec758b00c70ff -b4c2760454170276885d66f03e9fc4e6a4254547b04fea3c233c11dfbf71ab05dd755b9697b442ec419aca000152f2a8 -b814059b189c0ed46f9dab604fca25d881a12fdfaf834a75cc2c0e1d8454ce0ed9f2a79b34bc5e27004903a48c6ace90 -847707b0aeb4fe91c12ea8570cf0d16caece8946951360433c8a375a69fa4c01136172ff2acab6d5164ff6d3b5340858 -a7a9304ecc5ff6fdaaba6e774556bcd7c5dfe8ee7580a677301dece55c6a8564e7c64b60fc4efe89ff73954f3c3f5b0f -a1a86fc5648edd58cc7eb61cc30c62edb5314caca5551ffedf088fc9c1b92ec5b487f670c5bcd2127067e8fd5faff03c -9086a31715283fd525034d59d4ba3465d6c30059b967b1eeb7d537f3bf8caf6879481ada2849167e997212f3300f8ff3 -99c11903cebf722e1cfd63a46b0ae93312439ff2f014b6653fc61927ba430c432b4955b30b7f078c340f5aad4ae24313 -934b7a8b7bcf0108ed31d35a645d73f661c064a6fc6a5d1ad417ccf1b8864623b0cfb54707f10baa86643afb5c5ec980 -89d5a69ae8cc18ad77995ae92d30236d5a5ef00cc63274e318d18abcf9d936453d18a8e6392b52d2d66b51c18d904d6f -ad2448cea1948f0a4915ab054273bdae33a08c494203d11f46888f852d0abefa310b50367c80cacfb602cbc249b31a71 -807274fbe6f08c332a5d2e2ae12cfabccfb53511b8d83bdc875856cf15ab52c2d01cf706c9be428307ea62fbfd67f87a -b2f4fee9f32c0ea7fae306605b62d983b130e4d423e2de286bf9f4343b79e5c4545214250cd1348402d8278140c61c00 -8a36f79ab3ee0063098a39382061ec3e1234e67087b9519d0b762aa9cad54a7e0bd5d24e2b0a57a690993e3182f3e83c -86668e6743a7b6d1ee62e70e6031fc8639ecffed38afdb1afb41d64ec402a308fe0438a22387d9b0c130ed301c39acb4 -b816309d1730cb39b1ab00c5333c6962fd5f5d8b22f3c3ba987b1e0a0065334d206141dcf0e68eba717a4eea533aa6f0 -8754e190b8f751aaf9f8e7076d21bd31db8d9ebbee6b26517b190f624b3a892050312cee9d73cf3d7245446c6a376437 -87826589ac28f442c608faeaf3d63ff057af7724f9d412d1f2cce8c58fad0adde325aa496c6e4e8441775c02d8a74c2c -af30e5e32fcb17226edc54030f1eff8af619c207cd9e42a2ded7f15cd29fe52f140901f0925ebe4e997b56f34d3f406a -a62a4e5b6591d336744481a0797eb23ccd0f580d04cfacbb3e415ae3f273761042b8901b0312f93a6eafc42a50f81cc6 -968a9ccc95e8c124f4475c348a33ad2a52a42e191a93bab3d7f0d211df999aa081efa935391a8289cdc4a5a8f7433822 -93350cd99ab7d3e51756eb01c89172cb406c1debd3f0001d2fa8a01018be5609d73df671e1ff43e612ddbfe7076d9ecb -8df26dbc565ea7e758ce4c2656b65c1f0396761c9360d7092d12c121d3bc1c293ed28d82f1057f4eb5375b15443e9258 -80a0dc22fb4a12b06cf05ce39f76537eb3db9691ca466ca89b2585237c03d13fe3fcd311ce2b3dbd1b7382044b803782 -818b79cab08e11dff3d55bb0f55333f6340c5b462609d43334c14fd878b0f310b77c542c74d3674a94c692de704e88a9 -ad1bda19b1bc3f6d757fe4d189ca82bdcd0a9c1ef509c43e3f49700f84be33bb9b8b8e70f7a09bc6bc00a78cad0cf9e0 -a22ab44c676ba2b3889341fb137dfa14cfc5491ce4c3c1fbe2cb7103fdf720ff2b77806a40109dea9a68d8f072e1c167 -8eba6af1659b6145676d3663b04ebe58c199a1c24837ac4969793f07ed97165d20bb0410421e561cb9283faafd9eb51c -81b216cf08a29dfc3e16b2865e712e15f494b914cb24526a96799a3078f200a3fd403767119732ca4de07203b479ce8c -a023ac601c8e0c22553068ce4a7b8361b0b37bef5705fa68a71c3cfa80510041cef3640bec2cdb4f317904521e99443e -aaaab84c8aea75303fec31694114b3ee10fc1a67357cdd675ac9d0e33c3279e3117d389e9ab017882d517131b14e6088 -8bf9a44b3df3d7e0c776e7ea5eb76f16f1870960f32e7c5b63aee9b432a0adeebbd378c574ed60e15a3abadb409376f4 -a93faee621d930f336f4fd952954ffcbdb261c9dcc4e60cb848362223374010c555a73c0563e7933d1596b0526bf75cb -88753d0e35e87f7572f2012a40bb757364af5cf6e5dc0dfd16d082e698d3fedfab3c671bd58edbf11cedca247e9fa55a -b7de5f03681634991d2aa8a0ffdafd223b1a0d1ff70fbd9c00d03f228c6772d93c388c02045461d51326483af97bca37 -81f96d4fbef3cf00da423a1c48ab8acc222016c21f6be3df778342c1d1aa1a420faa8ce906bfcdf955be045efa4b447e -8dc75ec37122afaf0aafdbea333291ebb735792b4d5934fd16bf28b536fa759dd851e1de448c3efac3d2b0097e0b349c -9186f66655fc1c551d0233b761c6982a3b8539085ca9a2baebb826091e179026b90f7ba6a825f38c6a09b190a31bace1 -a1cf319c9ed31ffdb2108b684bc21cb495e77c853e6c502e03f2ea08e88a0c2b4e31958004d9879242df420b628acd8f -b3d3e5a75c34640bb2fbc7b62f8aced8dcb4b9b165992717fdffdf765bfc81fb4e67f3e737e6f70f24d3c24812ec0ed2 -86ee6ce0480f73cc89ce7959b4af52351317cb6406cc368e889472ee5567e8a98560dc1f13b87442c9a8c5d6b31fc446 -9478256948d960e3148acec3487da232fc2ae6818ac2c6eba491adf130c55badfe83f9a519379fc5ed0b63366de86a02 -898a8130718ac6f98ef673fa8b725af6012ef28be3f2320359a5c2c40e479969e5926f1864624ebec10f27594b24f618 -906f45d4ec3f647d0c49deb95884629a04fa65cf91a075bcde67940634cdc98f76fea8717fc1e714ecebb337e9fd6998 -874c5a55bca05fe52a5d1743b8254b642431b720eaa74f73b0faacff2225f448ef94e12585b2d3bcf12c140ee3e81510 -96f76cf34b14263a30df2135131dea00074f2ee853677b94fc32e04cd9872424dd93b32c55026b89c18bdb4e58bfd19d -b62e2ebd543f3e9a11b72f45275cadf77b1033713625c7374c4d2284d63acaeb64977fd2fdc90145066146c311a68737 -b1759d3b667af9f15da8d4e77440fba4193d0db159a0bf73df32215b2d292bfed7cbaf41c07c7a94ae1f04bab23cefb6 -88423607f005af97b5f8131bdb1fd6d7cdfc4c2da4a4a14bb818b3ecf50c2ae6d3b8cf55e23632354537f5c0dcb0f48a -8ba63acf22ffc1576935467af19f555a0c27a4b56e5bf752163038f0010fbdbff8a2131124f4cf36a326dfc188740e77 -8b1996a0cdac9c6d896111671ac4dfa84a3a3738c43db6d6788f1a7b8ccd6df16a31606db00cf0107eedab28af05cd7c -912a604a97457a6b46d48731fb44dbaca26e7cc70a4628dcf553b43a9efddc4e5fb040a1b89e31902888a7cbbf709333 -86eaf5b2fa873bb56b94eb7fc823527ae50364c1bce87e36fc13de149f1fc937af858a25cc477277dc6eddbf9efd5480 -a0169e6e915e7216b83b00b31eeda207a02c9db6825b5ea44134368eae5bd009b7c95005c621e0d258c33c59085cb66c -8c8ac664946b5e69b4e34ffaa486b745ac8afc8ac702e4a4cc36c59f420a81b31ebf8b875b1f572dad8e4ef1f547a1af -aa6fd75ca832fe60eda078fc81a1a529364cfa8a4b4fac071d89e33cdbafa7d88ff3df611720b48e6fcdca2e3eeea0da -8d30857ada34991ce6faa82b4326bc353691ca32aa25511cf3d52cebefb262d6db8d93521020a2d11b3ea085287ad54d -b78bd8ea8bd6a2fd5741228502b9777177039ac8f033071c82ae11fed7f0a51d8bc64fa9aee44df25eb4b3822d571144 -90904aeb1a99c4818ef21498a583848f4d1ee9253d70c10b03ed7d669b587f8712fd26d4409f00fafc3e26b5d72b4c5e -87cc8ebf78ff2ad752843792e11aeddbfdc628e03e13e0db598e08b496313f463f481f3a17ec889a3acfd128fb89aa81 -b4fd122c4830f339fc019da6372286d3a0565ac04d4f5ac4f28b2c066ed507316e1b7beb7b552f60060825977a2db9c5 -86e709d48d03738ca97d6140f13effa03137570c43ef00469eb0310909f66061d9fb933fbcf30bf04f13839e36d45a4d -b4a595cdd219aff5b8d0f80b679e58d9a7ab9cc389b47784484704e7d2c5249981b2b86be4c37ccb11b9afbcc8070214 -97c6bf26c8b28b982b7a56ff867b2f5785b37260b90e0ae680920f368478a3c88f4a47bc394c07bbe88fa1aa1776f255 -aa48418728684c9a10992d1851b69e54529dbc3548fe46721758ac6b33f82254d56738b351d146268fcc56a9b7f05df5 -962a282caf6f08a63aaaf7ed2146dd61d527144f3fdacf1beef36b34356df50302330598b8602f1447f6beb4439a1048 -b55d325499ce03c9b1c35e6aea30622841aff2a2c225276d677338579ce83177c0d64d78e7d11eac657a30648ef702c3 -8a91b9296e5633b3b9144f61e5436654cffaf04623a864ccbcdd21c8f981618a908e890f61c74df19ce5b6995bc358c2 -a7b6b32333377df24c0b0194393a1487a72a8783e06b1cd00ce6bc39337b34ff58ace57c8dee5b7f0ea2c9a54048a61f -97db4494e4208c9f297b484cb8159e8f600c61a44e1d878b07d29f0406fd32a0c12ebccd42ee7ac4c0bf33ff54a582e8 -8697bc039265f7b6e73c133823dcac9041d18634c68fe16412b4af41286a4164dc86f7e71ab7a493223a84e185cb6f1b -b18a66cf37f93ca0189201811e7de02ee029445132f0fd4209e5efbcef46ba6a28aaaee42b30cc7e97a25b08f4bbb43d -8b69f189f3cfc34cc3968a07e13d1cab0f5c7e093027a9fac38504acdf12e2defced4261a686a2fc850336187e017957 -96afba402124d9ff7048200acf329ccb4e35dabcd609e62d04d25140729e110a674849037e4b8aedfc99c889b132cfab -b75a809fa3b1c17139962bc22ddfce47d38d017d585a4e76ae1eb8f02849551ff7bdae178cb4546067bbab45b7041ddd -89196f1fe0869f2fd18f5c01118853503d71c4073aed8bd9cfaf694ca4a9e87974a9ad6e37449bafd391a2045ef5cd2b -ae52921b5d8eb5df7d4923aed1afb125cb98aa6606f8cbc2129cfee56ba3cdb7225a30d98ca9271cca67fe39c763d508 -99f1cfd27833fb64905f8678a532aa984329b2369ade3860025ad334131a9550214297bb2f7d3569eed7a9cc558a5922 -a77fabcb76e8c6ac2a5196666e0c75c7f6c73fd8a0a5fca32a454a9457870689c83f5821f90f28dfd91abc3bc62ee761 -92a4b97b7c14ec14c74e06363b0ab2e263d0d7d84125e2cfbf659bbee996a4d8561992e19789e507f4c24e5afbb91b2d -a2387e7857600a93de57faa0484650289c7553b9ae5fb001d011f43e5bf31c010c9c8b5bb82e7000465b546236e79066 -8641b6f2dbe9f0b83e0a7ad8098b0836af158fa2ee6ff1bcdf3e2ac8b3d25d2e5a24d515e9d549feab4e82b49e468fa3 -937306770a47ab2d5d2eec4bd6d9b3a8ffbb8c8067504571609a7e7a85c665b34ad2662701b67858e01530907172768f -b6b1b89f261e56b0cee15e2f5284c76789db26a6ca4762500745e260bda40b00b65add4826be6131775202c8c6c4247d -b1caac20a1b2aeaf287d38d42987e2c381e74495d9e880eda3ff59821d5974d01c7e3c611f4773a13ff41bef0f2ad44c -81ef049b849d7b0a732579299a86f1cfeb85f27ecee4280066dedf6024159fd47f311f1ebc46b58f63f71735a05480c9 -b3b6b657e64fc154eb33b6056b8279ef736839b56f2c8f8ca438cdaceeb5398b8d3625676cd393c196f664d7baa3a615 -a450678001e8db1ebd8fbd5c808c99945bb3549e834a346cdff316ef8d3b49b818cf9642e5b8097181cf40583ce901b0 -af3edcbfae3c8f368958cd11c95df4682ed10f894f770783e967fac1eed533ac427c1d4eee51f968ffdef080593ca262 -8348eee6ec1102884929736d6768477029961c3d6d09e9ebf84d2fbe55c0501165f274fc1c0549ab831388d431e051ef -8d799492659dc44aa38262f8a4ae37b6ba6eb10dd20481f652a1c77ee9a4529efe042ea873c13bb2ba3ec4792b167c14 -b4d3962f574c3298ffb0958ac999367db8207dacf2ca9d563cc1efb42fc889e19b7f00db15ffa91d145ff05eed97c3bf -a3a7c0e45dc8ae816d8765bbf097502b56651c0c11a03f476e362b64ddaee223128defbcec5629f4d7f1f9c3e4cb9f2f -951036c2878582d84d90dff79ecaca673df4760fbf9e09e63d35facf3e3257be6e1bd504f3c3daf8ac1e91d306e80d6a -8ae85094b13d349e60c8f303550cf4b01e96e24fa3a9f12d44c9822c004f1b3e9cbd772a2b4699e54023176074778993 -a7292b61d2667d74cf62a47aeb559499f19dfab2a9f41f16e7b8d6e77909457eb2aeefadd9d3d3f6db18a438ae53ea0d -804310f5d2ce8bcf9095945f931eecff79f999ffdd24abb9e91d92f6e405decccffe4a8d9e731c4553de79baf7a5dd98 -a77d3af0fb79b6f5b6cb640d04f4e13a28f8aaad1f60e732b88f86de547b33117386636d1afc7bfb7bd1d4e527812365 -a431f239ffc68f6b1ea13bbd45675f0323cacb279e11a14f664acbb15d1673b99cf3603b335a100a0e297c305d743383 -a64f4c28cc36b86dca65359cfdb50ed3dcc06fdb22ad567c7e0f833c880e76a53c330720fc2b96235cb0638394bae41e -b6fcd2c047de58003e9af3a416a2cdb143899441d82c691fa46d89045a12d3b087ee4603b401287a0f2629154bfc9bdc -a06e3b863bd183d8f91dea6d0211913663b3924f1e3476cfe0f328ff7c388aeb8e5c97757bcb56992c104ce0ab6ff27c -aea78204081cf5d24162686a824ff8e72fc0f88388525d646af7739265f60695b7d80b53cd1ddfd046bfcf59aa25f5cb -a89f556d42541a655864adcc1d5d67459ab488143e1b4eb48c67af30a8e753541fbcb479558ac26e1fa498f74a59025e -afc385b6b08c355a05fdc75e9360f4ffb384fcd74e8c9db34bbae9e0c67e0d1fa7efbff4160b387428ed58e129fcc027 -9428d05e17e5525fae515e1ba3f04742fad1a43baa2ee166d2f9431dabb46895b7345ad833d495c99939f0c57cbaf1c3 -b7a62d36ae55e681d48c911e1a433b568871c65a97916f939bfd638a054d6f1136a78c96640779ce1e3afcf90e3bb23f -a45b6d24930d91fc610e57ee78c6dc7557cb2ad976cb92e2157769447cd7c9a6a040f1008be9eb5dda2a7b8c9e524774 -8b24eddad804790df3ed82db7c0ba05082c61a81763c44c98ad436dcc7e1e89a2800ff9c2deaf350f6222cf4278fdf9b -895409dc0aba4d29ff322d2414b33c1458126c023a3d53b25b9038bb90372b7c20d3e9f6b791fcf8f76449fa0aafa758 -b22767ed218b575f397ad8306ec48fe07e8dc3a9f2f090fbaee411b6ba673a1258785d61adcba007d748cb019c458fd3 -ad4b9e4164010c4ba05a23f9a46957c8625fd4281a4e76f76ef7b4d6040d2228dbd2e6faf22b4a966ab42f32467a4655 -92340f1051f88c25a915d0504c1413146f37f709ab060e3859b14aff9be7f8c91352dcc3fc866910a84192d301029cc1 -b4e19bae926db3e1e295ba856984b32b796d86cbc81e81c6978e989f5331f27ce9004f90536a741ca996d19f998541c8 -91502e2a69aeac8e709553501311b4392dea3d5b6f14e7523bf780b8af246e1f2bdc4b29fc4ec3ceb725fafa31bf51e0 -b20607db1bdd6136130ba9683d581f5f45d8623ec4a2d35946723e0d8768654bdd9aeed55ba38303d8d1e312bc4f2442 -8fec23ac3b4cde8c18346dda1afb2b72d4af1a6c013dcea36cd8cbf7223626690ce933b920bd9137f673d0985b64d54f -996bba551ae3b76c5aafadfadfcf80fcb554ff26e6a9e14e60440b3864239129734115d11a89ba79c19e452525cb5a39 -a632f25ec68f02f7758103caf613511a1fa2e529e0861f286b4e490e8fca6874af2c13e3aa6ca97c63f3c621c197ae24 -b332292c6213c7216bb78612457de615da878619024626383914f9c28f835f1289818514038c30eb2bc3566d2da470b4 -b5bd5ed7e990ed8abf7de268aa1ef7ccf5562cf9c92486c2472051c1b5506bc9e72594380e7bd00c91771ed4e9707851 -8781393278ffd5c522ec450220698328e60294ae1e35f60b25baa290a125cc47fbf7435eaf9b22ea819d431de0656f38 -80a308c1acc4363f9bc54e6831c5aebca2b2af47d699a17ae2fba24495984acd4a25c7c95b96aeae3027f0fef9549284 -94a55b36389e05b848c6d0e6426a400d1596195c2cfb4a972b6bf8abde2cf86a932b769a90b62a65d0aaf388e66d516f -8d29a5db4ab3a1199946a79ebaee9de225284f0523637f90e4ac16fc609dd3dd5a71072c30e869fdf6f057b7806ec254 -99caa565547b13953b91f0468b78551784d947b5a3fe1b7278e4a45b294f074a93281e9ee084647d1b24c83b39a0cc90 -aeee1c88769e7bae12f163a056d19b0090c7fd866d451963bc855bda2736c41500bb97a8d72a1a077357419ca94bc3a5 -a94bd8b793a57b4fd79a84daf1f7fed5820bfeb44cfec0248f6aef130fb3219e1bbce68a6a55d332b124e1cc55224c51 -8528607774d780b31417bf85fa3e54a94e4ef6e8cc233ad2a1dc795c68c299abae209c46ba77c33ba74c6ae75ee004a1 -930f2c302a87d6bd159bd6b4db43212e7c806e17f572277ab14dd9715a435bd67b3624a9e72d9a2777f9b2080ef5cc36 -b50d97fd2fbe60105dd1dd44cd12d8ad62b8a3127329f969be917fbf10132f1c6c6fda8029deb990fa1ed26e8c220c39 -b685aea07aa1a45941f5eb2a593c0d97ecb5a803fd2977783488fb00fe6580c41ab83ab6cdd678704311c5542129c510 -8cec65b68f4b3b10d032d39ec4c448e6d76e7615560bb754a53c4c6929c2470a884e7d39d9f3e58a2a9f121ad4175a34 -96279388cc3e91dba49763ef50faa7550c3b4c277b2a0b0ae3541a2f990f9352748db75755a7b13efaffc9b8df40c74e -a7599c33614456b1b02b57921cb76b01109811a82f230f9e7e82675d57757f06021ac3f514d557ed9f2dec025364284c -869684197084f42dfd95350f8a54b0c7d940ceae2bbe49ec18fcfd178b6b0d21903447509e0ef356aa3d2aee83701bb3 -85e9ab73165878b93e0229e3384f048e9651ae29980f9c5e26492c45e180e09a3af9058fada434d1c398b43d99d13056 -a453a46ae96e6330c1b315d1b5f37d160731309d49d13d6c38c5d7f0b4f23ff1d18c985c471564afb54e4477c5d28d19 -a5999c704320d4468f94d647d83c9e8720c19782d2a03677143c7216dc434b3160d193389b0115dc638f6e2e12f2d441 -abc7a466cd848304616b2eca049c4b7509c5260c9236dc1432044ebe3e912afcc3a6ffe3e27d5d79d3ad4636ecda09a4 -89ca07faeef1118c6b840a2c328fd32a5709b31850057302a7e607891e11f3f9f62e4fafd420564ff10a35b9a44c0f06 -b0002f9d2a8aa850b9f22dd8d3b7881e8656cfc53e6c2ae6a913d88f6934e0062f30da2702dcebfbfafe36785203cefd -b8527c70bc791c87f5fbc67e2856e45b7254c5a0b673d4a5d3e9b79fe0715b608a2f35d88a61eb1d8d7cb615fea650bc -b9be558dbe778ba11fac7080789522fc004510f7b740c42023d850946933362a173267106aea046f338533e4cb29aea6 -b021f9e635e64d3c9b4ecc8075fb74cf0e5727ecbacad15f822c8608f0d981ad2c300fe6e47c6148a6b1a13cf920d85d -ae59f2a83a1384ef0b5613e8843cc9a934f7126430df7cd7f5a8508e3d83aba83bf3d18be7380570b24ba0e00e05e0e8 -b403e4d0495a0137a710c43393798593bf131cb8d49beb0f3b3d344554dfc3355ebee14e884f543bb94bf9aae40aac59 -a73b722287df7558c503f89d113fe0c017765c73181eeaa9ebe6de5c8a15ffe76fdb85ab93051a6f565653046624216a -a7d1a28fe1d36b17e37cf5eac7e27549ce9f6eddcb36203b58797d3372371f3b195cd3432db54aae4bf99768969f5b60 -a3447ece13c415c457b899d4a8b8ff388ba25bc920b5711f8687cc86e9c1b3f3af42c490ec6352fa8609b044e642e3f3 -b12f2ac1e033b6a627e7f7822317f629c896c8f8dd94ad91512855882dbb10b8e80a1e29c3e39138402f1f7e0de673bc -a7c65988996741bf59888415fc2264495050cb13500b6597d9d0e034898121b605784f681962cfdc80b0af291c316e7e -8c40cfc07dd7a4bcf514f2e87a1830c911e8168b0b8531a2838d2a14e790922b76c4642ae237b7547d8a3625decc7f0a -b480d70b57434467a40d6dd066f51b9e637abd2f49dcfa6450460aeec2bc895347e21aa82baa1bec7589b6a5a694fa73 -a919a033c24e96af1eb0cb1ede3684e9a3bc338c7ef37b67cc9e9982586f74072cc540981e2d1a2524e99144bb21a64c -921e0b350907e9993a596b80f827b2d40aad60e9c62f4b65a67d3fa4c0acfa924c93352dad6eb3e868264bb24904e3a9 -8d5419cea0bfebaa9c1509cd748c8af3869aedc3ae27fdbca3a0f08b3751a3b870e8dd3640f4abd4b46a2a1e745758bc -8b25e6eb600de81fdd03584fb9db9a7bf4c154ef1482553d7bef880bdc5baa7b64abac6db96fcfc4408329adf8fa351b -88cdb72bee7a6768b7c24d124dd5e8b29f0c866a0624e5a7c4759962ce1d71de7faa97f7baa56d5f51e35bca43862bee -af1d59add7df3b3ba234b0b4f758349225b9cee65691c102294eb7e6fb683d7588fca33ed97eda361060253acfdc36af -b19370b8fe123f1dd2ea6d5bc75e151b0d1514224f5824437166fce77ac41ac5ecc1e7c1e75b75e948acf04c420efea3 -a1ebfe84f1c012524cb475e68ae6c7cec79fb3372f1380321a0e306d15828613589567efe8bb5784360aed568e26db49 -a0f964e3cb594c359e2308defd3eaec476a638b6e1c216157009e11f7c7d0c33fb9e62c4243057cbca49ba315d4b508f -9391e5087374e45f03d36f6919463c473938a653adf3880571850374ef0a0e521b25ef84b6012a19a02ec88f0ca3891c -aeb86d4426d2836e6e10c3277583a37b6684ba35f4f30d2d073043f0a0148f763b99fc42c3935026b56c32e5cd0cecfe -aa98c07dcfb1b0a708486d83763511c7004896856e851bd83d25a9551efc28f059c3fb8752ece0296964e8c13ec829b0 -a466fd8dc1aea7022a86e12a119b16de35412a1b461680f6a1cec408e9b9c1418a8e406fd4a5656c73488adddf17dfba -8c9b0e18a033c27731fb3d22b7c83ba7a86fdc2234e8f2a19d7659aa67bad7a85ef25264e8eb81af529feb3fa9340ef3 -a371feccc2f1a1b96ad8a9a7d8db0c06fefb1f2800933134299027459b0eb8cd101b9a37c76c22dcbded01a74b13d465 -aeb34fc2758d8b68d17f15ab3c299344ed630f7351c498a5fe7986f7e14d62e74ac9a8f5d2de7c6289771210539383d2 -aff9e961d0acc71a077e3af52ced373bc694f9154302abc908710e500e908f33bdd10b3c41bb8fa8066758a18d64c667 -98bd5a8751e598896e9aec90649294934f81c36d2d0fb60070e9b96eb47d0988f71d9b68f4c475477eb4c996a9265c13 -b25a92c6260f389f6443a572960e0a52ab9c9250d8760ed148082584b2347ec7d103358c033266bec02374e69d0102fd -b876968bedba7f4712f5e5eea605c1e5fc40bc5773c61f08c32e0c0f3ec575eed3e13e48809983153beccdbca2123edb -8c4091ef8946c9b27490099d5c0b47c404b5a1113500592515deab1c3f2778bbe933b09c9824a3a7ccad2141f9b5dcc4 -ab85f95d318ce235929531e2e397d09b9906c58958fdff1209a514624a099d3b8c103a51b2fcfa0b17a8f008744b5d71 -9016714cbe49fac5e7b3e493574078c462e18f6363f413270c23da6327731f71e2dba5dbf1da6bbe0e29f57f0c33f869 -8c90df700c0e2d104ce7b76be7899209136498999f78195cd888aec6f069778d657e5032ad7db56381470dd1f519dcf9 -83dea8472e8418aa069a0837a5c44835aa1e00979a217f6295aa35548f509fbafc7db5b31b8767621e4f89957892e8f4 -80a1d673220144973ab70d977b94cd3d6b8fff7f82f23bd4b30ea393952951d2f07c24e6d411b2ec19f3bec13583d9fe -804864b58f9747bb3ae54c588dff46eb6e16b6d98e0f711828e97d9f019297b743aa2202f823e3153ef5bc4b95da3501 -b08eaae2eca2c64001e1da7d0e345f96dbd3e09888f9ab86f178718ea5a04321a8b8633e72dea68cc05687042808e3b3 -b962f91819dc570c2cf131b89882fb2a44a999b94fd1ea8b83f400e9b66075a35c89f0fe0e8dbc3a597cdd1aa3135888 -a5f33e8f04a2d7aab44e832f8ab4640519aa4ef88b58e0a398e45347492b040043e494de4b355f07cb4bc728b67f1ac9 -8ed80bfb4cd15bb87175cff427c6a1bfc3e6292bc5c2d04dd42b497bc068baac5602d41366448ee7f37d85a5d8437750 -83441e746afadf64583571a9918ba5122ca987e76a6e37f98514b1a8a178380366d10ded5c70d4feb08be6fa6d4bc25a -8807fb8adb2aaa6833960f435ace162c01a9cd0692a4cf038c89ef7405600868efe7bdb3e8a3db48901367ebafb0a1c0 -82c64b1f77fb78dec00cab089cb7a88ae16c72c94d0870bc92df11587feb62277eb941d2f7d3d2fb033d7bfee12013bb -ab2f1e3f1fcde3b8b2c07135acf3a492ae7675d9bc971ba57e06c99fdfb39e1f68d1c826cd9bba872749cab375e44009 -b4a25f1f5a2aeabc29870ab9a815721f3cc031ab1a55417b457ca6504e5e96e4fd0d2d364ae17738726c8f40cae9c36b -9519efa4774cb4de4ea834376d6213d946fe6882e2b36342f683762fe50d754765dc301569a836febb2c7c9dbcf44f64 -a75de0d0320e8cee962d6ed4b07db718615e75543fb25f0d28ec5e76f56d72b18d648ae42d7bd3da18f54ec1e4497a08 -a2a17aac11e732097b25c0b9f7b97d807dd78ecd33d88aea5ee0a46a42198d379a241e888ddba940b3307e9c560ec45e -936ebfc2234d46282ec4de88958553759d766f682d6f9669d2b77a2cb0cf9cea9b1ac02014ac3f5cd47dc5d8af2da314 -b33def3135e7ad61a660ef1266d61216220c7e0bdd867b727ff3deea904072e33a195e4febe64ee1e263349fc9096cdc -94337e4f14752676a703fab8544ea0ab7acea0ef924b85b05ffb84e4476f1087acc9a6d6250893a32b82f02651a179e2 -8f22942bbeca0118747a22d0aa13438e40bd6a383e310eafacbffa1490f5758504da4a11e6320e1c55b3daabc72c63f9 -86e3ed934fc613d0b3269cf368e32e67f4add59e4dc1ecb1f016fbdc6c53101c2435f95fc36625aa8c69c596acd9b0bc -86f04807460e1d93f8eea2a284119d889659b5a6b124d41dfb2825b31685361e8163fc3a253a49cf878e316463c9ace8 -b043b2a99b94661ef8b270842fe4d3c51891ec23ba749d9c999982553ecade6f658242b373982c9a3669a886889e4f33 -8b6a33a68ba7b5932ce11b3f0e23c3da580510fa37668f2154c59c3bf788dd2276a2a8c66a6bba1a68084e8b9bbf378e -b54581c88d4880fa4a0ec6d3c17b6f0ba339e8f7100242efd3b820ac942d75d1f898259d6f1e64a3870fc301d9dea2b5 -9449dc9bce23c7e3b41eb34789dc7765c2f7855f9670c1d145bbd1b2d1b47a9318862ef3738511b4f89cb16669c0af18 -926245ae9d4eb213ebcb88ab2d7e2a7d198557721051fef4cc966cd11be3490a3f83d4ff48f5fb60cbad9c5de4b98d1c -8518dab07ab15887c68d0de9fe3c0c09ea6bfddb99c145b3f6ff84659e7799da93e97bdd17884b228772398caa8c2ed3 -9969575cbd7953b6308391e9ce2cf4da466b3e730c9cec0e88522258639be35fd31abdedd94b445d7075919482513103 -8b1f28002c19b17d6ac1a6f50afc3448f390b3209b1a76a9a024ceaa274de4588ce82a891a03e878ea08747ae5d98211 -a611963d1bc45b60ffe6756a743ab379e4022bb3fb263f5f305a615c92432199c7e1060a79aa42f7662fa89a0812a4d3 -a3c7706ab74e976464fc341e5a9f7284264c1610fbff02fc36b88e15d6859fbf40fd8c5e93c8237b97acaa0900a03764 -aa623fb8892dbbf4fc02004a44e07c21a422e5553e4b02fcca24dc1f416a54eed36f2f7376dc1e66218e850772676e99 -8133cccf10b1686bf53143bd3520515ec72e7295f6945c43bcef7304de597b767265a3a9f7b281fa353acbc3cf6997f1 -852e4aaf4da9dafc988d0da13a7f31fe8403f6bdab88dec363eb8cb8d3e64c48ff34102f6660642749d11d69b613f8de -a616028c6cd54a6514fd9f7aa9ff13000eaaf39f582441f73a3ed8208a513b580eb7874b5cd0b1e9a542c40c5887bdef -a48ec58bc3bd4b512c21d3d55618e9c51836efa97cad42bf79e748542804114714db23d79ad03e410e0989055c9bd46b -ab480f3750420119ccfcf8d32c4a18ca580ce88bffe81433c1d6999c221c8aac482de5c0e41a5531806bd17897698d6c -8522bf3b7157cd29e948afc8f479d6192364a11f85dd5c58d4ea0443aa6b655f55a80e6a3152fc02a8eea4c0815fcf19 -86c91a6021e738103031c1ece906ff43227eb23088e5ce1b6a1cd58664d4a80d7bbcb0d56c3b0e02cba1e1c2ca22e058 -8ee51a59ce6becf098256e19c9aae5ef0c2c9e66c587d9a32cb4ba1ee0b64c13e2e008908e35f43314316508956654ce -b94766a0fb91c8de2338a68c4ab08ce5bcf62f6efa221067807dc647b595fe5a342d7122111540a1ca6ea7743b6ee772 -83f917b8f6aaeb9eb2eb742546e3f2dfc9cfe00cfec60051010113d55dba2421974098c157dc2601902d8f40bc84693b -996e489890dad3c4dc35faf53d870bf1cd76f1dc24e0cc8a1f899bdb44e89dbfc77fb11f7b33c270a1394c909f7a27f5 -a89936283190b2d1ce8d166b36694afddb4c3df01bfb1fa7bae69c55d1acb4e68e5e29867ea33eee8031029b3c6409b1 -b08e5a5d6797ca252d12428b2086e528a6e5c3965d2e5ff2bf83bc71ae9c0346a4ceb3bb2f2e3f8a1685fc343f36997e -a05bd12a7a6d52d234a1b3e9ddea7b18d6d41026a0d18251b1761f1cc863064dacf821707cfeef2dd1c02536f584ed94 -87c638feef9c88a9f89d10b56fe4bef6406c1d734cd1f01006e2f2b331196a49c7184c10786e855b3de8978927df42bb -aa194f3e4d0fc1d3107f9564b13e6274bbbfc7b8c1e73ce6677cc66d9319dc34b5a0e790d6d44c614c11feb50530a252 -b2ab7be7ee9d72d1015e94d006020e758b73f200dde81e89e52cd33f25aced0cd84b8c300413d32565c253edbcd2fb1f -8ec08b22265aaaf27a84a6cca5f0875a3ebc70fb36c4f5e59d60c55bdf2a4fe11ab7ba4b387f5d668e67682a0978fa46 -93643b9541db11b48e0c84caccc8da9ff7696717aa176ce6d863446ef8d887f3159b0ab6fe1f79fac883a371f6736e93 -8325654fd8388ac96935149165fa3238d0848151a04be57f2386c3304056013efb49febee0a871cfc2ee3c11bb029042 -a2c15cbe5d5167f55f2a454390b61d99601614037fd67fd198968531ca2f84f3c214b971ef300a20a114fabc6c67db0f -b40ed63b0367174b5b4b08396afe2385b0f75ec2569fa3cf60f87e1b17fdee888dd66057be2cfb185e9f32df59b7a8eb -a466d2c8052a115f121177979620385bb07148e202631979f4ffb01e7e0f6fbce28747df9bf70b2168653096aa704fbc -99395136290cd020cfba0ca896642c245182e2020ca2299be8ebb2f62e2fc62fe0be593838f62681f6632fbdffd640c9 -8e4f081d9a724bb54fafb66297a32f84687493464550c09259cc6f8abf770d076a514ae1d6726cb29349e27ef69a74b8 -a8d5c941e7c03dba0232c763590e93e3d99fa519b0a65996d20dd20deed1d0192738f3b339edac68ad42016223733582 -877baee9ee979be8ce3bef02422e57799dcadc34fefd8bf2baaf945f267883f67211ac5c06246f7b49f1ea5c99550a63 -b6fcc2a73dbbba54760d244bc13e1564a3c61097e9b525b247cc8687ca08625a7330fc6b15e45a3ee508b4d34853d852 -adf720dde6e9b5c63e361d69a2ab46ed73e0deb82f8e30f27ca2b19c2d8fc43e18ac04b4fa029f553f8d7dd79457ecda -8956c9038f3338f541bae9ef1f5bfad039d532dbbbe7814e3a3d5442d393ea6114aa666559d8a7e3a026c758a17c79d6 -8d6de7f95f30a5a4b3d441781c7f819a0265852ab78b8416227089b489787c8ae9dffbb0bf88acf1b4c4d6b8a29c1a53 -81d4efd71c9d08e9f6d7f7d7a2fa5089e80cc3f8dcc685686aabf3b4c8bd531b4aa07e328c0fde32b638f23eb78de588 -a30053b681ed8328b5d64587b0d38edef0e366a2762cf5068dae177e4f4084c4333f9a5fa5fede93db80f7a8fd5fbf57 -b340ddfaab2dcded58930e5dc2b72cbedd0e79ef652f34356fcf72054a87fc2373bd3aaf8a88af8d4633f73dfa7d9a28 -b9f3a7809be0bf834bd7affa2059d9371b848dd5e5fa93e83e90d9e078a2fd3aea64410a72457c32d33ff1ca11dc9300 -a9a8ce26a38dcf277ed66d75e111b07348101e93d03f446ea72bd903198122f8a08569f7125f6d4ecaeda8c093a00ec4 -81e78b705b44533e2e997f549f46723a5e6b88241d7a86ca20448ae3ab140e967347abaeb8700594a0cddf1e82285abe -84724094dae5b7ece30cc01b5f2acc8787de57dc0c37a437c3e8e26fc03069b6e8562302a0f1c95de85937f07fe63d3e -97a715861e5bb715a17a948d6b6a389b89744e8ccd3699fdea9ac3d890fad027b78d436f8012b0abeedd078a20ba91e1 -b710b2e7d87771416aa34ba2d93a044bb118f279fff62c1224c150ebc30f21abff212019f0f38c334daa5a96598ab900 -853034af5ad08c563ed096ab2d0590ea644d372cb400bfb03867092768d90b7432d35c5506378d001f986c59769d6d56 -b340ab52f751e9d516348faddb45f0115ba0619ec9db820f870007e3a4d305ba2bd0b2a58a7576296531fb78886b16f8 -b8ed8feff520009743ca3313899a118df025a61e6e03bd5fd27898a23beab472746ca3636c22ea3835e9526e17c06dc9 -87af435e3e4ef611d6da74c8d98e8d3f3de64ac8748105dc20287a7dc866f57d10a2b854f7e0e09235eee647dae1ab86 -84108b1f0f0ff73a179cb1be1b2ecb4268e7fd2fac3dfc7f6f99889c90a33b4310946909b9eef31b256b8d0e3ba56bf8 -a6b9fe966293e60bd384a1e4d472b0a72544aba41b31172ac8bfc3e19beaf51da54a66625d73a9ae22c7c4d1b0840a30 -92e82e92aa615e198ba3c83c039b0adcf4393b3fbf9721b2e47ab17a84bded2bc8bc2bfe257d2d76162a87e8bc7ce759 -b9286dd48800606b7ff9c3fe2abf5c49ef0a6b981711b5ba1f62952d6fc4a9999bfdf061c4664a019120f15e341925d0 -b5da5dbceaa7e82f30fa5fde88b03ea88e7003a50eeb53e3f3aeaa63aa586900525b42fe1b699451b5d915d1b83c3705 -b06072869fb8526d3077cc61a3c55d54a7a1197bbbcc875aeaf617d7d1eff3dd3ac243e2c76caf57dcdfe306edcab4d7 -b132db9ee3ed16e6d76db9e6e3dcdc2b142cd70b9582518bbdf5415b3bb476ad900d50004dc0ab6b87ba697c6314b4c9 -adca92336f3546ea50b034525fdf548a36049ca82d9d3cec10073e7cca186227cd662d4d66673e7214a6ed58cf75da6f -81bbb3fa241f9514575fb3f6cba8e34301187681354c94e7976a4205c0bb238dab52b29a76a5f0e0d4cb1bc82f8857c7 -91008dda2bb7dfffd6746e3544ef540d9a1ac7ee9c68ca9984a1d81041a18fa9f35b8c4bdb44ef3a860c37481d5e9a14 -8224195cf18ca0d8f01521a0ea92c9c598c556746c825a4dda49ecbe324d570a96775eb81dde1d3a14aa3660d50e27a4 -8b355eeadef5fc7cececee71aec3ed30349df8f43f25da1d75d62ab00fc73702b405fab6d422053c2b0fbc7469ace9a3 -a4d657dbf2bb30c1e57e0b63960663bd86ce17204979a9ab82624943ea370119f040b58b067a05ff6d1867a22a58698a -9379a367c918b2be61a9a42a495ec03f0168a4ec36f753dd37eac6e9f58a26c8510ae7b579a89afdee1d192edefb4bb3 -85b37bddc80754f0432573204a1a4b86a550bfe9689f6c710a61810aa94dedeb28763ece40f28fb3a6f3791ca4c86b8b -b41c3269b96e190e40cc16e6c7cc8054cd0b7902a43c69b79d8ce471a417d3096b2271badfcdc59deb6271ad3e5a35b4 -941185020a227b7a995f59805c8900f7f6ecff1e7b948a8b714f85a54449a0d41e28db5e17874e018eab72ade20eede0 -8a0795ce082f74e4633acb1649b52b46ea2b4360860fef6ec107910e245b30466bfee8ce59a6854f866f55ec5cc7bbd1 -931fa63550530af5a7ee24964b8b4d0c66c2bd59108131f375c7de86bce59cf52890191ec8540666c895e832dc312360 -8fb86918190a3455014a5cbd15c7b490d68c10cb7b505e9233b3eacdf52e63299d49ded75fd74f8c2bcb3632a9c29d14 -92c896826c9d871a83c4609f9988cec0db6fc980c8b88a7baeea2856ec2a0a56c3d5a846a87d03393dea966b534aa8c4 -a9d4c780c94384f5a13cab61c734836f5729482cde62f2888648a44317b749135b511668834d49296ed47c0a3b9fa8b8 -b7c26da09c3998367063fad19340f53217e8545535d376815773e201ef49e9e1b6bf1423b0b6bb363586f5f05307fc89 -8c445b3655f1f554c2a7f6f7d035121939a8987837dcb1a1663586614dcf2cf47f73633950d8803e2781baaac52c12c8 -8764f924f41d8c5c91fcd77de26ee3bbb86d5a5bfbcc45188be453c8dbe4b875fbc5ef5b01ea3a26b889d7b45417f173 -8605a8186d5716dd5f955a7125619bc72ff385cdecb187a9a646a4bdf6595d67f00e777836261f3a69c19d2e2cae27d6 -a97dca2185e4fcd7583b1e695333d55f54edd751da436b8982de8c344b5f57e35ddb61ad4a611dcde08e287c78c757c9 -b11c576a049f93e0731652f1a1ade62b0124cb7b4e2b13f6505206c27ebf7998ebdb3d887bed01e43ce5c24714903aff -a46dc516b8ab4aabe35f38af1236052564b01d66c558e7107175064a5226713e8550912867eafe4da133f56950df57c8 -a13e75bca5bd3b08030205cef4faa56a49e5d7da94bc41c708deb2f65343c1687aff26368915a490b89006185f18fda4 -8ef5135a6f1f635a4966aa540cb877dc98c6a88fe462be3226c1a270c82cad8e091aa49ad39862f012edb3c93d15fb4c -99158ace79ceed67b6d8e884050c6fb7c7a1509e41f0d2b9069ce8dea392f17f88303d0942cf3c0af3ea52d3194123a3 -8805c76ada9dc7e57545a5e1a874e6105592601213e22c1601b0b157b622e51f004a1da754a8fccc8f2a2241c14e21a6 -ac3dfe87e17ccda6196f621008716a14be4b983d187265eabb8f5eba7268cf770a70ffa19d1c7e77fab0373eca7a4045 -ad78a31ad6f2c84f6e5348f33631d876daa3d5978f6d1a77db80aa219e12c9ea656e9c18e6316f899bbf6c2469cdee37 -8c8726f8f6fdc40516bb64b6c624a6eb4caa931e3a9ca8ce2c31c282ad59f0624ea290b804ba84e339e83422070df419 -9303d1906cf416a184e15f13cf7dbdca5fb296b078079782c9044b9cbfdf06b0c965305a8d88678b53f0a10220e56f4f -99b9735a77cdc1c675988e613b3e8843e2b0469030a33f5c14383803a1b20e328d45d2fde6ff0d15f6bc2eb8da4f4d88 -892a18f4ceae3fe7cde8f32b84c6bd3d9ca867143a30fab4f939281cec12587929faf07225725bf33ddf154b90972214 -a100a35a2865bb465830ce2f68406d8a92bdeb21056bcba28c0ce8ce5ddfec6e293e926d764499e53facbbacd3f72994 -b797ab22a57520a0584edff499cd1aa1663d8b3f411faa542022c5f1a645a3f952f9164f61d200e4500673a8d95a938c -b1a457d100def2e26b2b30617ee866264a3ea649bcd9edc7be132f5cad02f3209f5dccb02b95a462b5af9a71fb88a341 -84c1f6d4f29869a359cf89118b1a80224cb574393fb557d1c61730a1fb1884895c4cb07f23c52165975b89fe9d6f5a77 -b6d53e49025bcd1d7960ce46d4f64ff8f29e4239fde1b19e5167d506b086152da3bc3b86fec8ea531a20afe1c785fa59 -9635b053c03d1be0bdf81e9876c63e8541b793ddeeb2a8f3ab0e44fb78f81a9e61f8c68ce393c7c959b62b67f9724409 -a19ca9ac5a345c96a607f979a958d83eef4350ebc9cea0e0aa11469dc554fcc39d9b22f8a3c92de599ca08ff4152ec23 -8e7d45d35f6fb95799846fab51b0ff2415857bb54b049694c1ebf93f45167b8497c3341b656f194edd5804195a7c96bd -87c05c7d5834394507ad3d363dd0ca5132a7763644e354c3b7a803fa594d951084d37942f59211660f10098cf49adcdd -b276246af578557aad38190878111e804db0f29846185d7033c913a31e7657d035114448ddfed2f3d75c04c79ee01e79 -868bbcf14f96547192053823e4f85b50fb988da5c4cf73f5cbf23953252b665ef7aea4421c8baec90522f58f027a2b19 -ac2be3dcb8082b64a3745ce0d2b97cf341483713e1bcbb37369123d6723968d3bad1410467aac7fcd3b623bfb1d90d9b -b1e5cf361e0857373814e8db7fc275ccc1dbac8559e8487cc892bf82d4c6be00d1b2ffe40289692a70072c5f80dbacf6 -98e16a5854635c72bce6e263bb57c071194df076e1ddd81e645884367b730d4d557ebb8c74b3c582e09046d2b9ad8078 -a0016bfaa348d44a3ef814b348f7d56fa83b78baeed4a7b58617b6f4772dfa990e912ebf91c2321307884be85dbf81fa -85690a2c5cec392b6f98cd2d03e4204cc51868612543c7a3112066ebeefd4304c5c8b21da44534224398648b413634f8 -a3a1d00d0fdd8c8cfee153347d590ed78cce48eeeb7ad42032a95baa73cc458d46882d0e9707f3dd519b1844f236bcdb -aaf2774fb26da59c115a28d86f0c6320368fc6d2c0bc2b7e4516cdfce3058cb423b0026b6c75030ddace9ccb7f058227 -af507cef7320bd003526fdf43c04af46beaaca5b6ddcad835ae14da60a2ce732b453d8164553e95f2b776df55ddb5efa -b2656c07a8ba2a2248d0313a7795b99f5acc120648c08e3a77fff5cb9b861827c94d4f2f99a2f2dec1d1667ca3ab26af -b426b97a51f0439f2da2d0d934693aaf52482bbb48893de12fbdbed1b2155e30791e7098baa18f93ecc45f8dea4f22aa -a71a7e08426518ef7307c2a1be7aaacd843794601c0d49f4f0e474098ea0faff74fb5ae2bee416aab849afe04be434cb -b6d510022dd3b9ca35e93ddd2ae77877967dd6966706f339b2197d2891bf523b5d55b7cdc80274368333f9249b62a7fb -95d2f6cec1b4038f56c571ee0f5aa14fe5fe7b9a2efab89eab4c51a696d2ada549a42095245bea14d7f7ffc69ade417b -89147eec9de685483d0a5e21b877cb550518a1bbcba0ee65e9519c294fb0c422a729bb0f5a8c8e3fe77070e1a89fcdb2 -a66e7116eb277ba900c06fa48baf274e2a6865977698a504dcc1d0c20f90a7030bb2a841fdbfaa5c8ef6d81aac4fced7 -815053a8483ce2a84a34f81909bc3eabefdce59140f0fda6da77ec005e5dcfdbc6f289d0f0513efbbeef0358daf94025 -b480d2b6320ebf29f3781f04dd88e835ad81d2c63b716f6f244fd2b113ba3781001a34189df586cd629e70c2baa0e5cb -a74281bddc3a93503a695f0375121b3bdf98db4b2b053eb2cf0773647f6f69d1d98a61efcf82e2a823035ce803b82001 -b84fb99a6943447cad21bfe2b34dd8da43d349e53e85b73fba8a5fd0fe3f41e7dc629960b3325d08af1544e5dc66de28 -a8d11ccfb0dec31b39efeee74c58536f29abb02d06dfa11acb7134cac626a17ff4e204d1d138a472c63c629b6f8406c4 -b5017d42a2388d90bcf4d0b6e015c63612a0864b2b379e9cebcf2e869e5fd45d2713bc549ea472d77e82fa8750f364b7 -83c8e090de4ab6ed169a033aa4ab84f7f3e2b54186106790b30741e9d87d9a5d61bd6a285447e0d1a8e1865ee618a91d -8db64f3a1680cf461f9afaed4e714709d37559071bcee52e13feb5627c1fa7c093fc8923ede3e70db07563d2d1eae69f -b6d20dce2f50b78b094949e64edc2ce1b077a3258692ecc2cdaa01ec19add246d0832a319bb0d4153198e3a35091d86e -a61e585ed55dedfad57352d2abbf8ab336a999a5abbaefeb5d0da9fb0d5bb791119e52034844ffeecca9655675d17228 -8ff58b27196f589ce0d3461e0c00d695da47a79809719b4bd4a229ea7bc9319469744f2254be4469092b1a27532439e8 -b5edaf7c3f9dad7a54908da0e7a153d69a6bdb99fde07fc42928a0dd38031e32dec81c864147066412a8ca240e7dfd0d -ade064bb3f87431a32b361074a89dd280cc1160a57fb3cf21eea5066e886c7bfc3655fe39099a1913b8b53242b23b2ff -9169621f97887db46384b43ca24b1447e23fcf5abf141e70fcd1834e9d691b9bfc6e8059d060bebdf9922608593bb972 -8727bb06fadf0633fb8137a54d6912cedda0bbeb0f93af97deef3490b1b47e58fdb37a972dbab1534a5172ff0c840114 -91991b98243bd7c138bcb60cf703a9d0828f6791eff5c2c1c5cc7e8edda258d3cf72680bff2c563c8e964f87450a3037 -a1bddb74f5892597ac687451b932449305d6deba20e97e10989bae311d532a7b72a3fab08dd832589e6a22c0fcb548dc -afc52ed64208e4beb029d1428697fea6add02210f613551d1e5ba6011c5d13f66ce26b3dd2a39b30186c566b1af66c06 -929bb88a9e30862be5f45c002c11537780d151f9836edeadcaa4a617b0bf958046ce331e15bee646f9eeb4d9ff854661 -b3376241793ab9f1732997cdf515b9114f88bb2c25c0bd3f3b22e5b665e1ae94fa3f6a9f88de37b7792c3aafddc682a2 -88fef7680a7fb665043264c9733dcbd23e20628909278711aad2e54f2eb8fa3d07011f593069b6ba7ed312d9ddc3a950 -b031434d514d0878b7011ce2840e23e94a4386034dce422f37fde539aa35cedad1511f9eec39fc23c7396f43ec22cf92 -a4a32f1e58c4ccb2cb4ac6c2dd8acafa292810c77126844f33287c8d522bb8c32dd89ce8f7c1dc9a273165b0879a45ba -82e5b11b9fad7c7d5e2a8abf03943aef271ffa43ed8127dfd85c7957b59d7cea56039116edd0b0b992262751c347f75f -a650327144db1806cefedd1daec1de3164b77c02a0aa652371ca0401b50ec3b7a392ef6a80de6d4724892d71cf48eb07 -a88d8370d88379b52bcaaf596c32faba155db4857bbc7eccf89b5d67a97ae481e53e81de6c9461a6719d179f3ffbaf16 -aae8b3d1b1bb0d71f19e37867885a1fd550f7805fd1306881515d77e5f6a990e0bb40c685e350ed09eb4a55298f3a393 -ac024fdd79688628ee188a7a9d39cd1306883c260dbda9e79eaf2d2f57051b5379834dccfc641302cd12a8a24fa2224b -90cda91b9e71b7bbc091b9e8e28d79f0fce42255e24a7a3bbf3348651405c46d3b6e2e33c5fb5e99fb4d0fbc326f77a7 -91325730bf7d71855ce0462a2fd0840f3753964b296f7901e1ad761f48fd133371fcb805c315c4d8cb2ffe34e98ab9cb -b9e1a298ce9efdc004903b21e573c113c771b1bb5b25e2e88baac6dd7bded130016b2f09e50a4346c59adee607a71760 -a703a60c430e365bdf9023c923a04fd9db427ca0da2da8dad6b0f0d5d352524943839d859c15dca64b590ace6cb1ca89 -995a5ef468a38caf66d58880245064a7c0ab520ebf3c9e9f956110a9dd68658baae22ae274a48d59464c8d37d2f8b643 -889c6e4516ece0e0fdb8c99aa482f367f2cef0ae2ce0987b6b602f6c856b02fab27114a6f4b82050738bc98a48ef5837 -b432ce5f638aa48ba952b9c2e06ce822d531c9a24011d14650cac0722a4c5ad1bf22109a2f429cbdd22a567ce6f03094 -86fe41234d309118d1256a9ac79b7bf01da1fdfcfd579b655f31b7c4cdab6f687d46855d56bb11bedd4b0be17e892b2d -905ec536f23dfdcc4f8128fc1c00daa877eb3caded7637dc911aff0e6279eab12f1748949e4bf015e4f8e30626d3177a -b6b9f47cb82244d7b1102b37cb52f5c9336e4c05e4c90f5e448fa92444bef12d2fbcfc39af9e1fd05811f5f864f12047 -ab56e7c534ee1f921351dfed3f3eaa127869849b44540b39b0dc021b3dc4dc94027e4161f7f3ed40bf42a1d08315264e -b9c62b4e679dbb3405733bbe0740450e72ccf39bf953142cce65fe014f132d5af5864ad96167027012c98dc8b8889e8f -82b8036a3fb6f648c6fb0492334fb3dc8f57c32779d4eef78ac2becb0b93f046dd68c2fea3b5039c21ce8e1efefcc685 -8525738182748d6f901650cc328ae498cc3c712300441042441f66c683e06dd741b644e8e98732552e55839b66f86b82 -b625cca7bf4ce510f21e8197b223dc49e7ce245c5a5d1e901438eecf7160a0bd37d0196191b1d934779f4b6a387b6db4 -b63d753d728670f3b63d4c24acc4a3d4859e5f15ad775e502fc50d7ca42b0d2484a8649eaaef9eb22cef28a23e10d5e3 -8e951028c0b4c5a691a219a6dbf348ef66edef60796094d5f6abaff1ad5802b53a5abec9b8b3b3b98f8b5858672847ee -b6b71004d898a3bddbcf7f730b8d5c0d8bba0f3b508155412446732ed9abbc1d03a90864f4689e6ab207aed495830e1b -98f33a74e36c035d9476b198dbf3a75573856264d45313e5bdd89db291dceaf4084917a2242b0a30d3b1ba4ee3016c42 -912fdb4358fe617d7981bf9a9986dade7fe279a0445d7b14951ed77eb88c77c4aff4162467e40fdaa9dafe78da0ab4f1 -b17bdf7a896480ae70b3696cffefbca468b57493d5db59362dd85a3da296e1162356358080c8b0a7f3fde798a3ad1d15 -b47ebba84e62bf453ab223496a892fea2244ba6c37615c3db31c2ecc16a5f9519dd79aa710ec1220a2cebd254f7690f2 -b3361190434ab75e46a40e0ce21ccc251fd0139bce90664bd33d9eb6400317c3210509e4ffeef604c7b05b260544e19f -966916b3966d7d33be49fa4eba925aa2f92adc2d0228d1144ef633dc5d67fd8231087c488b492688fa142a8cdb45ca70 -8ffb1491d4448af82b7cab5409ad26d99ef6ef08158c73a9ee9626c5a84d2fc6d852e2c786c94b47b5931c7194d5b82a -a2d4a5bb458688b8f593f39cce2b27fc05f8ee3985f4c5be453706e8f174d5a6585c2070c0bdbb54aa1d8e79b5ab40e9 -ac180389d0432699bafff42a4c3da59bd32ab1bd1c4b4a4829580577fb3c5eaf8aed4dc61a93262f23ac44255e6c2b11 -87f8fe99acc93080e2a2ae51eba24f0b146c1355855a202dedb7deb8e1cb5c6ad8664ba0e93ded5ce253597fe015fdc1 -a554d88dcef521dbf5e4823bcc9145c8ea98c598cab56c85f101ca7be82297dd7f361d457966bc69584adda6d40ecab5 -86ee126cc839d869c7e91f0f8d919929f66c1f67675ae8c5eaf6bc35866580c49d45ec8edf0891b546ec2fe7bebbd304 -970d74575be6cabcd2e33a8dacf25b378ce750478bb44086e1821c97b6b27055b7f00cc8ca189954f0150de7381c80c6 -963badd0cac713d8a23dabb8ac7da5e9a83ca7d580ec81dbbe3e5d53c5c9370b86222ca685215eb282c8f67a977b4b66 -8d2735c85136625b3f8c4196a8f892e276845ca7c876648498143f1897637807a9a5162bb90773099a7b0cdfaa292263 -a1a8507bb8a300e1df882651b0155e46a0f58399375f4e5f993251663b5935a76a02e60999a4851fa082a89d5cec2e63 -b712dd139d791a95486d8fe48e35bb8bbddf890435dbf8dbb670699dcfb143fc582d4bdc8a6751f6bf58a13dd8c2871c -8f108fcadbaa43dff904a23c89d809746a9f732be817c2c882ac3493624aa5e49af7dd9b46de7d9d01ae982bb78761cf -80e270c6620756d3d127457fa2e51592604f85479a1004d63c184d7d2ffe2eea4ff75faa436f24bd1494f4eaf90543be -81f039fce432a5d3bf9649ad0fc2d93de831f5b9c0d0e5fa92d35b5bf4a52c739d478289c2386efc964026134f91ac0a -89401011d51b6106855487a37459351f18c39f08ce90b15e52a876cf36e969a9c9fa6cad94a55b844ad45fcf1807f705 -ad66c149ad105ce8b53d38c410d73a3cb3ec910a9f0ae798f3aa5207501c7ee39b85f10e91b4cd91e6b280f3912c492d -b709445e56d02a558a1496bd2b9115d2635855b18984cfb908cbd54cd279d29ecab21cce704cd9ebcf34456dd1195d79 -851059069d9fef4eadf6ba508ca330ecb7436ccb91d09f5d0416874f9fbcdc56472d2adbaebc63a63f190b6abe7650d9 -a933c1b614e6d5a58c599b7189d06bfa3683995f449d636805c8307195d8e98b62ced873997898d6b1b01f6e6a52b743 -a692ba436613db22bc30c3f36a516971158d5489bf2c50c39d0627a74048a6d0b229606823f37a0832913425ddc30d06 -830999596d203b96329185c100bb7360189a50f7930286c36544d20e57b8418c71d8db331e4352a98f380c68a49b2005 -a56d7c262bb3d443fc0cacb2b61f24554ce35b8984fa3418bb4e271d5fe4f5378ef7b12c6cd02f537820040bcee95f98 -844a4e9a8c9eea0b6f929a80da9f4e4e273e999fbe182d3855b0a40577afaced6f8ea285595573e99e13b6a71b985c03 -b34df6205fc429c9b7cec189b2634d49a4877f22bb8060b9f7baf8c2eac4e1d476ed1f30fff1f4c019c65fce96abc554 -b3a97648b3b79cc513246d3d1722afdf7645e7216af233645fca6a2756686592635facec913d19acf99ee586436cb58f -b9cac906123f2a4aa13d5d7eaac84e84eeb0a1b7919526de5198b5475fb815ce556f8451c953bb0bc910c93c6fb3fab7 -a5e441019d492897de73d31a44a0055fd04e8cac894d626d0457ffe9de5394d0bf851dc5941790cba388b403b86864ab -8e3081cc7999d91d787e4c0937c9e22c959d2ba4be6fa04eb97471997ef150836a910ef28455f117dd54fa9ec655148d -98eb793d88faa691ecac3a7c78b25eb3a833ccfd0275186a63b1b1517bd2b984d9908c84e55f044b31c2dc5e251d0414 -b38b5454c2debaf1a4e9e467c6205cfe26d52d1c1dde5356c089abfd6a90dbae89525442419f108c7c8e82e34ec3d5a8 -942545089077b9f27304d2d6ceb3d549e983f100417e88332bf05bebfe8d42b75a96171ab3bcd049acc859f3cc9ad1fc -b9d444777403590be63076b5dbd9325ad58c1eb244dde2c9628234b62ba74f6b0e956642af2d08cc65f82a1b2e24bfbd -aee8deefc7ac67882ed7ee6c01c08d7739b6642deb2614064c69ea38c5c65e06cf609bcaf7db74545199cfa6122f23eb -b3e476268770abfe0cd64a4f878c58c027ff352569d8cf571bb067368e777eba6c003d344746fd006c8bbd474fc3360d -858137d63f90f66b9ef2a38d7ebfdae1bb89e5bc1d9032c96d699ef276aa2d7461366c00de8c47de9231d9ec436572b6 -a3dc8fe541c9cdf89d83753347d8c573c49e8471dc07b5d41bc48ad1b10a3fdc218adaeb72bda0f362c8af8e1194df45 -ac75940ae476a6ff07cacf70a379096786d10a5a5244fa5c466bdd8af69b1f98e97a3a27877739dd4b223627e0ce6d55 -8c6809f893c5fd03ca80d845147a82d8d54bb7dc6a688733b1404dafc360c45d5ea742f98f6a70ac2decfcead05d876e -b0818eee75f08ab207832c591aa783193aee5742147eebf75cf7f1eee6a6d8855b309db4f7ab51a16ab77bf619e14fef -b339ac167debc92cc9132dce076bce281e7f1b9c88978d36e1b5b9bdeabc974af318ff142f746319681764bc4db191e3 -a51dc040c75a8a8bc3b0ecef47ca313ae13d9560c782ee014257ee728a09432c4486a3f87b5ebab690231735fceadf80 -802500a52dc271c52f893b620952604b79d25ad243489dca7cd679b22907fa85947c88dc04463268d25dcccc8a6c34fd -97b136a881f500b07e5b0b79fccb84b93dd108074f92a1cd76e441239041ff389dbf03483fe76cf7c22a5f40b73b51f3 -9155dfb5d7f7915e50da7a715d1a5ac5b43d7093546d6d342ec8b69d47a86cfcb9dc11d8079f123854033b8d3e1ec928 -9423ac1e11f70b5d0cbbae48b7a5be8350387460631126ebda095b3b33a7ee2845776aa20ad60e2bfaf975722d43064d -afa907dc76e03d10cfbcc226e50e3bcee56baa4acd8db2cef8e484ee7b7bc536e1765e764180663710c4396e22fb4dc0 -8b6fb4bc641fe2147d3394322418e2e8e091718e3b54dab8d0d6bba687bc300d73cf1b17f81e2812f0943a8bbc1de538 -a8bb533bf42f56edf112b03d34eb64f6dccd57251244f39daeb6531af650d0368f6e4a0f9171aaf4f5a5b4a17debeb56 -8d763490dbc9a9b73bd571833afce20654348cd553a69678ec89454c4cdac044ed3ef0458cabdb60ff35af5e63405961 -8d3ebac80c55b7ce726f4cdac41c7e2f6a5ff4ffcd5f1803c463ae524243f136dcd15f9bc74f8b271ce90a4776c94868 -ab63cd85311fb9889041e692bc9d5c1153b26a805b511721154d28f11dc8ab84733387fd20cfa30c566ab2f8e066af4c -a506ba11063b14f25c26c92667dbd9eb67c8585d05d3980284aa19a09ae97599a1cf8d7cf45b70a32063f1fa3174d3bc -b834434632307602d9e046de6f625af5de673996108911c6b05d6bd3e2aee17246b2d860f01dc2d6415fa61c73110e13 -8248b69f51196ce1e15fcdc25d487153896d1f74818a5617500cf0bedd5180028e6567533536919156860e34ba275f1e -86a5ed8b6a1e9d8d17b69640220bb80c9065198c8f7610d4ee6a60d2d808508771a84d6bc679ee4db34f43f94315e0ff -8fde55abc106b2afdac3b8796f83c8ce1b90405532fd586d349340c4d7a4f4c46e2a56fe2663fba770a8004dc7b9d523 -82489db9dccdd13293499194068bb4ee8fff51f74f1b504d203c5deb5216287a6d614a2e0a769d4c929bc103582c92b8 -82b2d71281cf886e80e09ff907c1f9213dc444c058e965f964bd17fd36dc0382da2449fdbc3aa7b6d07004d6722a5848 -b0729dd38dd64c441e81a94fac0c8b5b3588081e43a5b0298bb576b16a9713acbdf09b9bc2499c677064619cb3a172c8 -97c4bd5c97182e80f55e82648e387c4a3362c6088381e96b67cf0f04bcdac3dc670890904180a5388b97002c70481235 -98d99f80ae9c59c921c6ff71ef01c2ba283f531ec32666cca1fe7dfd9bbfb09f197e9112af1761068cba8d6319af5d74 -b0569d892ce82d87a3d809f4c86a88ce627ed420dd106ae49b88b8c470ddb081a3dbdbd92d7fc032a7082650e4197ed2 -8ff68d42ec2dc5b13ff5c7ef506c619c4bbb0f62fd4c08e320953e5cddded2aa34624c6c5768b546cc2f00add0dda58f -8b53131206c80638dcff21d7f2dabdbc6faec545f19ab1f4f2bb858d6b01d87adf886072c3a744d58124b8a7a0c87573 -8b9c9aa127ddb950cad4fc21cd7c8eb802cef6db7290664b1773b9744836450e48af503009d4bb266ceac83d765b3b9c -ac61e051add512e749588e2549ff55f3e6fee5378443cbf64c80cfd7b260cfa63f16fc3e242aa140ea243435be28179b -9240700fdcde974f319a90ec4a9b92a0323424fe39e513c7412c621cb33072d193476118636bd2655867ed2816e03034 -b6b05975d0653079034f9792d5d8cf5743e1737e1b3860e431a1e159199efa5a55b2d3283f6d270c9ed3156a233e858c -a2ea8fc31294943a3a6d02509cf8b75a7b5d94de917ced468fa64a6c24ead4edef11c34782eed848792b0570219fb77b -ad0b54dc5dceb242c05a7f7c529289c8caed93ebe743f6609df653aedffbd7eaffceb53a18dfd109f28d14c80e1f7935 -81e4d4667900eb5a8434e2153503b2318f63708499534a8d58382931791eb0ad0522b41cecc7eb0e6ddf99002bd0127c -a4c5c329fe159bdeeaecbaf479c60c8f43a58ce613e135e9e9eed4af6bf5b6116bdbfea31c82bf0ba87c3f651e1464f8 -b95eaf48a9128df7f970754af926f9865c2078cabb4da4918d8b45e95d72748750ffd12f1d8d3f76cac0936ad0097d16 -8567385d52e6f6dceeee52f6b690781f7c05c26f0d20912bacc38c23afe8f64925ba18f8b6464d4a0557670ed0cea232 -8f7483cacd15fb7e49b2f8deb7ab05e64bac18ac9dba475666649c2cdbc5d6df0d5e789fdaaaa997a3b524521f0470ae -9252efa0698c0cb30dd431a72a0f5f2f14429f6ba50bb60f7039df45777557afe3ae732b9283b4a814d2146a8cd8b7b9 -a54da5287928a02cd5eedabe70cff80e56db252e2811842545beb14f25ab67788460a71ab8ee47cf0c1a5f8d01635256 -991a80279c622565a03929c94590f33cf0621a79b70a2168a41a4376bb3f0dd12a9ed9b16c0b6a4a59c50b5802449874 -924ff5d3a6f0ff4ee58c3674319971257543d2e19f0ce3fd0b0edb214faee920f8d6199ca794a173363a9fa06c96d7b4 -96b136b8df76ba24e4dcd68065c650fdc224fdfc9c1ab6410e008fa5b9580680c3c85801fa217917c620c86dcb5ce3eb -95934e64af642e7d45ada1bbe8b9fe972877a674252005afc34ec2e857f755ea0d77e7759ddb24255f21252d6c739305 -ab14c6bdd6d1ccaf69e0dfc6c832751afb70f89e4800c6fafd22db2e7e5d6f2addab8b1267c8f3fb85cee51c761e69f0 -87e2edb8dec1253547cece2a7e6934b0299715e634d599316af0f076c61726c7f2aec83eaddcc9add1c397cbc9fed0ca -91170baea88ba00fe00db375e8d948f58061f9e7b36a4573031b9996757afcc2c7e9c2d9642bc51402aa586569f0a398 -89d99b120e4565b0538b2ef4f8d8c05997cdbdf61840e068054e7f21677cdc1dc2f63adab1b6814225d14275c737b0e0 -880c2b79bff714665e9b3a0a647773a212ec5f0dea37ee6b29ed6850692055013e108a86affbe44d1abd0ae80a748950 -b564181f9ea65ca25b1ae7f25eee84b73f9db109ad1939e6b9351663ac0b083fc13e6518ad8eaafa3caba9ab959bf7c5 -93cd91391deaa726320574bb46706fd8e30ffc2308290c79abfe2d234d0f0f59ee4c38791e3bbd8c3f840a920489ebaf -8e846d48e7b120b59c6556a0394d25f744dfda0cd58d4e70029837753a82afb63a015e79157fe8c810cc68bb481d19d6 -b36904e7dd71bada7c9b9172e4a6748287cfa0cb6960ccfb7202a36c57bc28d351e1f5371c2b449437cd266f2d22e7f7 -8947c11af34a42f314983ba9c673e62fcf44c6c1f733a697351e1b8422a75338a85bb19149fc130d01492ee18b3c9492 -905afc0103e34fa9787102fbb80967b8c917bd03abb02731fe49ba1acff1e96059227616cd21080563e92dd021117a84 -88c7acdc65e6373e4c8ac6a13d1bce1d534aeef2965a4d9f887b2e823c7ee7921db1397df5cb5e7f12030e310172d6e7 -b028c19082411efe8a46c8abfb9936c005e766e2ad3120be774172f16419e2b04ba3f31132ed2bc209e7214c2d7b2b61 -b6b3a561d583870193226391ebf51ef47185ab6efb3556ae59106b6f266776064e5cdb66f0c93748e60d557db64e8f84 -93732aa1473dc2e50610eab2c8152f2d96992fea840ac2d82c6e2c5760d8c1c05e8ecbd69e14d03713f43e77ced9d3bd -9734c433ad41a8fd91e161de033a2a55189ae31e2af406d1fae443a182bf1977dddff93f6fe2ac7d9c4fb955c26ed59e -a1f305d17c36c06c515d30fdfb560f899e80a2e2461d0bd947032e5ec764116c7ccbd528ea42a3b9351e3c9b45904431 -b517f46b582655e551f766930637e8dc2a762dd7a2c54fce429fdc4cd503e9fe4bfbf323f50860be2c18b3a17d528654 -b395b5c48b1cb0daa8c156188b390a78441c8f16ecc8650520f9f2914bd1d992b83849bb11ec17a47f9f2d40d138e3d1 -9147b715b62fd50e59bc96d210e10f1062c87a90263b5586746325deeea89e759464be55a09b0548766e13bc910c4d3f -a7dfe5e7a39767d14d531d371b92fc4979d326ed0f966eeb7b4b4252d78117bf5295b3c17d1fd636dc2c0097cac901c2 -aa3f9fb858b30675e9e57170a1835717521eafe4bd0a0690b10020c7a753951576b4c7dc80cf9f042894fd5741b41b1a -a1f11dec034733e862cdd4aefaf0252a9e8175b6d4c834b7a7d30ab884bb6ed6a1d92bb0e958f0082085cd80157a0e40 -a1751d7452b7c5596fb801466d8d07a70831e568b8ca66fdd75e5898739709795a5768726ebe13c469b1d51092d86a60 -80acf49051b7caa6efe78318792d05401f5246c5b3bef25170b2a49adfeec8048ad5a5e6d50cc498b23896176a9d9669 -94156df9959c678578ec6e12ac068f3a28d69a981443fc35161d14b1f0327b8424746d62869ea9377a86ca6fd2c95b5e -95dd91b1e9b457de913a65f198dcdceb1fca75692853bd5ed44eda6343f32126e6aa2a309411e019dbdb9519c865b96d -b2516bc36a726cf2dd5553e319c64fc508682c7446a2a5ae696e43f1a8c129ca9602f5a41bfbb57865a9dad1d56728d3 -90cd63b4f9216fb70635e4dcbc9a6c5874cabeabe4f9ea83bb923146d03366d9befa48b20a64f3a2cfdb0c3a84007ab2 -a55bfe9b33781501f10d5632e8f5330841eba2d0a64b0aaaa92db56f014b5e44dbeda3b1f5b2e4c17eb6a243977b2a82 -b9e84b3c617708971f5e174fb8718906f9bd353f8b0fec8fa03d1a6e4bec20430212396a5406595343cd15777c5a3f8b -97deb79dd82185555442f91fb9a70cbd30a564751528fa0df0a681315b8a71bab5073716908ee0546d70dc41efa3b53c -ac77c2fe555584b9cba7438a4e3904958f671c49536f185cf1f3b25c5a57ea65e15554de22def94c5c623e8c99e47a9a -a27c62d39508552d79d2899bac6138783f308e3befab65a96a1ae4ab108b799628cf37db1ec72859a0ce1ac68f68b106 -a2aa287741f03e31f2c87fc37e228279b1acb886f32c6438b3e9807b8126da875fca7f194295c45531e939a13048a882 -84df8999c4c5ecc807819248957d68909d16ef64d94a820dd0d266cddb6775c9c7464f0b2385b7bdde8fc0f2169a4177 -8388e1a1babb941e03806b392fdc1bbe1a01438292ea1db4087b010de0805be78cfa56d20e9ef7c8b6be5a04bab1b1e0 -8cb6ec409cec27e7c4537ee2e5bcf82a33e7cd4761d19059e902b6068a9744e897a6010e2ab42ce72625cbc433892ec5 -b6e71cf74455b0f506e03eecc0976831ec9a56eb8fd0e39e5e12ae199180a4c6e5123174ddea6ce6cfd7a414cf0afc5f -815dd267d9f67b4d229a798a499b70ea2a611f3bf2a9d3698d1105890a2b6462fcc7c6ebff0d5d709707ee4ffa981689 -b4e5b7fbab4d8a66d1b167a5acaa4d53949e1fbdb00107e62b727b4b4b2cc70e2685cd4a16266e8d13ab176f9be09c10 -8d1bae7566ff551f06baacd8c640d0d04accdd49fbfedda0841914aa1bceaf9f3f27344b80bdf5f9b93ada438a4e6d68 -adb054123e27afd4a691d2cd808a3232ab58f56fbd514935caf47b8193b4c64aaafed4d08a7a10ec4deb66be8c292e64 -8ab5255246e01478ba7dc6807c84850308a719f8f8433eb049d5b11cbc361c08930722e7e5878ad99fe1586b3d11cb1f -90e862be1e3d0824106da33aec437a87dbd2599aeb58d46b4a39a5f651097d49943c3248a154e09e309eaa7abff3d500 -abf16f35e3b2b29a72cd96802c900fbc54100484299198b2d40cc6071945781cc9bb3eb43f6ebe433a14c1aeb172929c -867a0f396374cca7303845d8a1e4bcebaa53cc0fc2e790dd58cdd0b5ff2b9a99e18ad4e57aa2b061826545935a5607b5 -a6b6a2e22932d7c9ba8f27b1e1de8559631a81effc77ed2cd7c45c48e49ea7d2f68c59d07a155757493ad82f733d93ee -885e4c3904c545c0eecc9cd02e16d359ce69a78e3a355e7fbe6485762d4523f2604f2f663a4521152a8bdb6fd4a9d4be -a668f417391b07a35c5d40ee5212cb7bdaffcf040a4f20a3d7e70e9d715bd908d4f8fca87a7dbf7b676e088ac8651ee8 -a70d67f3379e1ee0708c34c4c7a7f552267ff679460b9d8891549077c724becb99ff79b35bd80420a4290f293ed4133f -a523cca782ced0d8a3f7e19707f9c64ff38495f739e035bcfb5483f202b209c07c50c764eb28d3bd8cf68ae093c46f19 -8ce98e5f96889ebada090449ae198208cae5c247cc5f6fe7800b4c2254b0e7f2475b632cbd5021a0871b466c5b943dc8 -a69cfdeb27ce1163ae6b6b4b5d46b49507c7e62789f2f90f7f5a0fdce79de988c755cc9afd8397b1c02976e03589f985 -acbffc94dc0445f7797a0d83e5107ad3ec8bf61620fa83e73a999ce4f9b6bbabb00245a619aa6f9b082a2711bad5ce8a -b64162794503c86e478c23f060228105bab4f3f5d46582bd455a94526aa6d71f4c9630d8d63854c8c67aff3904681e0c -b1288073c012a0b2b7e31708e874106031a8cc98b2c94ad0ef1d7b9df42f429f58caef5494f6d581baf12970cded2a17 -8d7ad217c3c1cb74cc301540a0e43be6d74d5a3c0383ab7c9dae57e25f8725781735b58301ebc014476171725299782a -924a33c759249af270617767101385910494724a51fc63600836ca00d06f0ca86a4a0a85e5e87cc29e404ff8e04d036c -a7b21ad39bcacc96cd857328a83e5d26cddd0a5bb2326da9a8f593927ae7b5927704acda9ee217176618c964d0452d54 -a5c3616c308bef98807a852e16f146859b0b1f31ea8a721941d90abcbe37eeacb4403c6568480b6d6e773bbb94a89307 -aefaa1033e47673ca2b68e4c945e6ed892e223146d4fd24219304c2667777c1b18a19488b73053cf7b0e6e09ba1278e3 -b308c690176bc43051f51839d3ae1636f6de5a57c626e8def464820ce2f96ca09ff26294a3dbc9b4573cfc42dd03bbb0 -8f7b1253ea9e257195ee92c54de41f2e7a310c90602a628ba3180e059e5bba79d6bb8110d1964c59daf4b65cd9735704 -a387f003f7731b81bace54c8501a3a2a25d8a910cbb28dd603ed16ce61ef1df34e233dc8579071856d7198a071efedf6 -955ad5523828c0fbe8ad6a77a191661ee9c8005b741b7b0439b76711b6992795758d76133399d266df5e494e4f86cd67 -a44441964f5cad7b54d0105f162ed3ec40d12870fe8c5c30bf16238440143b330ba986d6adb00c9626747e99449f765c -a52df726de07cccbc77e81abf4f1712657c9261f65feee8815ef0e8a4ca61b8e470503801f1da8a23fe6d52f3306807c -b5d239222c3d852f2c49997e76d97b70bcfe73d85e81258d9781f5f7de87f9c81648bcf58cfffd554e4685b2f860e6d8 -96f0193aecbeb1540678f1a3369401e916ee75d2a85f7124c555466a3def91a5d8b5f774e3156a163e1010690d457c5d -886b9f4965120d942b076d053571837780232e139c3efcc6bd6c64eabddbed2d55c3a9a06001bd7a2ccebb36135edf4b -897a1e4e9f4eaf755807bed984ef0bfea251740386a168061f4386819acaa337fa6d3f038b4cff9a11926e68f7888f90 -989d9706f8396ba422a34b55897b9e261ac1ba0c7a7a11a30562ebfab92473b9e9b604ea8baa6067137a4ded070fda10 -96376812651020f68c6a1f0aecd04591fdb628051f01daae179f7008ae33af5abb42e8f304662c9b6e2584e8b02ba6a6 -9344e6f3ce42ada6281d0fff654f408e61f0acce81e23ce47466bf1145a99cf60dfba9a22304efbb1f428c92357d644e -b90c5463445156c8de69d8c35db656a76f3e195c325808396a829c11c06a7503f3c092816b3f23a263d56d3f2c075ff7 -b4dc6d948f4b67b513ce27fd12bc8efe43813c119d01b2da391d01c1cb0abb7d51350a5446e0a72a6f8bbbde2ee4b0c4 -84d208ab983941bde208fd71d58c7f9335e14db237cec42df453155a3a8dcb21dec8696a1334cfe5d035c192fc44e88f -9577996c78372d2d6c9de27d497afb29c918bd894bfefad9059bd85cf2ab520ce1d517994724e1567f12e385c126f26a -b778b9054776a2b8ee81be356050b977bc8aca0d0a202be91d56ba89d8a384bd29c5c652ea084709d4fb365b107962b9 -b7ea99f8c841678dc854527ad0c8ffc700b43b5b36b3d18303e51175b3901b144c53e22eea6ce7cd500f6879a80a8c21 -b466aa7d1a5ae3d9aea240c8114b3dc3af38f7d8f1e323800a6382de5766f19626d07cd6ca6eddfc4d71a43d2d49a07a -8a72b1ee7993f16400396982b6a5198f0de08821431bc66489189d5b364b0e36daff5077b48aff1d55c9a88580cd1dc2 -a7c4dd6095f8cf61f42c5901ab67e9d1ad21a42d1eae9ca5e147a9396507c7a21747c2794f71ac66002840f4fa4e1dd0 -abe40e33cca787e7c521e2e97fb5f95cd4ca7ad6148a505afdc94e0c003e4903b1524164a1df2b2a1330fd800ac33b7d -ab8e1930b1e592aa2379cff636e7fda9fd7f05b358f47d9cbadcfe35fbdee5bf06469fefc052f62159c10942ea2bc5af -b28edfbfdcc27c3892d64e7e05a2aebb173808c020186c225590b03d91dacb866108370f2c14ac97a6d20d95a8e32f8a -97d4841704bacb06bce2778104e4437c930fdd9320d85cac383d11ce9246525ad5167cbd63ef04a8ea39c8fbe3d88169 -b4b178a1c3ccd3344831936b784203919cffb611cd18def1a52ffa2a8e4286f9f9681bd48dff9b2abfe62da5fd619fa7 -afb01a4777a128b02fc22e282e0c4ab1d86246d8e0813a7e85c51907bce079766ae40c31d3c440d5f99c92e89d3a683e -91cd070a607c20140c1f35b25057bfa20290b1435e99c5b33068c4e5755ff8f1aa2be61fba28dcfc131cf881aa1c39ec -aaac82ccda92c6090970f60a56668c011ac20dcab26347ad40585a60b5a9b5a9af883307c55526d4eca1b110a079fd3d -a7480de83b4cbb2eedece3d3b27b8d934e9183f448d56d5f49e0b63e24575014a94e09d406d7ca5afda08da9f4eafbc1 -8e568ae356775b06d963b440f75bad9b5977b7bcfb8fbd1dbb4daad5192521bd189674654d4ab86ded4a6be5fee27ef7 -a501a84cd0b4138383572fdd09242e3a748e593f55400fa7600698d4f916a2fc1feb96557a34f4ef0f13eee580fe9f54 -8be0f6b98d52b83e9deccf09d05fc4a7b4ae1cb11972f01baee4fabdb804cee2b0e9b44a1385238f755d2c1ce395cfa5 -afd01e3658ed9204d39fcdda2d79239b8c45dcf80fda8a680a8797b6be294e7e8bf56ce345896c3f08446e9a2a053a61 -851f0def025a50910bfb6c2fbe5ca62a31426747d9cf4634c8faa714a014fa22586c3eabde84e23ca77371ae25d720d9 -90a1aa7bbe7842cd361d0ab2e16203a56318885d2d32409370ffb64ef0ffd3c8c57658573a0714b04dd1595aabfc8f21 -af56f30bbd796de5cbf6f3d041c2f649d0f36e0a1335ba923eb1487e0b29d0ab307a1143e6cabb79674ddc01dd9a5cd9 -8429afa5476d0f3a4eed4104fdeafb79f80e94e709b59aa44b4caf0a94bf75fb3efadf76e96389179eafc389fe896efa -91d8399bcc3b82f0044b9a697b2bc402285f6d2e7b76eec25ffecab769f3fbdd45d20897d28a8676f090edf847eb3c70 -a06f8d37404ae58c35732db58c4c6270e4311c691ecaa7d89b3e9b2bb1421ee3c3cde555d066340c0f2479faea1ae162 -8011fcbb711ba6511960245c69a73fa99167eeb4d238426bc31ce359a90a2339d5936042b281f3ff3eb976357db96885 -8dff2bc19830b4a58d2cc3c1598d060da34c8fde11635062dd4222c96dcbf2bef79b339c63fefdb1653153ef9af79c48 -84ae7869e2405e326bd167249f89c2e018817d3edf59f3db8adc25f64836ea4606c78158cb30020a54551283bcd9f39e -b7be6cfbb7cbb7788fd60fbfcae3504d441b0af3b46317944e00a23079c605c08fd116311432be5b378ed8a11da219e7 -a3656ce4a79484e365b6b7f81a9dd72a09746da16175a61794bc5fcc0c3dd608751ea2cfcf7bb0c14421e0b05d94df75 -929d5603a936bedc69ede2d1277692012d0c820a23915ac6e776b832b9f4e0e6276fb3b257c7abbca32ea166d4482149 -82d47138de8b6ed4bdaf69526ace4f6fdc50fe5abee63f1c6d4447fe4948a84a63b7963c8a65858442856e282fabaf26 -8f8b2d05e77e9e4e2cc5229ea98c5c02ef9d9b6939ce6663d98d8e2dbed73af3d41628662c354972c1b48157f8d3c459 -9353ee31f477b51558f4ba5ca437d801f59d01ed995a8801552f8c578d1937997bd76c31aedab99fb5532789e72469b0 -941f777fc9115fe948f3a979e1ab87f133238935acdc19d33e1d86a1a64924eb9008e91bdff8d650f5e3ad06db931234 -8ee79ecb7d07e3a5fb80ec15c085898e97876448685891e09ebee9aacd5cd0147715dc60b6f75b601fbe83598f1a939b -a96a50de4fa25367706c99abe9dba95ce1717483f50692bde7c8c3a6b427d02d59ef6e8bee82762fe774f5afa528f0d0 -a451ff58246340157fd94d028ce1ebe5ce49e5ed87d9b61884c8ad903ef9b697c4ab9e5acf66180a89a17749046c99fe -b12739d77fb96e9e93065fe279307eafb11c795da2b9efba4cb239425faf687b9762235700d9f2cd5df9cd9fb2b36e3f -a665e34895d02e68f1dee7ad8090558514720ff3e809cf46cc06d1e1274d219fd08781fd430367a3f09e2c591dfd7cf4 -a262410cb60409720ce68935e91c743aed5eccb4a0427449f32a4acca103f9d65413290ffe2cbc895e2e1cef96ba7c6e -9597cf4d49db896796132aed4bdfbec71ebba08a617a611d1fece75bbfcce902e8ba228b662d0ec5fb927429f082eb38 -80a045d2bd30aff2267a5385be12c646b65b24a586c4f5cb1bdb81387e3ff8edd2358cc8e3c4c5c60cab88d4dce61d90 -80323f4a9fc78bc89aaa172f739bbd4f57f9321a7b8e9eddb74ee5c99d6c7b8dfe847f7103110f0a44d4e7c20ed29114 -943b749ab77112be7593bb2ac11094c66c94bb89d5ee2cc05316ad623a3997a38aec741ec93c24770adc670b6ad12e91 -a8e1b4935aad8a84112a99fd5a4d3786ccf1c985aca0b256c46d52a8801a132024391431cc2cfee760c25eb18289041e -8abbe403bf13bad914a4d5bb0c8709f5b264a7a81ba0542850cb89c3c45bc294f62b22a36d7f829ca80830a3be5832aa -9084defe85d170967c08d1f5e74ad1dd592c2b013b01b84b5fe3f2ceb260bde2e52ca22e4006b07f01e3dc7a36774e94 -a34cf1cfca622dda528589b5e5e36a4a68cee7e18cc621736e3e165b06a5df9a8e9f3ddc406838c1fe94ebdc44bfaa18 -8c5f5d7e98828d0a063d90d5f78bc493c46316fec3245d47ef8900241fffd5316e0d6d6f1653cb3b22bbf05286736c06 -ae7f2beef46b6645a6d0b3ca664c826be205ca6de35bd2809a4871f19368bd2c009ad7de0cb4c269c2934357e87c7f64 -abae2cd1ff7320d0803b6b5345ef9dd364fcc001d91fa456199dde24f474ff3d0ce94d460be9659caffe7ae0a6814217 -b86710fd69a6eeca8a813c7c1d643b487a32cadd70013a4aff4b7331ec08d1469fb17a06d06926e68f546e7f5238e1f5 -b42e9dd8d0f12f95a16112ef7ea60e6f4c76a39cb64e7f6bb4fde6ed1fc54fe8317e93160d736d97d87ff7af69ac2a41 -86e5561a7b621e68afda9d63945dc69bcd615cc099c84ac51ebf6350b25c9c07ab371ed5b160a86488e8213d143335fe -831c730524214b8368bdc619e5c7e55a0731b6c5ddd035e9d7cd90577a472a429e779efb0ce47320c8d3b62997eec0de -a3bcbb6c321b329ea2bb944f48ac984f8bb6cbcd38a5f80e8780257765756cd902d252a51804879104527bc7b251c1b5 -8b1a0ee0219a010653f816de88b05116269325c42811d717544468b3bf477953900394a71d56b6dea13e4e6ef9c9c5cf -a5d06e2a43d965e47d400343c093d64bd5d4adcbe3928093c80439f815938b9e952bf59da7fb26f459a5439fe60fd49c -b92df54cd0515bb9868a8dadb2a808d3e62fec12be3c708fa6c845c833c3321017e2f8d71f10b064fdde02b098e22962 -afd8fb1d8ced274650ecb6c370c5bbe8f09d263391af7c2f2290b5c99196ddeaeedc8b9b6173b6fa349872f58c83149e -b359418883d3425b1bb896a9a9e2a3068c19abbb18ebaccadb85dee713b14bca5b83992cf239cfbb73adbe2f07c63f04 -b8cb045dcb0735b02d6e81d9aa9906ab2f19df2e2adb5bff0533022c03a9a530bb27fcd45173faac63a8d13bf0f41565 -b8b8ed443891d3ecd807d3f92d8c2afe714a423b97019cec3690c24002cd0444548ba6b454e1f9934f01a419206896b8 -a3c28de7e71c54dfba701b7e1053a1719032bf48d0e520bf8d513d155d588d08d14af3cf1e9ba3083f8e59dc947ef99b -a94d1569107e659db2ca58864eb8feb03c83ca083c75a6d949805faaf7095a4f981cbd1f89a464aa46107a891ba758f7 -a9c98b0501a8c5102ec0daffddce83ab40bd097c4ccce66a8f8a61a3fc28564ce5dec37940092640b36a0ef6efbea4a2 -a473b784935b52ce73755894177ead52cd9f2a10521e9c034298fc0461aa6cfb03d499812189eddbce4b3cfb58774a3f -8c7a7984739a3db7b28b7ef10f081e2cbec93e1da39738d082898fc73e83db206fb52cbec476c9809c7de61ff5871b71 -88b87148a573e576d0a8fa912858b7a9876001d8364bdaa7dd2759dd908555119f6f580c0d3a663ff5c2a2bcb05fef99 -b169b58fa10256b2753221aa33dc4f0f3308a294b98300528347ea4e89128a1a1da502990c9f2d266fcc10031b3c5a07 -85b1f0e49528ec8e51112771686b5b9f18e4cab091f6f97dc9a327221fde48be87f59cb46e6caac6e1af1a8c70135e66 -954021598c24f5889a642b9d20488a04e3c78c5b04bafcd0a01f377cf24b49f64b1d820ee8a73f8cc193e1de9a106a6f -8954b280ae11638d6e9c27f826fe66c0ec584fccefda8665f75e0699ed640e8e74fb1945753f84baf606d2fcc804b1a4 -899303d3bfcf48d28aa49e915ddfe263117ab87384f611bf7d555ed141dd728a39b97eca74b6b623a20d44458f35a157 -8d792116aaba18c94069cbaf0da373c4e61662189e8bd0f24dd675531ee6f99d574f91844ace86e3d018c4603ff0e2c6 -876c457846f27161c796f2d063aac7f73c2197ce707872c828af81ffabe91a6f353c6e887464c921718425d046c0a722 -a0382a36d4f8007d444643bd5d85d0b6c3c892c7ef8158f51c878b13af6a5b7c8b098ac7a6e3241a6e13b4ae987addc9 -81d668e292ae20a5a39b55e6798255c39368d9b83ca46e986c343ff9cf4f3140e3f07115995b8fc2554dc0372e4acfdf -85e58c950d8089ebd5d0a9d852c9e78d1e066c4cf1f1e64b4e76356745d3eddc13f1abf177dd32f0aede2f190053f8c9 -9420d1c470588085057549b7e6544aca2ca329ac9b232187d8ac894b7a878d6d3ea351357174089943b43a83f057ab8e -b6ea12644c6ae73b8b9752f8eb8bf06312ca14d93fddeb5f79b92167ed78338964d620379387ffc9e12ac0e323f3500e -82767d1ca19c7672d38216bf17a8ca0a52aed5dca77684da56419430f9129ed25b6c547fce50c834746cab666ddd43cc -b1864c611fdb1b641708a5be8140ca0ac52d59d7c3fa3eaa10bd815f7f5e34413751f829f5fc0faa259064b73d43f4c8 -92f67f02d17a1ead3b01478687cf26b40fb32f055f3b34feff21de083852460e02afb834f61c37fb91100709891379ac -b640a52bf00e4b29623c9b150635391b4dd42f0016e827daaad7aeff6e6a64fae4d67193664bc5bb368c72b138c76efe -941c8aed9a85a005059b83d35f6a70dae2e2b5f645719b567de0da3bbf1d2b85704ac977970a7206bd98609182090160 -aa976af6c9809550721103fc8bb8359cc4313f672421a4ddd760bc4ddd86a036c1b4145049d9c8165335309fb608d6e4 -afb11dfe01bb6a9d2cc2c040e18152645b4aa972fa01b6cb4285312bcb11a317107e743efb53aeb4bb6f8a7fb7741f50 -95f8f780fae2878792aa3f60eab8954ecb107942bf07f0e2854173595eb2d4b914f4aa208f98a63b0ebcfbca46840123 -b1dbec7871209fea98676e68d7a02dd82179a74e389bb9dc0eaeb2ac2d446d26810146586b637869ddec4caac8281bcb -931c9d571e50dfd2e1bee0c36f42085e4aa4e7d80a1c3bf99573d9d09ff710f6fa27f30712daba107d43d263b226d130 -b080bc730ed34724851d00be3bba84093a296d6320fe7671a83364ab1faf922189ffe997eca0e1ce4ac2c4435d7b7f10 -8dbbdb4f82398c891d16dbd4169716e078de5d677d3d550fd3853ff6ac8d15d278f17a2950333545bab823fad09a4922 -a71bb5b71699082cc45037805fcd95e410c29575d229a556a7c5f2969fb6f957f0c63861048c65d5b73fc4680a5c3c70 -b5bc06a742016a20c60d61cf55006cd7c2c7b8f367968f279815087b2bda7009c1773b9c91b8a4b78717b2bdf6a5e96e -91aa31c68634a81c9784d0d6adf4dc85c981e122635d4e1f25604c8184da860b1292d65324d4bb9bd8a002572cc96bff -85484fa47e235410e2ebc49f4dbbea9847ea064f6f6776dceb0d868280fe88bf6c5bb72e24c0ed3cb0a3f1d96ef8c9ce -88ab35f32986f0bbd8502dc81506cb18638298e856934fa374480dc455463482ca780385537e7ea73c4c863107b74f7a -b3022847a668b6d5d52d0af14d594c3e842afaab5416e3ffef21224bede0e1bbecb0799ddb7e095623a3a6f28b6d5f43 -8802d0e6e5203d0018d243301c57934ca85a002f91e5763b2f7372816c7b3ddf719c3b743f2530d9b7330f4f35d69d83 -85709fddeaaddead7a27d3f75e5ac568b0c9691c797f1505f5b33678158f5dff96ab98b921bfbc83368c6763420bf949 -a45ddf8ed1c273d61578bf6830fabd4927f82e3efe7732d64a1c82887b9693dcabdad1e7a65f09bde459fef89c0eef82 -970fb837063e059b1c2b4ec88011131e8cdc459daa1e704095bd327b7c94115c57cc1d9e8b4a29d6cc4f20895e309c61 -b789aabda019356bc5c5dcb015f8e7c5da25150988af0d44cfb11d8702da22fbb43f69c4af889dddc0647745d162d91e -8ccd44696d8c52454c833b0b256ed0073527616ce49ef25a113cb9f16d41f39d27e3bf169ef0d3b2fe78f2a5910ec83a -9846a3ae6a2c339b09f53b6cb1262114d1ce2fa3ea43d77b04816eea6451e8620f0030ba428eff80d72d8e907c8f9e3d -80c18de89a31e2c8309353be974e42ca97dcebefc1a914e76b57609b9cb7c1c6298e2ee1bb35ab9d587f195010d24337 -a43ac7ac3798af0923ef5bcf2342550aef8551c198a31b0bc9015ecb24fd2633bdcffd84a2c84f9eb72b4e67084caed4 -8cc1551213a33114c8e6b3e00c68dd26b9cb3728376b498c95aeec60e7506a3346641ed5297fd4ead33c0e42b85079be -afb54536b43e311eef9f584b8f1074866f6d33cfc75a3294aad5aea870cdbc3c97ab6e849ef719e2e1e4386a8a360fe2 -a2c5a2240256c64673372b63359b646dcadb108d785b4fb16a165f4b3b0ab3dc3dd5058582b25ed7b728d56d5aa45649 -b35e3e4407b63edf3eb567fdbe03eef00dadddcf41b799c80a9c9e26ddcf0c6b0b9dc4df0a0c5d54bf31ac8273740a32 -a3ce737baa7e1c1c69931a5b2fe1493a06fa0dcfc0b819ef8242b4fdae8d63bec8d15561d4fa24ef6d6c3a326d0abafa -910a67b377fb17d3f9cd1f994db52eb5f35a4aa002bc1b7208b259b12c64c095e4dd65ffe54772f8e2773923a890bc97 -908c5ee131dea3f444a9ee2052c93a657d28f2f58e604bf08e51500a306decb2db964f68e87d5ac2f8207cc4e92adb09 -8f3de5e756409b575ac2786590fc85de506f0adb51450f5c24669bb3a688f080c1cc37cb8e7a3c8db8e25c49a4bd76cc -aa62ceaef91fdf09d2ac2edbc07fcc651584a7e7d7d93e7bd4bb4c42105144c2da32326b3ae320b36a2df8aed07e5610 -959fc29ce63dcac2b4dbe8180577cecf9bfbb6db6505d76aada43ddfde5f48ec8f6fed14fac19389f6c9ed3555ef7882 -984cbe54156763d6ae078d6a8205cb6f9d63eee390dc5990f5d8e85b9a19fef563653d3dcc190c9b18c2232a916b1409 -923b448808d9ac04488e8345d3fbf9aa57cc3b3f375af138b674daa0e5a864faaeabed08f94010478543f3e1248c699c -8c0823bf2706d9aa4c074673e9d221eb021de2baffe8b703e64e676b6801da73440b7793254fe4c8c48d2ff395e44bfd -93c9cb050494824aba0d57320e2d1dfc95c988bec46dc8d73f7036be9ce0d7de02e56ad1ea3dd8fc129100800aa639bd -9339fa01caba0f4837efca7a3d983fda1f6a479f63890db7f7beb837e3f6535b1f1d0788884dbeb73fa657410a4ad308 -953f213ec904d4540b356d53eb88f646a98581a6deeebdf99a6646cf612e5b07110839d46c57b76545f6879f12371b10 -99a4576f12de20fbecd3906e48dcc784cdbdf7fa0843c570c6f59f13cf3a559cc1f4882fc1d31015304090f83306280b -b07fb8b73793a236e58b7181df5a0a2e8d50c1d3069c475c6e178e32d14b6e75c45af60a8b54823c23ffbb316bd4a98e -98781507866499ce396730ee91a08e91d3be337690f7195750bd43a601a8f78e9475d5ebb43e347934429a4ff3db58b3 -972a5a21354beadf80d8a6e449cc4f072d6b747de293f075b8e0925c89660db9195a30188dfc8b73dba02467ae02913f -827dd2e21ca88891b9b37e10f0d6b6304438cd6aaf9cb125ea7ed822078a233f3e1b49a8bc65f843e9551691b46cf91f -ad3a4ebaccc157a7b880db6990a937e2d230875f509ce864fb0b7ba5febc7f4668191bf3aa55b85f3c17ce8b7d75b349 -976672c981d106fe1835188e202adf6ce77314f8d7c8f797aacf25f00d57f8cfea31b057f6afcb40b9f97df6ea387979 -8c77ba87e3e8fd5de85802a764b719d67f4edbdace75433af7fe966d3d18a94778c4414572b84f98bc6b5993a3225212 -84ca9b0435001c246143e50487a55349bf38300cde86219d29199e2e9137e262a1619ee7d6f6c44b9551319f1ea8526f -ab06e3313800a7dbb970145c1e89b7849db8a1e3169560fe2c64956a1f9d1d3157d531713a8d7c2213356b22fd3014ed -a0d04163ae987227aaba1ae82f74fd1b44387501fa47fa61b66728a0697155f48bb44b9eb5e87050a5bdb7605038db12 -8e76d3e50853ba5945610251dd18736b8541bf72bd643f6b561cab1c028dd044c820fcf79a5b45882e7dde0ba6db164d -967ec8fdee2e6d61f0ca2cc255f4e72c41a9c1a62150318be0fa508b424487d9254ad135fbe8dcda55caa51b9901eda1 -ae25c496f872f7380d9c64fc9bee0dfdc0f05cc1d2d6ea7747e166cae7e67c17a72a24a9e351de15f52baad355625d7c -b8a95f3bc67ad2a2d3cfbbf2de2003b7bc894b3f99f0364fd181eb11d154a7193b1df9b671a3a8eb8bbabafeee2d1a86 -b79996f818d94842175b06650a1e7819cb12c96b6ba37e61fa14b67684c2879e7d3884fa6bae06faba009329db2b0d1c -856e1478ef99338f144757fe4be68d935f0069a05b0a6209be2fac9ebc5cc669c6a80825d3c74801a54ff8b1a3777da8 -8024798b150aa722dc599f288cdf455479763a9bf776da74d5f9cf76026500e5a0282d840e5ae5451a0e28d507b397a5 -97cb767ebfc0a6cfe25666089f85e5a3705c108096a38151baa22308276ebf7cb3c04079ecd130cb8cae1689508d4bcb -874ff07def0f8d32f2ffce7cf31a43e8bc5e633b279acd7138ae938e46889e486c092ac34924aed9a4e1f93a91994211 -ab5b6bec8c81133b6edddcd048fbd526d59fc8a1f5acd7aa72d07852696faf5e8d305e85077450188cddd43d6c1aad27 -8402f5173327a95438797cee3b107407e8b277759c942bf1b1f975dc63ab89b8c43f0f4ce2a11de6e5727e9952b8923b -a5179a16297f7a0913ba61d69879014b9adb5e41813ac33acb8973e2b43cbc17a2f9a7d98210b39471a47b534f0eea23 -8f7cf3928b51b0b1bce18a34da935e7e2558595e4ebc50cc1cb698f0bf3c1ea0050aadbcec33786118d791218e1734b1 -81552a8927942591572429892e5a1572c8bc4fa7901395a5a2de3ce9f1ead122e4e5ffef6cc8434b3b18af1aa62e45b3 -8999a1bf4f22fdc884f9310e7a3f5baa0d32c04e887c51a20736cff3216f3dac5bbede43632d29704536d7f275b0be9b -85d9952816412a890a3e479025d1c0c8858337498ae28731ae23332c16a788cfe51fa9836bee73d03b253803096100a9 -b6a736447acaa6f4d83998973cd2bc3e12d34c6c076880e6765513c04087eeee5b5dfe9394c120a85bec8fbe127f1f54 -89302db4ea39662024c748ff5b22108c0f34850f0fda476051a89a3eba0e02a2294a4511666987d89f3b3bbcc334fdf3 -88ef018d32e6b379cea9ce35d1c12af698d8241c4c7468a5d558099f5101f04ac8e49d09b6bf031a811970faf02ed0ac -b33afb11f73195a7132430dc3961252251aef42150e9aa63a8c7cae724f467543a4afec289bf27e10ccabcad2f7f812a -b706315deef0529725fa6c4520e5d320a028b4607d47fa6c4c8ca3558afd68ed65dc072a354d263d20405bb13ca119f0 -8ba035d75939c1a3cfc72a9ad3aa4ade105880345eaad9286a182950368e688a182f6175357a2e62d977ff7ae08959cf -b47ca04b80107eefd3a596be2e990f5f021cafc6b7fb64cbb78802f9bb7bd2cec4f37755c451bb1fc8786a076e90bad9 -b6fb1676fbdf6cf95add7173c264b820042511e34dbcafa76273ef5e4500ad1208b274855985f0eff5196e7200e5a8b5 -8c7493894853f4e9fef5a0143dc134f03eeeaa10c80c5a72afb12f10ca5207df1c7bcefba6728d61f3f89d3978902629 -97d14d9debd4228be04f2352e57d9c8138d4e40228c269100930e2a3f6eb6e66f2f99807be0c9857082ff8b9a089049e -86e327360a19f6ddc8d0362cf92fa84677737064a94d9d0c1031bae92b85abed36193428199b0f66720be0d6edb0d28c -ac79bf758fe91d47d1ddfba62bba87f5e64d93f82309d4d07b62d78ad6ae95908e1989299db99ec52c5ad8c8f3d7132f -804712afd93328864a52a9f9ca1ae148de26fdec7d9f51d1bf8c0385959ddfb639ae0904c855180dd418ac21f9a8a7d0 -a789e15cf3c1e911fca7f6759a2c5d0a281c6ab744f29709b8d0623c1fc197ed9bf56b89fb0953baf261ffc4bd8d1552 -b738474bd1788f326c5145ca2a468d914ead6dbc338680f62ee21b1e5fed49fa501236d70dce5363a72147b0a8974c8c -a34019db5e8d5cb680a78c1692978ce0f3f8b21c1615ff65f3d103ed5a1e32884680c90d1dc18f0edcd8a506b1003806 -b1b1f26ed57a7bf77257e2ab1bf314b22e47f8a4f4c5cd154beaafdc34b257e9b976b26c8d9f1508498b6e8c9e9fd2ff -a5f645d7a75741f536e5218d4a38ac75f5f2d759e62bde2c9b628a4cac299b477a833bca98010b6c2a8f30b85f407250 -b3947ca7df831d68107713bbd52fa300411bc14362c37c2617780f5d621e211b8bcf5fb7099d903748420818d840234a -ad16157ac24899485e7eae71eabf9e4262d01b8f8bde30d7c79fd00ffb4c347d765bf2b4a30c260c9fe2e5153a3e1c69 -b1bcde4588570576872430e704a64d7130f921667c13101c3fb771efc1e0bd72c4ad4b8e35cbb98d709062257f0ef59f -ab45dce0e29201e79cb1da61cc4353840eb8b47db99319ff7802d2e18f00e3fa8d5e70aa6a797684b4a6741277ae033e -b6977424f2f5b968a4eaa9dc1ac1018ca51e6158a6a4c189f0adc94ea1c2f30bb33c57960a5c972a1800cca2650e2f6e -899f48fedeee4badd5b69632f78a244756458529f27c75d05e9c54cb29579abcbe4ff7567445ccef96274c8cf5b7d31e -a8225095071acb2610d28d9ce2645280a84c702f5f5040df7a4134de1144fe1a1b07d3e28d4ff5e2517b4b2bbae674f9 -b48316873f8245854568a37ad9c5fe9d5e6d9ebd60c9cbbf9e6f63c512bd8568e3a736039422d21d383378c77d8f10b7 -8b40afa65e47ba365e723b9e24bd4a13335455e059346187356ff9abe99cf71eae383ee33bc184a9ec17b32d0800f158 -96c3b7ad1e31b8d4ac0e14358655e21e687beac6f6b7b48dd3750641315ac7088352976e9804b9c625a712f9d4fcfc4e -914dcb36d621753286340077d16b36bdaa1414eac7a8e7ee84404a37f8fadda837bf4c5a932e8b0f3e8e673832e9b3f6 -b20a438985a4bdaea41b98e831537027f4bf19ea9c1ac5fd37546eef117cd3d41b9c1b125d2302ae3d41176ab5d9e9dd -94a4cf3cc42d7055b55cf58959a7715232a273e66ec6f83fbcdb79d01769f7e6b1e328f6b0a910d1f8cf7a5ba4934779 -a62b07dc466c2f83dcac7fa98215ce5bece548164e32b4bb3aac055b3c0aa68ef5cad58bf7d392e3b1d54ea6f0d9f0d7 -9870784890da6cb0223daa367163cdd41ead23c300d246d62debe980fc3e7de0b42576309ae35da914474b8ed2c5acdf -b0f28a74169391fbb179ffe8647f3e6228e75b409c49ba81d34ce780b12d408d2db5968e9664b9de6a7416d2f6d1c1cc -857697b0222cce1458ff591e1add39f5632cb3aa2e589a64166738d8c00855e354c2ed44c4cee8dd707188790fffe6b1 -b3566bb224742d0871ec5d15ee890755d7e6727aa7e2f374abe965ef8380b49422897545e2cf8fd3f58bc81f05abf173 -88271995f9c647da82820b042e59011121ac723b4d0a2e461cfc1351d89cc10eb7d18830adf1c7b9fca55ed3e910aedf -863a43548db29c9cf35f24c1d5f7aa984ba21bb924dd9e09210a1feadb1e0ddca98df47e970c230879faa5e7434b118b -af5c71b27157a2391247622a5029ba11d17ab4329001b01b3236f38d67ddd6b8902aebb48ee9c963983c16f6d8c53d26 -97abbcd4fff0d1ee2ea777788cc146c1b32601fd93a5ff9908fdc2de225b954d8fc0c9874c258dcb90ecc7fd169823c3 -94129bc418ff5d00ba3a3389b62986fcda5714ad25d25091db12a66e138a35a9e38999c4cf38fe7cdb1340c099c467ab -8a785f303473e763578a5bff75a069764e346224fa2dd8ee3105ca779cccd5939ed8c21f7369bab9947a4ca92d3b605e -b37d1644a00401b213f29191a238f4c9c32ba550db2ab3b4c9d1f02021a8f6972ab0fc76d0bc5b9c6291d5edb9632658 -8e42a2c87d7feadf1a2dad9dc822b40029eeb8afb785ce574a340929c4c6ddfe4d750bd3a482e62bfef1bdfdc36f5bd9 -8837b0408f48c8b975ae777b0516c569dad0daf607da51f187bc2c67d3f67315340848fabf7ca78dfa46b05e3fe33005 -96d53e8e9b14e602dec666fcbff8ac2a7ca0474605b294365bab5f5228d8cf0a17a772cf2f37f7de3607f7ea6127d0e0 -b286888ab9afd161a714fcb1954f6046754c1e3e398cf639bc215327057ae68ed69113481da88627839b551cb9660be3 -ae5747c882d3ad685e481b0b42907f0934a717ef5b0bcf110fe3125d40628959b879186464f95bc4a69d90754034c141 -b1ca38e7b1f87e4c878d4b878afbca750fdc2509f625a06871da830c1f68a6cb20dde7d51ec73a78454ffdf54451ed47 -82225700e9b32f416618b074479302629114761fc721ff492d792d4d1a4d6fec887185aa81395703fc8d07a67fa4d87d -a132ead3cac6087bc7bf5153f29ea858a115249d779419e5c52f4d1f2180f4631caf45ab7cf90129af68bf67665b8dd6 -afd4778ab2921b6c9c3d3e2d8ab7e33882f7fde3c8f66d6704f0859f3bec468178eb25a103b78ab092de5b694f2d2ff6 -aa0123ab3e8af146e974c9fc72dce94554cbab212336c8aebe618ea082c15ef02c6b47b6c575d262d1cc6b0cf2d11f47 -a5e35113393e82c0ff3a39afc99a60f90993d5e4995e5d21a9a395ae31074ed5e2244214d4dd877c3d89e52fac6c4252 -b2f476cd5d9df15e624713f22716ff01790f2fe16957b526677bdd3d203fa8af98ae58daaffca10f84a7c61e29ba1d79 -82d6d062828337677ae19ce13d27ef45ee55270a27e674946c7c1c762bf43af6391d77454dda4dc613b519f4cde43636 -8e86b1803d4ee07791269ec9175dc3d3b595197c089551e5bec3edc55c77532235e64848aba62e43936d3e9438635f5a -845b7233e40eab725c241853013d1884d782457ec188ff7ea535926c36da0893882fea2c9609f96b6d85392471b71d2c -a2090ef73e125c0809f2bddcdd7b74b4f4eae452d76afebdf47691d2afacd1db7c6a3032e9a4c4ca744bb496258b8ead -98e759616bf468bb4feedbebaa8df381d01cb4b0009a5ca5fc980426e160698abd6fcd2095cf964eca6f8d92fe1bfc42 -8a29df48ccec0ecb8b3d904078897d996ecea1d2db6b40b79fe51bc5dad04358d7f7edb6543d7d1cf0c1f54544c3d85e -9422e88414d88e5d84b17f9d2f1c50fb48e9c5b8de215dcd7c52bb26a6ea71cf92c90f3004c4fcb34040eacf5b60b06b -a643123915445bf0e528d36dd7f2da9a3b993f93a7fc9f6148049fe14eb5a0063575d971ec955aeffbdce069d0bc2937 -81741f92a157bfe12aaabf0d81121e5a8c7df2dae86f5fdba826167c4558103363c653a928babf4ad7e3e80634d26375 -904fe8e258be2500bc5566c3890a9372c9404935ba19396e8cd30289cf02bda13ff3d776bef56dd87ce57aba0a8539bf -811997c1d70feed33ae3684eee512a46ea91400b39638d405a8bd6f1d0169706f48d1c04beb1c5afc5b10879390a1a0f -a4fff30378dcf1f04eb97951b85abc0f5257b9e53b7bee814a5acf060919d73504db14d55edaf54e4030b4c1d7278c57 -ac84f2568084ee7a715b2387e3fa3b15e6940a27ea99b4fc9889c828179c55f29992b68d719323c2ede8ded3a4e16553 -8fa542c15bd29bcf72a34b3c56eac1e7d4e4f3b15b82672cd956d23a9b9863233816ffbcc6738a225c86d9dd13d1c3d8 -90d94517e7f1236e49ed6903db72c0de3098b42fbc76afae7abc1b09a903cf92cb1bb6a6ec8c29331e05b8946c2e9e2b -916c0d6b1fb7c74c0001599211ca37812f30c309cb6cae529c876221c5e7187876d37268776451df2aa44f91a3a17a11 -b9ae0c4f0c00e8b07b489e015711346caedfc7cbbcb36acf3a2ffadf2a8f11118f93cb70181c27443d42634b2f2f6d90 -97a51eb35da8b67e82d55fed968ac9aa42cf2d1348ac146d534344c4c7535c29ce25dacf9901abcd7e8c43a83e34e25f -b2f035822c552cfe3325da99f28aa31b847477a644402d43379947ee219fed751497cfffd3536c91f2474a94bf758203 -aa2fc0777c208a2efb2884dff33c459f2f6c9dd4cba360a65918c8604cb02fd493c8e5d26069953bba56039f8bb694ea -84c63bbbea15e06775bd39f39995afc613586fcbaf32c9ada1410dfdeff09b8e7f3dd0c99b23c678ee72e44543ee6443 -8259332662ff222d4d2f817bb94033d458e650e5f6e2c31ca84c6f3a4b3d2e8d1f40593083337a17193cddd960ea86c7 -899fc292aafc17d01c06cac50a78edf1f11c8c3253f4b32116625537351a1e82ee3cac67725973e3563fdd73781985b1 -92d3b9aab29854556666588d94c3b49d159c9ba9046487583469ace7a6b8ffa61164839dee24d28dc2fd36b9387b6225 -b54f62077e1e42e18586a03b3d3fbe3fd680dda6988bee8aadc95dcde46c215167b261433d6cfaad8e2b3b6207662af8 -a6c021aa10019319f944f8a77455ad5b153a502dc9eabd9d306be3830a4fa2539e3cb380355953c3581f12348b919214 -8cdbc2c995699cc83768dd23383fe492a1bebcdfa55fc4b9d1113e510a6f4432ae55fd57db732eb56265dba6ad452c46 -aa474f1710bf6556538fe389694b4fb737713dbbc9c93d8a879dd3aee8e004c2441dd14b5f4cdd4a98e804d031ce00ca -95448d62b1503e71d47ef4f5a01c60c938fc3cfd9280d7b6d3490ef331131130630425adcc53c9c96f262a80c3251e4e -a4535757aedbf6d7b9bbea99f4bb7bdfd1c99d5d976bd8d4f8c69ee09c9902ea81884d8b6f4fc084e12702fcbb9e4b3d -87796bbc38d5c2d9a56a65ca91a40530b57fc2a768e9e08a2081734bde163f39e069edc99e87a84b539606164993f30b -8cb7647e60f023066c4835c956186b9e997a7425cc38465e95be568ab448b7303977c7ddaca73b78f6bc137f25e5e020 -90584dbd8f672a349682effe2f775f2bccb1911b06d20cd02f3a6e30311c6678e5082ab87ee47af72e0c064a43592bea -8886147e87a552c74767faa64516438d6473ae275e72b4cdc174825696a4d7878297b1ecd0fe1a62fa4559ed232e9e26 -b739745959c324a62943a225140daa51faa8e41c8e20ebd68d6f000351101a89341641933dcb2ac5b3a45ebbbf7fb26c -814f858b4c709694472eae1c82cfb7370191ad6d0cc5aad69084fb8e9d81e90ac2fae52b4051af25f1b806c273f61e0c -a00426131acb84ee08684f2fc2a3ef01290e48e6b5f96bcb0459adb62f4190a4b2616eff2a2712991c48adc551ddaf64 -b37a1e92b72e3ba42b79dd997bbeb031a392e42606254965597ea4b8a2ca51f8c324619fc2b9f886e17b632ea3bee629 -90817db93eed264f49445d1d3a14ddc0d5ca93191b6baae278b4c48231a56b25725ba6f7ac0e9c7326755f0082b79587 -95b7f470ef1630dee768698a31398e8cb407df3b651a15493c38f6be6c7eb387148124a2cb1fe1237117617017c12203 -ac49be639391aa5dc08e8678cc690ff617e9a0ab40166285f90c2d889c87ac70c455a972e61cfc339db59be4394a0ad1 -a6f5a698508f8047edc45bd605ad4e88245de20013e7a4e51994e99fc60d81dc945504b24f23f7241f28059f4b5d6756 -a4d30a6db06153074871c6adb0ef4e562c1491c1f9841c110359dc41a3bc0bfcba3b49fa53c29b8258a814b8ba1ba328 -b25a500efa7d38f797395cbec660250f4a00d104459cdf7a15b541db3917e26bb7568526444d469d363040fd094680ab -8444d11f8a0c686e2b22642ba1b28cc556ab7311686028e3fb4040fcce22959b7b6cf244b77c711ba86e350e17411823 -8ce90bfdfa93cbe58421be78e30e471b2c6e6beb1f9b3f85031cbe269305e18d25a2170819f2699346bdd735b6f5d664 -b73970a3dc993e28b71bc236b3391acbd85a8cc622b79e669109f9d3ad7ce7a01a8686e75d85408c54bb70ff9771ca80 -a64cebe05fd027069a18f152a18be155ed65b6b563696e395e045c8b2f0455fa75c2ff41c1247e596451b36ddf258460 -afec84a7a480b09cecdeafd025ee3ee02e3b3338b02d26cb3b7575ecb895057650f0955978d1d732ca2e6b391ed97728 -8caaf53038bfad6e0651e61e9a44a39027d456ff3ea46ee9d8e190698d5a66938d5c5723dd7bc75f0ddab660e178383f -a91607e39108d2540b4b5c9d33d96328f56ce9574ac9d1d4a81ab5c938443c3d7014e19f77cd55ef7be0a408e44efa43 -a3f4c6629a3c0f34ea060a8b976096e6fd3a91c24d2b056e9b6b60088bb0c706e25dfb31079f42e0ec031aa840f46afa -96b9c7d3f47ec35ab0270cc57841e9f3b3f5bce3d26faf6abf6cf657b6e949ce0bd1ccdcf9d490beebce722aea48caef -abd2433b4003b7d861b35e99b51e2eedaea4831776e7c289beae2b561ad69a771233e3d6bc4a7f869d0744c5be61b5a9 -a989e5080d39d4031aea86c03b77abe069ea9b7fbc515c6a79c825eedd6a9bf6a0ced1891eed20edc605f9e25a691f74 -93ca5b311d28e4dfbf4de84a1e1530a9153599e0853c9abd3671a1ce04995e00f7d3092895461137fd78c72d24a99494 -8acebb0309595f4eeb990b7a1543f0633690b7469ce89884d5654a7bd2d2543f09232693a04e1e1b445e6e0041c8b242 -abe3858cea5a873a7576d641571965736d55d46f9040fec219803740dc2a5b43c72689e94c9b61d3c3c44dd3a821b694 -947cd395aef4faeca9b78b6cfcc8b2f8f361de884b29181266fd95b21ca6176e7944058e20cc77c7757fbca4fe445394 -8c2e50234c75d645f3c887693e2439ef42433eff328111b9c37aa3ad5a3b21678ee44ee2959a91610006b27a0f5363b2 -967253e02e34069ac676063aae9a493bc6d52b8bcbf1da6243bfeaa9fe05f8c840ada0a282df9c0180d05eb866402441 -a16a4c9a11686a5294d8329983c8a4aa0e6e5ad0003ab319b493842e8d072aaef45c3335d9a64bfde6bba120a48a72a3 -85187b866fbc72e5b42b91d76e7ec2647b93bedecb060b7475236d7d152d17f901c778b704f7c2c1d3d269341890c233 -83b192d925e3f4a1fafcf22cb48083b2f88632ba93c1d498539bbc4997f61f74a0a3b8d4947253a0daaca8999c407b87 -8338eb3e7f549988435f4f618f4ae1942c6756bdc28a80dba7ccc530bef161c0bbd20f77c8c4d63c94e60bc12f7cd387 -adc869c5acec5e58459eb804c2141e03e3582ce1fef7d40fc1dffa3ca0f923919e291a2ca4a60129e2a470cdb395be31 -9279068c28840f2c34e48e9a7e7e9406907ac14bdf4eec7b8c28ebcfe16a18fcb047015e4309f19e6fd73d6e6c454157 -98c4fb637a868f161f2f4222f93f3bdf13a61ec1f4e4c20435c150fca1bc0c01c790da91afb6227ed2a6aa540d70366c -9209fc7b307f40294bd9cce166277a7ade9c64277c600b3ff09579fbfffa471a887061e9cb5fac97c423eada30a8a52c -b1d63569d5d47d052f3a6e8b2c390bfac1e92098291a2adb209f20af875ebb2a8669533155b1d15b232690e26d399ab2 -a2c975c004e69e7b0f22636141d34adfb2dd1396c7355e95fcd0493e931eb7eb99b4df0f0f202945d7bf837809a29ed2 -818f48e65e337913c52e9256af134f4311be84dc332e3ac4cb5ef659b9c6e9cb34f04b0bcc0e2a3a574c9c3cc51d7368 -b92b63d0b363a368a348a4abb10661c38ced99a3132afa6cf002b81e6cac26f862c9d0a6886aede555d7bc453753cd37 -b4051275cef361cdebd254115275b0b86692d3802241cae5e2c75accee7df98d3165cd1de86226f382e736b12d9dbac3 -ad89d85749c23e045bcb95c3433eb8038139a51c8edaf06b5cb235549a2f9ad17589097ff8a350e934c8662a8879a3d4 -802010e6dbf4265cdb5b5362c0b197317f2435253237561a3a7bc6766f98b129ee06d370382998ae70080624fd65831e -8ed6a5b601a5ee11e983035f3109075444b063aff693b3601f87c0d76d2ac253459de48d0fee32330c3785d38eab5cc2 -a6c8bee787c4b87137f70c2c54ad3ad0955269c7ea57ddabb1a215e613e250944cada7f241430c0ef09f8eee29fadaa7 -a3fc6a643e1ce110b08344f8913ea7f8c9e44bdf1a02978df8dcd3671d9b357397df9857fb11ba220521d1ce40064ee5 -94089626bd9c81247f45e25e573bd6bf727a0e1a7dcd630dd5e661f65d4b6f35bdc16b64da648dfda404b5eab39d9152 -88362a160a95f01026a2e52aee3521e8496340f96a35351892034198740d8b6159175c60b910a4ee05af488dfa578c8b -b55a5b875f5594bf41949c212543517bb1ce34db3a896f93d0216813261aa95f73663c789ea0ceb2bf8815255bd328ca -8f9acdca0158df5ecea4d574e0ef0c256ab271d9d3d3bb4100761f5062f0a1a5d2b8a23685097a1a2b2a08287a2e2c94 -b6d4e3bd49a17fe7d929b41fb223eaf93141453f7dc233eaa74424290014a63ca6a099174b687048d59cefd41fc720db -ac0fa8aeca20a0b4189e96c57c85a2174338550855f9d0ff0c553e773a1a1c32fe3f8db7c8362bddf601e41380c9177a -82f05710f08f12b206b2ad6a2d06161c884b2511ad90b43fbfcdf54933c2360b7c85dfa4f598b5bdce8809a803d483a0 -a2ca711642fd498cfeb897e4072d13e43b5cdb2480449975188fdfbd4b471070cad941af03a2dd8938d3c376366fd199 -90c27a1df934339bd0821cacaac41fa70496900044aadfccf6e5fe28ceaebae5cbc500fd6f2f88c5552b7fafea79d06e -818651b7c7a6f691fc47a61ae4960bba7239007e14930f3a8cc9c95dcc0b03643047671f819e30d89c2d1891640fc13e -a88f01062ded714e7f2f1523644222cd8e8cb8e535eda88738f4b4b19079f4f7be664abedcdb618ad1de3e74689042df -8174282a183f3f393667352fdd60460d2199de16752c372a44465f8b71ca134c410d1d81f15afac839748447875f8643 -a358c3e53dd70e1a608f36a1fdbe225e28c13b5817dba890ed8e82adcb7ae86fa68ff6cbda7e02e8116c11587ae1ded1 -8aa0bc208a84d5a58b0206a8fe5ee3c8d224ccb86b11b7c9d924e16b2853a6c3623502dd60b94f8d720810e0079078b8 -8bca870eb6cc5f7b5f6b84f88b49d9a3994e61ca3f2ad963f28f925e58430887f5362ed4bdc2a2a38b5fb9e774a75cbb -ab86840fe84b1eab81675eeee17f85a500dfcc95dc4872e57b39919ccc71b702585ab9ac66146d264d2bc8fa39338a72 -87c46966a4bbf2523dde607852a40b26cf3431d0bde9b2c609997c0f29c5932d28014026862abb7d4107b28ab8e2ba70 -a91666a8c846a9944ee7ab243ab535e4124ca8bbb756777609aad848527b354060c484acc19c333459c09012670f03f7 -b7145784894c6df87d2ce6a06cbaa713e46097b5f83db60e5449e62ed5bf382a7fc3136e5599226a2fe7951847527c4c -951bdbaaa06ba8b427fc4ec6bb44e93e70692bcef6369fa06c7a6882227d27f09465f37f0a5868ce43ade188a5f37f8c -b69662dd5dcc9ce7bf24be8a0e85e80c8e5af9b030e740796f91de548569bafa2fbcb19d98e13900c76cae3fb601a8ca -9630a7eb15718a2324518f78f26a71e3c801a8e2eab3236be7623807321c128ccd79c74ab657ea8e115d6ff3078a6887 -a2f98c2084f8cd556cc1bab19398e98921ef56f6445f63444384efe5d7c895690c57d0d94cfd24e99f63f5e31859e34c -8c3994d3cb76fc6ac22ba2049ea4547db92ef78f009d24f08695b282c95e395f2c1477bd52d3f569d64551aa5e259b5b -b58571076faaaa547df9522b48c684b310500850339d79d2349dd8211bc2c8307d13cd5bb7571e0b5baaa013b502e410 -93e07feb14f691e66be756b37467f290da9a6677b8ff565964f010fc20ed9c58d8c712c4abaf012c787bbb22cd1473d9 -b4bc6159db1578111190b19aa678281eb2fcf7a82c7f699da7473720493e66e0ab54429da7af24315ed9f7399863c954 -93cfc98563f25b45c15a07780ae0a38c4ada52ffc1350233a3b45417c16cef92e7926354b761d0e0de55aea4c1314406 -820c37c923807790d77d2cec39f0eca63fa3ac6eaf0a1978522f0b1d293a5c46af3a0b4ca542cf39e796afc1fb3d7195 -b87fec722faec6a739355fd30a2757e5d184c07b5bbab8581b74eabc2da413faa6d11ccd65cc93f886c788239b1eefb7 -a183bac7f647a0c15b14089879a8aadb712f079bcf2078d3c65851137a00dd3ed7e47263c064feb19362f98180aa425b -996233b2010c20e0246295735b6d5b3e932f2aeaf0b35aa3dee66b6296f39e2e7ee95a7e1a15838ff3389ecc8052e315 -85c943e09a6c77e15d49ef4fe57d89744fcdb705ca370cdf70b3d84aeeccbf2155868f6790333f88fe36e08042ce195d -b88f82b35ae14a3e6fb972c47123236bb7db08b9f9f3828033fbf5a895b09b9b0de423f1caa04b3e8e754409b21f3a52 -a12c957409b6dd335964532ce3c045aabd280188b4d6ee809cef479e51dba030cbecc86b0ea8777cc8828c087006c5ec -87227fb4299efa535240793cf0079e952e971a18ee62cd71a62d6a5db921da669c5d8eb1bbda318ed5f3b03b38798a73 -84b5c7585fb1c98d031a0bf6fa8ad5484c7766025af552cdd72e7ae59247deb845f8678862c44ebe640a7333cef8391b -a94cdb0f42ae3afb4b1878f960669bd99008c7ddc24f2fed45ca521c60472e5587fa9bf97b315efee1f74619a4d9b762 -969a9bd21a6a90aa30fea44e397cc88118fd5abeb68839556194f9ab0076806aa320928a8ec94a47c4eade15498f5175 -b2fb215bbe7acc3baa04b0aa9be654afdc450faabe2702a0c9fa760c9e9389a58aa5e3a4c6af4f6f5c934640d90b59d0 -8be6a43071464e6c7dfb0e9a791a658214c1a95adc88f144d8349ecaa0e76b8ea5f88cfe95e82694bc170e49a43ec4cd -b75d56cfa1f3b61428d24784d51dd65b78b977bbb52cd71401ac7d3c2643f3dc097d6e7668104af402cf7e7e6ddfbaaf -811005c49d1be377ebd2fd3bea9771089a0f5675c55e9da5f31fe13cfc9d1ff8520f085918279ccbdb0363eda16f8056 -a487f7000c16429f2b7bd7e8bf4990bf26f666f8aeb11a99114d33e24f946cb0e3e025ec8c0b0721f9be101504c8a1ca -99b72e711ba7b97083976b2db7b97346000a78bff9b20ed910eaad02f6c03b45fb3f0f1217b328c3e2d87b481eaab52b -828429d387a0b83ac8e377b32db1c893a4555ca253b8e3159399cd053c5de726655a2ad39348c8e7ef11b37b0bca78e6 -835de10c73da7f0c07295a3306ffb18991334c86e5fa4c6df2d8091e8989f6454c8b43721b13696e1f665480a64284de -a4ea48f0cc5915993c83309df99247dcd7df4c15c723d168759175010fbe8d84adab8393707cb338fb90a6a77b69745e -9976bc842b06ffbc5afb309eef8964908802e9a5c733de4a8292d5d5773ecafb6daeecc63a8dc8847d76b77d4c3915ef -aae89156b013e4adb4bd8e7b6007937f0ece09af077fd407798e4155dc09a129d44fe8f8b5f6cf6b3c84746181d7f4a3 -81891cf2d70a8c326c6870a8158edb79babf302b4f9d51229bbafdf038cee39b97f01694eb719df99a62478bbf909a85 -97bdcb526108ef3cc2205aac074ef3001d528f56b4889573e0f4a3a2504232adf23880f7fa2f57bb787ff30b89599da9 -9778949a95fc663c742e70596faf91ccaf8b5b93b78bc2d4993480722ffe10bab3c8df3ae50535d258b6e749a0abb86e -88bffdb927dd88c1ba3eefe7da3fd6a42ae494bf282e094893e144330cf08e3f518f47aa1dd76d6f249cf83e6bb9d4a7 -b53effa345fe59917f4f1ae754e9f6b8fec9bd34cee85872b3fc47e52fee29c418b9406aa50c8d5a2e853d6f2056a49c -a616775e7e77e846066fcea413f0023dd491d8176dc450b0941368680571cdd236f0f83883d268842fa61dcbf3e4864a -8b5ae13dbbd07ad19bd2c7bdb48eb3c760244fe0caa73d28df3f0c31f5418f8b06862526f5a84bb16b2a92eb2c7ebc28 -a62294830750dbf43ea497155b185d611d75e767aafa8c2c30256f8a4875b6fdadaac429e8363848b39e964cab2aaabb -94b6973fb87c2efef5efc0e7dd7ecff5ffbe76320fed8a20d730f9e3751efe9e5db39981f45477ddfe037e18cb971930 -b931b6f789947b5298c258c8f0b221ca927c447f190f0d8afe2f18ce9b90979eb3247e77e128a1d6c57d3bf5523e787c -968259d9d001a08c0329bc19b2438b48dceb5942bc6ff9892d78fc36014f1b60a5ce7deecc7a808e41aeb4e26143aa41 -a52c1906f103e3fbee8c12fecd93f7b7d6f37eb733147bed841b32caabc880fd6e72884380a3cf93129d9800ee7877a7 -969dd12f0f6ef0b868e21539dcba5dc7327033eb546570f5bbf91b13f9c2ba6070da430538c40bc53a2ace4794514038 -a853a74380d78710c212bcfa92d3f9c433b8ccc6936356f3bdf923b8e420e1017bc530ce73bb8d04bf7a25b20594c753 -a84dfbbd3d9f409badc8ac2da5a0db98124df9d01bd71b1cf5b2b9c32866309304848a4bc1fcad1130bddfb9636c1b56 -a9599f55173e77dad54cfce6ddc77bc48588f36b79a98c156963a2f5397262ae07634a98ab9bfe1aa6357f78aaf89d89 -91e429b5ad0bafc09b5eefe600e179ef56f1ee045765ab3d5ecbd73eb201305a6de4382038b1350abc70bd1435151a0d -8785056b83a726622c565985e815847b63745fb66b138d24c985d6f42d5762c61ccd5172d4a3237222c881e5f036b98d -85869796ef180f500dae84f669b76a9b245e2ff4614a58d74820c22e439837b7d9866f480b72d88f44682be54c6dafb8 -a118baf9c17d85e22ac3315f5ba9aa4e230ca2a031906f99bc43fc750a0f96aaa5e6774d1cf16b492726a37db7b51327 -ac8e33f32c1cd14c6de14e75f83b8518bf1bf6f0a70e23ea0e5a29f096e2992f1259a121bbccc5252b9668c605240435 -97babe93e2016d29af74f776e167d82f1cf2242202bdcbaac4a1eba2b3fbd9e7ce57cdfbfe799a0f6a06a0e6838c4e99 -a70acd7e1f159adf7381d3f3ec2cc42b56232601f18ee62fb650e13a80954cd06d39a57217ebf4d8927e28c910671ae0 -b33ef5c10d0588df0b9d2d963912b294a2375a26bd25225f002cdc206a1cc058465c64180d348cccc899baf3d677033f -93086926eb1be21ab929b0098767611bdf1a853b6b67045c14f00714f806f8655be37150be1da05c5d2e6d9c66057bf9 -8890aad532a6c9b818ddb9f1ea12d627010b4120fd4969bd239a9654a05116272d4cf783ff8256de337bc01f9b4154d5 -b878977630f647a5ed7c99f59ca5eb653cd647277b899b918e5f667eb17b6dc433b56c2f3a2a18a785a4b5a9ae95f372 -975582fadbc276c9afc4d8ef767a66684df5f56e898d2a8749cbc2763982c013e5fd0ad0ca7ebc67758124a609b59663 -ac45e154a651857f0464db38afb2fb25853e8bb1eb476df31908b13b4fc86491d4f831c0a15ed6bed0c873b3dcff55e3 -a778d373e361753964a7fe4e1d28702c62a919e5203b941b04b0e74cdd3b4e838cd9b6dac3c39dd523f3227f1b5e6766 -b1bab7994941f8de4235e2e188b302bba847c1618ebdec7fb782241e9eca8d32dd506d254d865e0319c66396535cc484 -8c4ae5b346325f1d1609328e41d20108c4388bbe021361a86a1f9681caf1e6fd64896d72641ba8c984e153537317420a -8cd312c6a23e56657624d21f230a2c22d102badbfb2e38a8c067186abc5a459d0c78433ae7b54334591862c18864d7fd -8739d71181c5a657c6fcfee1df71756c3b6b8c48e8d97460fb64eb891abfd23433ccd08574a677fff600ffa5519a2363 -ad3c8d1e9eaa6f9122fb14d323318bb0338c5f9f29c719715cbeb15a2738493930542769b596098a5f505359c0314381 -a6d78b78227f8c1203e502caab1213092f320e77a6e9729e1659cf81e981cf905170e99b56c4eed1326320acc6aa60fe -8e5ba0e69e0f08a49ea4fa28ce0792f7ff6c032844ceef11be90b2215940d4b0f3e4acd5e4b189b189b0a0ef8045aa26 -b7b31957e7a85a640b851d4241c7b2f6af64f59ac221783b88c1b51cc4185f5ae6446a3c7137ee072c2eeb97c929d7ce -b066bb41c5818d6008349dc6015ab780633cd961b5d947062e14618c1ee1abfe42139c86b77e7f5be0c275fc3f5b8909 -a6597158957e1a0af153183151fbc4c73bbf8156c77f7b409d0f97470b5e127beee6d9246bde770127d3e3ad400cddd4 -82a6de6344e5bd0c5ca95f3be1ccd42fc974403269874603944c08ae1cd3ca887e66fc51ed61da8b7af3cce02f152e6a -89fd363aea11ddb2dc71288bb534a4a6e32feb5b9e4b88d132f4181f2579f8f8f39d19fcdb3d3d7ea118b9f4431520ba -b70c945986c8227d239201857e12cc7cebc932c3bda8913c82b62c872b18f866313738788e11bddd630bb5953492fec4 -b4e3a1e8f82d988c85cbb58d9cec69bc63fadb4c1c9a09f36b5a61f1ee96baac1a9458bfd0f3250e1734ab3fc6c0a0d6 -8d01d1eff496e8bdad1e6fb4b60e4bef0ada39a378c8b57cce2c115e611e0c4fa54f9b599e4c34dac925bc06e940eceb -90857123505746f7bff08e03b1a90f67051a71ba47b49e7bc63f1a8ec30e02a98aecf56465d3b4746aae166081099da8 -98b9d3b7fe1d5449bf6498c30036e3f60c8b90962fe04ede9ebf605d07497f617d99d51f0f0c0c14381377de765ecfd4 -891e7867e70582ade85730a21c19f6fc239760f76f8bbd8c6dafeddfaabd6fa4845f62d649b454fd3af8ae7028ee5f9c -945136f71f290d8cc6bf282b554cdf8ff92200feb7901987a1348f2d2edd3bd7b7bff6f57ec25fa302a27121a1a959af -b574d8379842467c5f3cdabc2da9a45e5a6083efd7298b077ccef2c4c3bab03abf1dc11507f4c896d745ffd41e4dd319 -946fea5c1b1d840c10a5a732c7dc23c2bc5eeeedba6956f85ad78fc1ee4a95b309c0d4a4919d1f7155814e3f36fe322e -98befb2f7d0a860de662f28968fb6200cee5a33cd7a6c376405a9cc6f0718b90fcc5cd5b9142e84e95223a3dfbd10f29 -8c5f208ca23aeae44a056bc21e04b570c13bfd49b14681cc085d5b318e62e4c088f0bea9dde52376967649919b59829b -b14478442f8e985618272d4c56d43a28e10112ea200b52fbb32b19a4d1eae965fd5ee1e9772416d52dc0e2db57d3ecd6 -aa308b19a57159ff702bceeb69a385f91339db7e683db991b1414bf3af9916d8e52dec4c492d7e8b5a5a011680defc1b -a8ac18a1adeeaadc192e15b7e92b611c936ba9cc9aee01f03c2a236827ba527039c719f16149d7aa5fb297cd63878766 -aa09af54f9a5fab6a61552421c13ca62f99fae212a9606f8a5a050997271ab6dbc763390bb98d90b1af3bbe9e8d9513f -96b8ce26b346a0d3fc99b6e463f0c619196cd85340b795fe1c1c0cd4f1b3a9f2bef5454e0bc7d51d75ce26f217460602 -a3efa46273c392704ba0718a44f306edfea03b1a6be0bc1e5c67c62c89671c650eb8ac9bacc35372ade6bed12321f1ff -b484881108a43a1dbc16a6e7369a04286f896aaa1dae847b4019fa287c18e9d82c8ba4ad22cea2837bc220524a9a7a17 -827b63d83e15ef61d54dfc365ed8a4f9e200d526884ec4b1d35032227245410ad7e1b1dd3c1d0ad48ddc4720f0fb5e1c -b513c3ddafb01b6189590b74d20348db74e400c106202dacd9ea9552ee2c642909a7a73ed7ab45a986eda3a0701be79d -831f4030463c84cc6cced28dfce0b3e6b6ead01afa200ddffd807f31ddd4ab93a8699ccc9d26970407628d521118ba6c -86312e006a800720329b82f6feb2934e2cc156958ba394278caa6766ee10800d2fb8907aa92346dcf6d389c4f66f5e1f -ab6841da372a286fde1dbbc57cfe967cb4bebd6fe2ab9e317cb9f9eda04a4db0d5844ffa8db72eb9cc6bf311667ff6e5 -b8238dca3f2be29bfc4aa65a9f59bd4e2c17fae78114a69bba1170782b993afacee3755e768317a923fd32d860f6a74f -923c1b60c052a3ed4736da7e84e52b0e9e154627cd90cae335dbdf05af109ceeaa016954d6e47fbfc40d9d5649c198d9 -96a69d18c838512d95d97735263a8cde752b2bc790b3827ce048e177a063dd11e2a69b86b3184873503a68170b2ec255 -aed7c3af469a93c22afb47a904bc70b7d88262ecdad48ea6a6c07eba7398410bf5a97a786beb11843cf40ddea9a37098 -a6b50f6369ae558dda3ceb8cc9d99382a1e62d0d9804b903086845479b9381fadf8d4595c2f342307c94d09e02e0ba2c -89fd703d457580a76544bbaecf65f93d3335d7a22e93d14afbaa61e5236d9c8d8b005e403e9f5e7a103b0386971a5e65 -8e909a3638208c8f885820af8bca6ae839128ce0d902a2b7b6f9713d21da8c943a7984d9aeee7fb104df4cbd1092967d -b41e2d7a1a0082eef43e886eab5e781bd961a83155d6a14d62756ab7144a208f4e4574d47d2ea094a7fb50d0ddd7a241 -acc6c63450d124014a1db846bf578c44e910436c83190fae428fc3125ff2065d4c6a1165aea799b46093a86126d4c483 -8dc63127435cf2f269a83024b562b3f4da18aee3399ed5255c295e6b80c357cd8f1887de94bcea29f84db3193570c417 -8c4cc72a98d42b9c5807322f596ac0b48b08b16ec956ea4a70c641a16a70895644e5b14aee85a4046673849249115abf -992afaccf05d79a3147d2985970c1793459130ddfb18a9d31f3036c260790109c9ee6a19a812f5d55779c2facf87785c -91394d3e84649cbfe018d9c709604f6aeed53e91cd57e2b29d0e84aca3c413f1e0135c6bcbc70784dc8985a30b9f3fb5 -a33fc126a8f9652c6905b1f522bee45848ce42d7f4c3a4cb3f6ce0e6e64c82de74e175c2ab6b5a867a8d42322d257ea8 -962d5fb816010a14140767c2486cd629f7793b304a96cb82ab85a867bd9a407bc8ed44131f87238c34a1e4ba41adb1f4 -b09048879ce26a34f56e1d4b2cbd6eb2a55d4ddcf3738c462329ba6726fc0a21b8c1bb55169cb8338b2debf20dc0927f -a9f9ddcb86b7427e268973bc7f3239212716df394394fa535b9fa5225b6191d234a44a126766eb470ade18c469a2d166 -87cba6afb115c0b3a515b08cc842e7cc2c705880c82184174837c0a06e1687ef668609c2ca080840fff80282caec7390 -ada109548c449990dd8f1bd42c9cbf194a62625d165416ca469c334222446fad7a743b1f584ec3f20526c3c44d870696 -a69a0c58fdfac715311dbd37c4464f0475120362234f5366ffc65227e8178e037ae91efa5a52cda5fe28243f47390175 -98e726cf884c6f706fa25fe25be154afaecc0c3bcfe682a85afed225bb44ea07cd1767b4d9f2201358ef19770330f0bb -988ad5bc57f0621e3ce1256720f1161e785371fd478c467c39e554e2de27df5ab8176508658aa90ed7179bc212ed0dac -ad0ff6dbfb397da51fa4d9d959ba5819adbf1a1ee31f68fbd62ae07a9cbce0641588cb1008dcd0056c17d74e83c7114b -94c703cd32b9f52c41b07aee3e3c19b8c2b4182da80487ed7991d568ea8827f0cdbd1e977d482dbc102c4de2058903c9 -906fc2a06cda5d82445e50bf475dc4ff2c17e64c982539c26545798f9e4dce0bd4daa8d55b027cc0a8e1b26c3e45cb08 -b09a51f22a9a24cde25f805cb18754e27d3d168e64db4ff13a202839a81c69dee8372b5872faa0d23fea283609cf4391 -93c908f514e97502d170310bc495d02948d99eca51e71f9a4779ebabae1431e1f7ba465af485546a9fc97c025877df50 -8337859db710ed7e276a47e90cb3912c829151cc2bd3dbbd4dd04acc90c9cb4870c44f4233b407db8240a93aaaf7302a -b13b16ea0943e235f8cb064d6dfaba9bd8dac67e9b6275a4c3f54a1770b9c905d8855517415ef6489843848108dc85ff -b28489f0de1a76839a898b8d2f302c95610f17e893a6e7f2e824fec773cde6f2b219038a3f1fa212bed98c97daa66d5d -af13afb48d56caffa32f941ac5542ec2b7fc0d6dbc3b16e51bd2a8b633f0a041ba1e098d9a68c470da00e630f08f24bc -81465afadc45ec24825cba7c9edbb36858bd2ca8f8b0b9d7240152b58a411b08503b530932e7b6ec3b0f8612869cb244 -b2e6b7438fb6f70b52b8726aa870f18191920bcb213a375817d100297b507908d79567d0c1780b3f25be807a8ddcb853 -aa7ed2b0b2bb2070b5f001578efb3d1085950c19f9d06584a2d31e1c235e6d6d1d7f081ca6fa2b0b0616b01b9a467005 -91a245f1aa8c8ffe03f7db1412e5466f0345196727eb8e6f98b80c01672e4260e90724a538d26b094e678a3d85f2dda6 -b9ecde963c8176d6a726b129f229d803d1a6259533e432eecd7404703c972ec7296ba35015acb1f4b5ab2653a3991902 -8cf535bff6e98f75d98c5d2a691a5d1aa645c7ea18d677d07d3a11a9cfa222a7b8edd048529d163120a5aca411161314 -ad2e51afe96dd0e942a7da5a37587ca1359fc17cf66ab70cf37ab70ea34f90054fa52503d6527e89e464f8058f5cde79 -97337d62f83ecbaa1f402c3964dabfaeb279b916ca08430a61fad6c31d60087c7e3a9decd541651a2b6e68fb2816bf45 -898b7581288bc7f97987138b7481d29e2cfd5255ebef133177d9060790a0973ba07de62cdf38568c336c237cb084b7c5 -ab53c0759663bd976de62f9f98fc82fa4f58c146b8a6a3053d4dad836c762063ad69a54d51b5499e9def86f8d4bd7ce5 -b35ba58109d44c14be159333b999c1e471fb61f5ed48f9d2a6bc689eb045864f3fe88a6ecae12315183703e2b1fc1ae3 -858a20e233f2860c24c5a3f4a820cac7544eb3ce91a2d8284f12013b13120121fea3c4f25427c3524a1e883aead429e6 -965be1a56adffa51f5d80761327cf69656e6c37577225b36a34afc2f8a959d8799ad0ecc3eff4470d49eb22ebf8f198b -8e575ee39077bd865d70fca2d93473f51dbc99ef4f715f4a3b1d9eb21deb2afcd0873b4dc53035b77e05f52029f069e0 -a5c670a73da241f5888c5cb44c27eff2b8ad3f491e0b128e5f1d498aa6d76640c9e625f3c5399ad8e99b666e4b2a9759 -920e1524255b03cbe500edb230696c55b7774963535c063121c9e9987ab74d504f2f1cfa14ba7ca82a6f66745fb0b392 -8a0bb7cb267b8e1e0cddee208734632b28313b3ad89f9c2168f341be5390bea3f09eaa51f8923b87697799a53201dc26 -859ab9b3cd602e78dbee8d8d5c3a9eb4270f130ea4a1b417ca5612be753d20106cb2724097840ca8919a9a96e73f96b9 -a76126d9a997fb0e7e2b27ac682dda1c6b99067313371387084be1f6e7a9a59bfac395e91f089e14cecafd151674a446 -8aeb466c58e2829790975fa08dd31f18a51a63777070d2e24605adb1a77b5e0e5c5e0bcb483076d23a6fddee5f402f8d -a8959f312f2ce0d7d974a4998bb709bb98ff6456413ef4ae9bcaa8d687b8b5ecad91414bce8f704aa44a83d8a0c86462 -b9545c8567827fb28d070624579702ab96af4f06fce515ad880893b97ad9a374c4c91d6288e2a584ef14b1ce4930a6bc -ace41f9c2756ced611da16e21704a367b122ee1c2feb83145103203ace1a5cce0ebd3bf295caaeff05281672c92574cf -93b90e75f56601191e3b568368bf1d24f97512cd42cac1da8b42f0019e07fa04cd5f835b7e9503fe4702632df27ddc19 -973c8feba289eb473448c32b141ab4a6f861222626b3f2fa265a431a54675dfe5eb479100a33c172ff935464d6e85f90 -a6b0798ce89512644490d65ce3d0441ad950f9a25f6fe2c9a766a58b9c8222fa6cba753f314cc7ad6b6e3da881c67abf -a79c560dfa179075e0d1506adf5082318915c15048328b15ddca5748ebc6ed8b10fc5d7a50bfaf8942cf9ddc6912be0b -8841b34df170519d07edffc4d33a0e70c518dcf53ea8d0a9f13563822312a65d16f99cf596bb95eb0daf85435d4bc0a9 -88527539258323edc2c296dc742cc26b9a4a984ca299a81705c702a425ebc7345a79b4df84b2d440a1e73a09fa18b5d4 -88026753926a068e1cbf49a9a0fa545846cc7ca9abc0778e44f5b7510c1b6b73e9a9b1aff754199379522b2a985c0881 -aa2c306ccf91f967b5cdcb50808771ede36acb9a6cd84fa15c6de4c873cc2d0a64e79778a2822a109b41f5205fccc30f -9751fd8bc2a07ffe0566e5587e652d3d8d5250517278bcf8754e14717b8941c07c194f14fa757f9a2f3461ca6376bdee -919746e5eaa18b734ef59c0de09ee8ec65e348efa659219d9eb6a3a77b8edd9449a6dab727e9860ca0d3837b161c0352 -a271c146794d6a65c6fb87797262c22b1d938ecb2624e03809233469296d33ac0de6909183c8efa438b5f3971c8c3eed -82fbadd9049248914a15755dff692bf689eb2650fdc6e44e8f3ae003b8f15a0f2858c7a2a8dd137b3448420c5f434229 -b90992cad6df98d2fd1c75bf90978205280d993d439c44d6721cb95d52eb042e01b418e45c3c48ed667aad577f3fd1c1 -a0c3d1e8b80ed4a979a22d6a9647bd57f22ac8d73c37ec3d56d06dc178a5c9d5ad3ffd6dba9eb7844c1f40b8c89d3d33 -b513aaf2f0a07fff3543d8687426d07773677ca4d23554ca517e50bcb891164d1f5651944a2f6e0a634475f6d33bf0dc -a0b179aa2ecf572ac4a3ed898aa34679be3cf3d8d9bc74e33609345cf1743e915124a59ffcff41bec012ed2a99447e6a -8e991c5549126d64e0b515a03d266e19097eee38d08121d942973d568f8ae23a15b037337cead0686f7c944b9fda3e39 -93cab29e1bb116a39ce1a82897776da1bcac06ea131a7dd141a688ecd4089c5a0b8616d6721b1c6d92309ae0820a367a -8d4e0159fd3534172b2481764cae7746b1a47e9b7b9465fcec0824ef234674fc567c16ca7116dc90ba9b2ac3eef28d60 -88cbd9ff6ca551a7efca30b5f59fedaca8f9efaacd4e9bdd17ef0dcfe4f3449b52c7d3066716f3e7fd478f264d10714e -873c71b2feef5230c31f13d8425f8b0eb0171eacb9225f484a36da3cc796d62594fa4771af9ce1e7ba951f5377e5db76 -939eb99d7fefc9fd5b3dabaaa5b331365121374a4ced862b8cbe0cb3c574fb1f0cf4932106088a1d87522acc31ba7f77 -b283f1d54bcc72e31ef572498821ded40485f38d2ffc67f70bac68a100612b020a538b36001d94228a4dc97da8fdaf17 -b2e4c2be605c8ab3038b4e91bca7e77e127c5c3106913ec1341102e138bc8aa1d218c3d3c2ec1d36fb8e044b4bc211a5 -82e73cb5b2cfd78c17131e871e92026643bb56916ae64f009a009555903df878fa3a2019b82f7e71a3ef7eb503c792d1 -a6d828a5b7de0e7818975b65244f6efeefc712c29f2f17b27f3264e19856d869c350ab39750ba63d6d46afa3aeb369fd -865b17027e9d5bdf2de0afa2f524f67b6defed87b14e0af5f4b6b1966c2de45550fd2b6b39b1be88ee9cb06e755f917d -ac8b47f9b7e675b556445d103271e6bd3b39b94d15ee1f3108fd1b777d439c75437c78ec3b281f7104af6d0efbf0ecbd -85c2f71ae18105fe499aa4da0a835de3e92ce05d0f28ccbcffdd2860898ae9909e1c05831ca4fed96545133bb3170302 -8bdb4a72b06562591ee44799bd7400ebe71f6737290420dd4ba2bffe0050d8ea4d586b7e329541a52611e945ff1b16b8 -aee4843c9ab02026ae723531112170bc7464f51460bd4ba5166fed54ecda0f53342cdf94f4354a5bc1b941e8ab085a80 -84de368006db07c89a7a43b7de54a63637ed72379a41d029430f6b4ebe404866896d2e84996998f7b2c20324143649f8 -a8375f69c01289cebbc97843f417d0146f68c6416981032bc1f42d3e09845d5131eb9b4d68fd0ba7f5b1223b83e51bab -b1ae126dda1a88fee9265ed8e5bccb810014044d83c70e01e7f80059a685067f4204cd15809b230caf5dd77738a64e38 -8177544c7b1f77181735c660102da20fbf9a2ca4efa79b21c92f1cd2b912630aa6c830b7513980656bd275097be59d1b -874fe8038905065ff3b77f1e53904854fa4fcbdc4c8959fd2df2e3967b3b84100c6f63fc44338c01fb26c042c454991a -b19324d737364cabef3d2ee4785e8f19cae399afc06fedff8fdc120e0ce525b3755161183a1f5ad11ee758104081a49b -8e7525bffe35c1f5c2db63ee911e7e0197951ebd25868660e6672a3e7d4fb309738268b36677921be3be2f323ca718cd -846c51c7d22e7d43f6e2addb7fb25113c25ddaa51252a898fc1d7d5b510f772534c4f5d37ed3074d124cb259e2bf8110 -aafe2a16cbc901730178841c39803ed84d3a78f92f42f84a1c01be4aa3b63ed7ad9d054ceaa8a2d56eadddecb287e8b2 -8781c9810ffe3d93fbee3b576a15b8786c3efd6b5a96b75819b1f93daf413d4fd0f56d1ec277e8f5adcb784b17f08371 -ad66011f0e2927ee1924725bcf8a296069f74df78ec66ef6aa8792f68425e48e9d7f717d022f68a079501770ce192fce -acd0ef46fafb06f336565d86e0b22f9e5500d2f73d047c827d6a207af40b706440afdaceb32e6571deaa1a79f5e6fe27 -8f65bb98baaae22e84a3ff375e7598b5c61ebec676fbb5a4f79c8463c427eaa96ebc51b1fb504840b7b0206ca6c2c72c -a4078341325d7debf766e43679b8b68331dc13651455a73912afe062525d2ea909d8829ac08771d9b32f2eea28b64022 -88eb29841b022f2ec9029ecd1a137173cfb79addde1c7cd4be425e5806ea6ee295b11a0459a940ba79f789689a8fdb81 -b762b9923a40a1965847bc7d046723c3b8f0d63323303aa3b25e93b4af8e527f1afb3dafda831f50baaf79926d1b1e78 -a21551dffcdb069cb8f30b625c8404dfe5efec83227e3a1a67ef0c9c9b49c658bbb31240c3ff6f8c68e02f67974c732c -b4735a6610c371754001425772aa5314b759c24da50b38a9390969c27e215ad9d463a76762323b7954756a8d5ee7936f -81bd78e545938f8a3e53ecc2e88dc26bfbc30941cbfd009572d9b38f8eee47a85209a318cafe8cbe055eccd5e62d50e4 -82ea5495db9dd48da97723bcfce02788549c6006773eb9f4aa4f0f3ae13414430edfecb5cd095259179ec2014b6ee1d9 -8493147b8f0818c2d5e75acda498139f95fa6f904b47f87a8c07e258c60f39bb1faa1d29cf0834c8a1ef1d6015d37b42 -a491233ab353f9daad86e60fd48b6f70dce60dbe36775958d8e270725cbbda96578b17a0c4925ba1298e630c6b9ca9a3 -a8c148b9e1373afa54778b6d4f76cb12f40eb6e07404a7f27b271fbce0d18d621675f1dfcb30e3908d7df1d962de2e5f -9826a45c29ee22cc26ae399be25cabd16180a291669fc822a44d14cfac81aa7ce85112d7f2c30effc7e83d131c9937cf -a793c75e716aed4048a2893f11eeba78ec565ac250bdae16594d056f06f4aa7d2a156e1617fc26def4e39984fb28936d -b6c454d822343cd1b1ef7161cd2ddc28145134d4e59e6d69634c010ad1bd44120aa8458eafc28f6103ece7e34b368e1f -a3340a0edc3fa82fe4f31ca2d19d295aa09c74cda3bfc3534c66eb71bbb7903843bafa92f7120de4505c7ec819a89664 -a18e5218cd4349985f412ffc7741b5db21bb14c6e00431daba194771300e740f75fd46aef1876543967e8719bc6517de -885ce63a88617bee05144bc67d08f1c7072d8c4e09b23b7359f020995aa8cc9654378d382de6340ddf0803717687eddf -8d8a0b614be7df01a12e534bac102b1881905a9d084146b3d0cf2086dc7d400129e0de8e48fc966adf9d8ec8c1336429 -8baad19f604bad656398a4010b20ffb6ec6131681d120220dbf2cc5779de1ee146d0b773bdbdf4e8e30aa0f464f2b18b -a39ae3d204491871c2e88d7772055b35af341ba66531ce3575f47c749eb8e380d63a7939d3408cd51356cca29c76d4b3 -813afd593876667ebf0fff2b8a8a5bfd0f42a4fe2e4a0b7c78b6183605706c97dfc40b627340e1d9527f618719d60e88 -a013e458d678fb302bcb6f002a52e3e0ace443009eecc9113ab5b78f4663acadb8ca9cd757a7cab1e850aa23f09ed698 -b6e14f351fc47b9e46a83984756812cfac795cac5ebbc6f00d673ee23209d0d91a6bd7d576c7d35ec3c7e7cafb758a46 -b94246a346966caf6fc1e0081a211f27b38f058dbb9dff915e3e65391dd36d66c51324667e3d7469a865c0cc064589ab -a1bf4bcc7420bd17acba90ee67af96e73502777e1723255a73b1ae3e92fc77e80a287ce7c3d4088040e0edd64577c8c7 -8b6f5eb9b6bc7320349b19876864baa6cd8e07da4f70653d7369740184ad416c40b4395c04750f5d8b54b3b3ba68295f -83250b957d920b1b738f4d0f44f9eefc01b5b0582128f5ddb5a282a11ee207ba1ea7867f00588f8b891bbde2e56b4c43 -8eab312cac9de78c9fece9d67a6b26d58c4e15d5e0668ca2cca2d9c51636eea5210a893f9321c2fb232e09f9d0b40fa6 -b4d1e5f284d50360dffd2a0d21c4b31d81f521158aa21bf333a525cc68e690ce8ce4f0eff8e71a0c2d5853e2fed18231 -b1f194c28bbe217a2c98ca8212fdca744f0806d60e51f9da81548155cfb97a39e2a98e753be8b2196c83f7db8caad2e9 -a7905cbb59722d9463c6317ae59adc10d5bcd6e9788f2a54f4ff4a4de03df3f830d6b8faebcda541d429a7e42d158c9b -8a3b31d0d0b33e7011dafe25ba5c3b7629cdb5dd5b31385d786fd80888fb8409812b96d28fedf6a401a93310b045c620 -86e4990bf50b27bac76926dbc65a1ca34a759d005e56eca56fd0e00ce82635dffed6f3052740cac2f1f37204699bba9d -8f0b6a0b66f1f5fa3d12af444963c6a45785a36dbd9e1a5f42830b5534ca8773a05fb618292e718cfe8a066b8fea7980 -b7f206827d715b33989de5c02f0886d3a457d0ae34931ddfdfe2dbab121b69ccb560a71fdafcc3ff204217611674f5d3 -a6e2ffb0c5f29043984c54f5fe6449ac4b7a86f2982c909606b88316ef1f0a54638d565f44d2fe8cf00279e0eee435a9 -8cdde76212e73f9430cac210b52507583e81aae0bea491f6cbe27e5e2c8fdda373ce8c7a5f16bcf8c6238b282d06639d -8030955eecc9b8e2161d40f1f514d58024d25e07c6710916824ed8982b8bcf7ebebc5643f0260e1ef6150b6901dc2dbc -8938fc90e836d7bdf1cfefb2716cc25aff34e7c4dcf66b349d1fc6681580de7f58665faac29494b30bfa0c743d6f33e3 -b182f9b4a5d838e9d534e41ecbf06330c56a8a64800eee561de1fc2dd9486565ae6099f40d0f1901066f45047641bd65 -81f98b85de7b6c581613f4a42e0cb0dd9e6336399b39d38a4751c2a9f195b65c9e5592fa1728b91d83cac0ebfec7d675 -94681572da95137ce41d913360cd567b570a87c9a439f2b67b90d623561b75bd3dd0486a90a63d49eaeb412cb97768da -8e64922606ce05375556901b8c042d4f41a18fafeca24c1d56998e0bc9054bcee7ab079c3729a67d908d0d7967a85edb -8e10e8952b24125321d0cd9ba922affc93908b3abdce47eed22fb2d44cd556842c31c36de6d4c28b4a1b5dd84e07df81 -b6d464020a51bbb53670c81d5f1474ef439e006851d5d5a3fcf74219614a2a9c983737f20b254d38a2fc7333b35fb3a6 -91801712ba264cc2eb65e8a3d5a032674a89f4c2dff95ef9d80d3a9285f3c2cc108e775dc326881484756814c2a03637 -986e5a00f13326735bfc6b41b086623101f01dd55f2a88bf995a3b81054da86bb2f97fcf647d58e90428e8e9555eb020 -b2875b4ebbab678fcafd270a0238a208b19803012fdb3c23f06c74bfd45929a9856b7a0f9881b75c7e97fa9d35e49d1a -b3d1acb9c844d8d2232834a81862c59548cfa849e8e5408ee66b4c8b86ddac0fc231b2538a752eb6c1ceee92ca443d1f -ad0b1b5d6bb50c43f5f3b692c5d3569d2117b01caa7f0ffff502d5ab727f7702a2d458b89d77d218d3f92351b4c2b92c -95b1b99dc260ae6ac7c387bedd43fba793274b15768d93df13c88ff6cf637732cb6b1719467919b444c3b5166f4f0107 -a0c3c8b59016056742145e7f4ca6568d4393124efac6540645152bf71173dea3d0058bb11b3093228ca4729cdd5b3033 -9278afba60643257d9f21a4033df3b57743c3b43d66d96ccf413154a63db054fbc3a36f2ef378169f4f19987964c0bce -b558754c97f9824a72644de1725127dd36e284fc07ce89006b990f09db77c48ad6728e5c1891a691460bd5416ad65faa -833a02af76172f868a25e850d35f4d164889bab8381fa9c8d9880ab0564a3769ce3961cde72bc94ed73a1723daa35cef -aca496f3e528a2e3eceee138291107ddddd68bb088b2e49ea76d0c4136c6924b3251d7661ff467a36dff29f07ed09102 -a9367961ae88a19038c446df3eadb280da005d120c16f48ffeabbe4cb8e5e2784902cfa1192876ab934bc90606baf2cf -b43feb49373dc36cb46e050e3cea43e636a64289efa3af790dd3fe960446492b858f51b3be62c6b75b510d8e2b985573 -8cf24955965468125fba2c5a5799672845ea6ce97cd307b09236ef1a3cfe55c88958ffa311e8bc8335bf261a84275d93 -88ceac98b512e5bb915554af92318a5d07a494e0b8734c4415e192e7405d6b06d170fbbe254e3bf387759f6d4961c34c -8a9044ddde945daf3e0cb3f897ca00d0d4e6a5f7c99aaa3929f0beb9a44d2ed23c191e37c57140ebf3ec759f50f84d57 -8b2a2c0fb51e7c5fa51e8c593bcf118696b8411bc93e35cfe5de6c5465c6e80bba64398d7c6b71badda616b918bcc7d0 -ad8bba2b7d5577f971a1a561b17a9d8f6b7c35fba55e3e421a0d8d77b520eccd52122f02afaf3899218b652980986a92 -a8d743b56896d44bec838e10ac1ba5a43f58c26655c71be0a5417d936260453a8e91752c87334676c5dd1dcdeef4fbd7 -b0b0540f8d2d1ebdcd74d6e4007324de8f8bdea0531880520d79773c0b8eda65ed49e672c5a294fca6b4560442085829 -96da830d1c1625d002008e9a364005b2ef16cf56f5aa4a758ee963388493cbf90aa75c25dd67d496af17212537ad44ab -89e819577a95195056b872f8f790d001fde3253a23120e2c41b3ced7fe8e9bae0df74907b7d65ddf9bbd6d2efa18eba3 -90a139ffc7dc0992c023651517db4c195aa2f618dc3002f4a0a43013b6c6022d8d9844a49cfbaca543c9cf5d9b2210f3 -a2061f543b216fc9c801d885ed681f9253f67cac40528b23aa8a709f24e0992fa42a10f1bddc7f10af2c22209343ca26 -b5f53715b9146966f386f214477743e2fd2b771bcf90b192a5863c06d7225be34edb6bf71389085edf344e60afd88561 -9634ce27272f3c687035789fa4eaea2aaa71db5b5531b21b8e029645827b40561a5901b33afd80a3aeb5777aa89850f8 -9674736cdb4a823bf982d54876794e99c7672eaea7455be90e815abd03ac06ce1fd9e73bb987a515863c6cb4ae597835 -90379303e285b19fd7816a6d02c0b8f94e6291b56c196d76aa389cbf813dee7ebf64e45555ebe8a281daeecfd7aa5b00 -8a1f759f6cd6e5134f67b96e0edce7170e4be1b39afaa7af1c2de989116a6ec9d38a2c077c8e6e65ce0bdf729f20f1c7 -b416f9937a51a298548e91cbe8fff71585335c00e69602423adc9cd72d18821987b8fb5ede32fd8bd2166e2ba9aaa792 -a423073148046c81f840a481d57909f7ef621a51827e44706da9e1f0e27fccb8f88652097a9880ca64c41f6386aa9069 -a173305a5aa2a17349eca704fee25593f5c2fdc5cd8cb932a1bbc0ef34bf54ec2f867ca93d8e6aa33679cbb71fe11083 -87c6756d14d815ac8237ed4a75fb11206f615585ed527ad582841526371366ab19f602c7448a21722adbf2d987d89b81 -8a1a6f06d6375d2bfbdc7531e9177a45330458da2581f65ad129367c400cd77f548aa748bb470bc560c0b02ee5b802ab -a24a05c30d0fcc8334f6974c30d13a5593bd3b388e2146ba006f232bcd6886edffaf7e48ed6126efd3e651997dcceb12 -b35c5f8a5842d97cbe19105305cae1f971da5662c52eb979975efa0753bb60a050206fc0babac5b5083799e9ce8a68e0 -939ca5532c922d00d08ec5914e6c58f8a1302a1214a1cbd5c844b334ddc84e694768edaf1a2af02289ad74970800198a -911d6104a240f84e0f6502597405b47a7faf5e68717f6d389baca62bf82fbb7207ce8d0c584fd9d57d3afe1f957b7cc6 -88777ba7a4bdaecee78d42687cb4fd6dcf04402b43524e2ae67506d93acfdc29d9dae640c05d01c90caee1d04cf3d35a -9226e684606f8169e38dc21a14911d0306b1c9ce5244500e4b108eb1a0c0783486acaafd2e0b3b60c413bb003448ff21 -b2f527adbb9feef9553bf508f192b5ca211d0e491925a2331bb294fcde7d8e0fd72b441e9f07c838640dd35fba03e1a7 -b474e6d6ce22ea272a93a3c078197f40c01b9121c6f3083a8e587c367200b8c97ad94e156883475603f0a66d0340fa52 -95c4d9896df11d2b5a8205a19d6331ea02a2de038aded8e6fea6d79bf5a6648d5d986bd29430e4cb5a6afde8b07a9a48 -a12bc53ba6b6f8350b400fde04518a741a1d755123a6ad1d435c7642492c7df28f7091f17b254e793561923de781eae8 -8a0578ac03070bc920a3b5a7a33d976b3133501309af5339b0cc70536965465b4f7288af70db3d5be16bc2a1e5c26a86 -a66e27284ce6114e48ab56d7f623dc37a6e79cc5f487cb2bdf0acee099cae744cf3a9de53b111492b5ef99b0deaae0a7 -832a338951022c80444ad8c6d0285e86db54254d2689defecac2ed87f5eb4d876373af6d76e3d613523e32c3966142f2 -81e83f01bac3ac3fb67e780b28de30b32247a774aaaae118db3d45c8e74d1d4f1defbf9c2a7ffdf176f5c1cf4ae4167e -a1b214ba7265f692b4637352c6139bae8bcaf3e7db5806fad0014ded93048fa4a36ac9c9e0b7cca0a86cd45bbbba2fe1 -a7ab6f470a421e72fb703a9d153362056ce80c40264a3ee5698168130cab8e827df5ce3e6321ce9a669c87a2e5c67499 -aefafd219f2d062a378474c48d2650b51901b6bce00e4ba0b509395a6fb39699037577da353cbde187e65de87ad01575 -93db16a0a77d1b181f33ef10300112fd8db5b2eea26732bffa3b1fbebb792c6ecdf2899cf6f26b505dfb46deb81b217d -a63b6d9d1cc2f31ac5f836133ae66bc9de3e07ced5026f5bc90116599461dbdc03cd7680c1bb43dade9218ebfe1bc1fc -984b49ca86d38a486f6315f4f9e6ad521901a06f8862ce1fc095d9c66bb2164e334718c71d7472ed765367db5fede105 -ab49ae93955a38f45f756afc4248a37773ba8d0a19779253fca3b744854715b9c9b10c09a37d3426614ffd3a8ced7bcb -b22166dd64c83fe16feecc09d4b1df2d967ce7f4ab526ae39799dd5a5a4a9ebb1d4a432c5efb90e0875a4eb6b079e2fd -aabad619d887b69b9562066fba2179c69c684b8cc9318c9e39646f4a5381535c024ab277a0f0be46abc95283b337212a -99f5d484db149e9f8dc9c6758647c4e3702d88986600a3226874d612bb4b5e92a76b1dfbdb0909b8f21afc773ec67c7b -adc8bb04eb8c56dc4ce97c3fc1670da10db134cff2edc214ee3221079251b968e2dbc087c56c01c9260b49506958a6ac -ad625ddf5cd211102543e0943a7770a9b45cf3550d12dbb484cb5522b70cb626f9ac795b07a305be3e6949d7ad475f66 -8f9f5b2b43624e89e8535dc73fc54b744f247572b2920679bdf6a3ef346e654ec40fe8f81a0f7c7ce7cd5b48f3975359 -b70b1642f28bad56bb24b342eeddf5c3782e0cf6e0d5007c252413bb44b32586da1e3b4d8b45a72c91e44e07334da68b -81b0311e557c47ec22c5f5d1f757c6193cfffae357dd2460019247178b13733484dc8630fe2e13037a1a3d681c69066d -951c9f1504b19acdac1c04aaf535d3cd3e39c431b2b5d9def9b374468e93d378ecc3f5aa02c91ddb93eea431b327ca4b -a85e1f4c292723d18a49cc9323dc7af12bb5a8d0c95d71881ae235ce123c50018907f46bfc846dda1a01b14ec45dce14 -8a46c8b86bf9890df60de4c210cd7865892d0c11fdf2747620289d73bad597e6b482c208dc310c25955dae8392d8f278 -ab65408622c63b67842a80c4ed665258ab617ccd07871fa3f0fde2e5ddfeec49f01d7501790a60b3a05d7579b087b787 -8706913d42b557d9ea4d7b70697069281504b3c4e1172a2291e3b3e0a0305c8d0bff6b7721356d971d2fe58e32d4556f -8d9b8f3c113ca1215dcd15d4c37913d023c8c5d04f617319af76bb7bab72fb756c5bd992db6b9e765cd7695c316360f3 -942d4d3351b2a9bfaab2500b27d24fc2d7237e791993a7d0335f36fe6456c5a1a8bd28dde9228fb139e95288d6de5bbb -ab014e9cc7d3ca08f1d3d24473ddbd693331f4bf21ebdee0fc997aa2faadb43db6a1195644c459b52a969f3d98a85b8b -8b679da80561955990c91da9093837953f4ff7fdc658b51639c462b578a2b31443421712c6b7742fddbe0ced48c21cb9 -a9132ac18b1bce93e815f6d2f8a0d2f433ae4d6fa04269eb0f5f25864a8009b01531c7c3ebe87f07454927a010ab6dbc -8ab02c113149efc877967c92621a8ef618bf423017e78b9cd30cbb13c51200c6ce27c46be75e19ba843d64a3050d4467 -a881043298341efc28c60d850d90d90279fa6d8428953337ba57b74eefd858e362c6118a82ebb025c9c102c91b4aeafc -92e4a587479c64b8df955c6bf1abf1d7979a978e45d96f05bc1b9648f10428d77890be9ee03bc1b1982f5ae7b926f0a3 -90c21a22826e2e9978dd7522f51353fb33224cb65603779de41db3ba41e01d664e131233bf873e28d6c71294b565c533 -88e8ccbdc54ff06380c2243203d3f8c8a75fcfe638d6e6a010c0b3a39d5cda31f8d2cc416ee5264267aad2b457c94e50 -a256198394b458f6468dc91c35f579da0ef02a55fd93e98b25e43b1bcb650ff889df4899236765c1a6b35cf49da940bb -b5c7d9c03c36cbca068abc6778053727e77d9b58c5dc33b11629f1ade1c228b1c964f5a7d8dea16057e76662c4d79f18 -9588e133517f0d49622222b4de5c124b1aa4260971e43e4aa767fba8055540f2848954886b7f245583ea527fe2fd1de7 -b66025d75169bfc7ea366cd32419e24fbff829709e3e9587d7d59620b3a7b72034d3303106f965f5f7a71d66b7f314f8 -891357bbe44e60627b975c10c872a34b78d6b264380e351f3a86dbf99abf8e2dd8d20c52dd6073086e48e1ca782e2ac1 -8a066a3482526a92476bb8c3e5caf07575c725d72203d67ce98f654f5ee8b7f979187416fe3d7ae0128800b253d7209d -80a9e3d8900046b71fcd5b7034d1e0f57d95d2756da8307a11aec0553e5715518a125a653d356f399409545256a1984c -924a13fb2da7a899cebf2ac09c8c0a183491777100de1aa056a6c2bceffd5a63e255f16a9066e4ed89ef28096a1230bd -866cfc8116d2e0216d8049d5ae2ef0e3fffd377028850716a4bc2cfe16c5a6be023334bd6ddafa0c77913dd4ff0a34ff -95eb74bebbbc59d793e3fbae8e98c258451bf9bc5097df4edd832e9f1c30a1446a59e1f75a44832d0658d5ecc13dfc86 -972517b2d72ab53193db5d682db2de7790a418ce4952c29d64e1f9107d51a782f4084591b7c775648f103445b797e8e5 -a14ad2cb69da568f2f958ef4253d7a6daf574c6976f4f5d771ae7673853ca22eca81e20400092bac84453b6eedf5aea2 -ad95bfcec6c06cdc11d316b7ad33fe65555e985bb33b15c9f481a09caba1e5990601ed6a88038c0ae2e04b1607e2da48 -b7e3bf3a585af1029d83f12cf75acda894fc4441cd7b3d56efb6991ea91b07512bcd7d6d68738557a48f0446b2cb21af -a57efb1e2d2e10e41f356768385375a21d9f78bdb34d618117581bf7a15024eba43570c3956ddb85a025d39476f831d2 -a66d3622b1cdd472a2a4491881de035c2eb4f1c94927902a3bb9f10739f900130907c6b002982e03785c43ac30b8109d -a79f2417d32fd772e46f3bca61ac788af8fab174e1e1e48a84ac557f7e80a9cb4e2d7b467365ad18f9777f4cb5bb2b8f -b952b976e3b6660326c0ed357ff25ee1291b74891f3eb7bcea39dec2ebb11e287d6e26ae0506425a20e5e445273cc63b -8c23929e9740ab51d9b82c6b7840067e7163e6c7b9b9441e1bf867ca2e532926981c98641e6c798ef12d35108abc1dd6 -a519578772c9ed2d691a8c423d360e4bad76afa422f1a5218a7a08ed52c9a5935ce2ae4c0be182eac0712259a43f849d -b1529dd189cbf3bcca50e97199bfb85b42f2b26edd95b35758d988d1d3740f5d0d2e249763874fdfadcefad9ea1b3d02 -aa3fed8d14a4f38df75b9eed7f187a31cbb7a748bd3225dacd8325a71dfb680729fcc91ad8cf0b67ce314e1fa8ba02c4 -b77c28abce17732a08e682491182f63fb55640e60384932f6a9c6d3d7886508c9e67a841cb93e59448d2d59fceec4620 -b7a24c58e3b85d60d654ed14d78993a9cc78c130442c8cca42921ade8ec94bbd0653c9fe5c69ad1fb2aa46ffba04da39 -b7d08f3ce97901261514a5dbae582848e75515c5f9f41f5e70ec17a8d0db3067ddb19aa1c86803bdbb757230b148bb21 -a5b8a6818be4d59079d88f72d7aa4957c48ff5898f3fd01def48ff6bc7aaf9840aa91f2f05617d340092dd9299115c2e -8e548db6b871fb23ca1cb8538d44b77ad02f4cae4d33c8c43228b820abee1aa913ff9acf2483725b195b4e65e2e92063 -9509189e063812fa04f4e26f87b33a2289a05c229ed1038fde0dacecd87aa55ae0fdc678a1c86bf13b81f4b3a872426a -b355f24a5dfb7a8f3ea717111a038487632bf00d67cc2cfa2ab61e1cace7bc7f5bc9e04b190aa6be0652627ee219bf76 -a9b335f235df51b92f40f44f19150e182a938b9abb3bdd8e8c447b2b128050d228e0115a268af4c1bc2ca49552b4e0a6 -b306d3e6cd7ab56f5f7572fe51175ac6b29b189220fe2d380b959d131a35804da5ce95adcfa51d799f18e27d8d5eee0c -aa49cd2bd34c37ce1f05e192fa6837f964c068170ab97989e1cb22ea7e13c2400417a51282519e74d8fb6983ba89a549 -b1d4fff41d95613e30427ae2ae1d3df8c9d06389e1e0f404f8cd40199d6c4277b7a898d06f1579be107fc5744247c36f -99d220454889f476931b0cba3570eb1a8eae30b4c3617513833a551aab0a2630125f72dafc64a766b1a322dd42dc385a -8267ae38c9c8532c7d4ec4455279a5ed4f2e48746cb0f2619937157534b0e5466c5f4b99b7c342c095f71f3b77fd5882 -8bba0794cc4ca00eac50309a92878084a6a22e4c23206c68b8d7268f9e7f615da4b9d0f3e006d9dd84bc3dcf32261e27 -adc965bd7c7bb2a52cd3f4d2cd3fbd72a196876a678863c6a67a25b4a2330d1d3be603220de22c8c3f60c1411df57b7d -a7d5f38a3c4ca0541d5ab101af9c27b04c5bfaa42a1715e882c5e7715e460c4666aac4b6272b9fc54514346fc49d0560 -af94b91ad9b0f01df1d41a459f16ffbe30710325617651cf1da000eec43876161957f079a27b70018ba34d1d5d68cf6f -a0e2a492da4614f41741157d3a1d19a2370ecc8e178d813e22b902cf7454b8237f1ce3c16270eb6f3ead1f92797e36f2 -8dfcd39155d7b8073b0a1a9a617fa75218f569520d4817f3ead375850ea8a3e3dca64c44e83f54afc37173d927070601 -98302358e5b740b73e1a6c568b99affc6de3c7245ae96d9c712d377fd363d8b8f49dbb714aa8d39b5b947b6de341ece7 -a2fe0f9fad663cbbf4bb05f61edfc90716564d5ee5a9529ac3cb8f06f96329248cda85c43f24a2382a9056e9a53520ac -ac50b0727ca2ba80692c0b7f564417916695ea3760ce9fd71593050912bb97366d29ae5ed05ce52984e52218854b8e3e -86f56bea946a4516336a90328fb4b24cc7f82d8710d0d1e34c2e27b6af73c4f4a9d6a848dcc56a87d6259a99ac444557 -b33d0244948c430a58b210943e41aa3cfecc9a823dd3e160634ccc45ea2680987db2912ab2a173ab6cb9cc2b7e16f7d5 -8808f8c2c2377cf52e7314820d88234d7819a6108fe9e1c6a675dc47cd59f81f95594ba2f5fa10e3719580f53edda641 -ad34a814be6019931972a76b3300a4fc9ce763d6f4fa1ea131a67d575c00c827b9ae7260d88577b4b3689e90a845137e -9370abc67ad0fedf30b929d1613e336c6e99e4bf83ce969e61e5d77061b48a1a493f28fe2eff436d4a979af700a83b5d -b0db136c8f4ba2fb7148b1451b18f694769f5e53650d68342f15817b04734ef8ae59681a5754df617d755a687b6ee45e -9149909d24382054a05fc0b057613d059721f132a19017a92198b30e48fbbc5f8f0b5f5db55347dbd9d190ca88f9a28e -883d1d170fb0fa95b55b10b32ebed24b1232dbfb5c783148a63a765fda200e796aaec52747441704967914433a01a323 -8f55fd5ea11c4fac277112d72489ac1de28fe163a756b125f27acb78aa6651c70d1cd8c45e0daae417bf894149ed2d57 -8d08685f99aa8525b008b868f5486e24a08568a5afba9b729f7d26370fb1b162937db28b935d67e4d22f7fda69a3a6a4 -b1882e23d784ab48b2f9e58114c5920bc9d0c4c01d2d7fa5111561df0cf2d738e31a32963cfa58939af87e79428659da -a3eba902d376063e48634c9436802cdc6b89d3a7c7cd03b26a3fccc7218dca85a3ed939eb53956d2e001805aa5c2d63c -b97330c40d51a4b71f91f56292b628379ba735509a66c7df054112578b9df40d3aa32598bc64c03c78a3311a17997bd1 -b84f3d2af2aae2aefdfec9a0693f6bd71eaf4d477cd72d80f4919235a471607c5483b354c9d46628a76d6b6fe7c586af -8a1c39bea7fa580de967d8ced7e3860a9031b07842d71f8c5941b8877cd55ba15ef7aec6116ba38ba290b887b4530685 -b120fccf939e7d7959c2c1e70d7a7aa3b84684dd1ca8e5cfa9d281fd06d23eb67a629b1a27052614c3ba639ff9c90dde -827a8e0dc841af0e2c4a9ca36c84a0ea60099aecfa40294344f82878b6909f5581f7b34fa9510883113795bd09b5e4bb -88c24cc54dac5a2982be5ac49684d99f95574bb8cc44afae4f6e18231ebea0f2ab65b49870840bd3e8f2c9247f62c7c0 -b91fc3f2cf743f4ed42e49007514d43dea1d7bab388a18de6f71367fb8f2e9b8e88ed9f7492b647e548396ef3e3d7765 -a175000c4765a57c57b219b21f8302cfd85aedbc3340fa1690119bbe7cd93dac4fd0ba676b1784ebac83efe3e78d4bf6 -881a373630ebc24dfe17e27b3f176de6651347ae741d55675675e9e6904ebf157e787d86eec42ecebfe4eb8f28de6fc7 -a47c8b155c8ce8e16f38deb345a051fe0c9b217cb7a266fce78d7694134247887789645a82c0ac24341f51da8ee6ef00 -adfa5bcc682d4449adcc436649b444dc61157154e24d68615b0ceab50eced1ab55e15b45562dd8e00785806e9ef2b7e7 -b7d2ecddf47e9fd25dcb283eb80e323300bf5c3ee3344abbc3a1f2a3296c631577a1fadfbf685abb336d5d7059d17166 -8833f6b388e46e1f8fef1086777466277cd418051ac0323e2cdac5902d7ae45eefef93ce90b088bbd618e0381c1ada78 -b6abf44c5aee5d0fbfdbcbf1e77354d5a2ccc239b894e1e06d7ffa76584683f707384319ab0e0d17afd93a854d7d26b2 -a8c61859a9553a83bac398c14c987b20c8dc27d63112115b8aad26bca275cf98913783c802ebe3b7c3d878c130407b34 -a5de7a519f8de4daad9137f2c2838544219834cd70457ef09467d869f4dc32098b7a8d4fa85e1eb283632f6d09971318 -98c33a315a66cd8ab9ca8a58c87e5ec588107a6416c4ea498d0b91bf7597f53a405e437ca0a9d9c6acea27ad0ddbf4cf -b2909b1f8752f4eec25180a17163ab215fc20c4a931d4471d3be0ab64207a65c7e462fc0707791286a92ff2f2b7dcb0f -8b96c2fec34cda02e98510a3ed80a980b0cbf4ec03e3c4260f84027cc7453acfedb5f708c401d26db137032c6cb4a31b -aff645dd6ffe8b5076c83a823daca4149f0769bea3293b61330ebd97a17fe16758e4fbbcb5bea7449595c6e261127b34 -a45f8b3b7196449f9952cadc8d87a787a28b4ed89f8c7599e7db361cd0f0aac6bfa464024ded5c0ffc660e417594fd41 -85016b5f7ea9863557eccb0e742cfbf0b09630f0bad3de55aec92b95d4645055cac60d03602586b34f774bd356dd5554 -94fd89dff2fc6099e5ab90149458a4c794eb1857f1dd9a2c84b88099412477dccfc2996cca2abee68d23a05265dcf271 -945a52621ec19d26f7c8abb5d01e4f5630924b75a349ce74219377a137f4a0d386172da523edaa522d27902444023cd9 -afbd452dcc57f5db6b3fdd55368807320459c16559d944ee8ecd1af6acfe9d58c13f37961f78030883f8ad7dbfac66e7 -8ce96b3be871a1f33d559a6e55e4d86a0b92ec3954417f8d98676264596c3296296532097b9b20c83c341527a0c929b6 -ac6a4dcd58486d25a4db1751a60ca4d02b80c939b39ca165a37d9a0a52d8675b3753719f136a59ac400bde3efd036c8c -ac87a37a14a5d48842d30432935929a0e9dce5642142a8c5b95e377ad1bf52120dc64697f0508b7c258af24a0ef484ae -859f0ba02d496861455d9c39c269a1ae5bd224319918fdc3648311c93303c0e13301ae7f3f77eab4ae43f1184a912b64 -96d9b1d2d2fe70b8fcac136a65b62a4ded85aad9d350c19bb955750a0b24f93174e9cd00c0e0a1987793e1180dfdf66c -a7f5135873a1c08c7c8d46adfed19d0ed0e33168d463ca74f75116168355318ad588ebcca1946d7669c5106bc9f5a8f1 -830b0587587b80df078ecfe0857a4b4cfc05b722c0f4f3e1217048ee18749e9940cd0200c1f7a0f60de832a5a44e9f1a -b6625ed0199097acc9aae20611f02d2fb837e4695762cdeeb4dd722517ba5a344e5011f14d5076783f3c32bb5c4a027f -a17be2e528c463aa4ce4bba2df5b005f88e363b87be7324239413ecd5bd68e350d290370e1080ab9911a0d54856536da -834064460f0e5f38950cf5ec197818712f01950ee1f32b1987dcf7f4098d20e1d91fae6d48e8a054390693a2e572f888 -86217b9bd269408ac92b5cffda5716bb3bf8674b7e222668d72939a626f4ab64f30efddf85108c0764127cdbcbad7d69 -8d7cf47b0648be0bcbd3ad1062d90010e5ee84e397895ce98160d5a568d60a19582c985944ec27bb284459789ad8f6eb -ac056e3ed3487427142b3a4e4f9db53f1a752e1994f178577c46dad71be5fad4d03d24ae7019804c41232705a4bffaa1 -94b83d67af6735e81b2e392e6af8ee4dbafb0071d84486389f36f222dfd015da718c621acdc4360630403762dffcbe3f -8ad27bb51c6cb860c21954f5d09dfefcbe3a9a0bff3e24fd1f74850edcbcc76b5b389a616ea0c0796b239b0c22357a44 -af9990dc4c9f536385811528f207a8352b083a4abe6dc016eb5eece0ad74da65b2c6c475a78cd0ecce0b2b550e4412cc -816dcb8ff8556540b54dcc1efbd2242dada0acc1e3d3da13ae581d905a9106bdfb8c138eee93992a23e7740593e8ad80 -b8fcf8e11e5924d3d38643b2a4bed4b54e69f816f40d4020e76655eba8ffee758c16cdc2d970d3c8c1163cf501044c03 -a50e0ef4ddfba6d969e7dd864a20cafc7fa6aa232fa7a806c3d53c3e029cf110828c5a9c354ea42aca5688896f27e6fb -a560435900c48879ff3f89067daa8e512482f061c68474d951c608ebb5a69c7863a28fd1e216eb4b140e32124e50fc73 -b9202d152b7b708ee61c4fde6cf423b481854538d2580bc43462610f12141b89ce779c7398a35c27ea6ed0afa5332bb2 -a9b3f8be28f9546bc70f680dfb9b08c1eea6fc381cb6f3ebfbe33bcab48294347d4e64004c11dde5eb409ecb19941ad1 -8cb3086d265060f8e52a96fcecddfd261886002c1821a8f59a1ddde19a6bb1354b17cd19a9cbec19149dc219a4c394c5 -906e8dea406ba0f0ef43ff623f8521039a9455a2290cae4ca9bb6494ee0aa812528267d1349bd5d339113dc9d1616b28 -b9b5212b76d5824d66b8df7cdd5effcb05ccab5df6ce67558872c99d1e484ab8d21037bc0e22f5c4082b192972b80acc -a1fe817596bbb5bed93a5dc4c03e14eab627484cdc7ab7e4fba569ad0aaa93b34c4fc8680c4f8180d8190113218d26fc -82fe7a20fe93564cfaf7eade8d4d1394d1b4e36048cb8632bf366d3d8084ee52c74d65c4c69d9d24208f7916278aa592 -81f42f9a3b8007e5f02c26770947f884c715bce1e600f38f164a390f159e2e5b6f8522ef566bf36422b14340bb6d3556 -b53d3c89bf2a4b29bdd8f1bfc001c2533f86d869fbdb383fe9cd93ef0c49da0692361baa9f537094e1af662a3461f8af -8fbeee613823ebfd514e991d81babc05176d5c115907ec36dbf83a69eaaacd622f1f36be2e47b984cd6ac66a6b35816d -a9068ba463ac13d4dba25f9bbe3c93baa35828563f357c53a7009cf0c809a23502e023a32f651e29f14424c5daab2884 -87468aa4c942476b3ac3000e740c4dc72d320884357dd99eb25e81d7b52a859b9ebeb55f3070022bcea3855a9a198e9a -a5f1219eb902234ffe8ba809df590080ce8329ee574eb346f6b4372892d66b0725f048465221655b70b3d4c2deba9fa0 -8d9663d4b48cb86201d343b20a8e7a6ec47a4bce0e85a905be31121a01fbef95d9f29d83530faf79dda163c6c76ec514 -9921ea9176744e15f64b20ac6e95ec132052eb853ef47e9334108778fee60d9d9b53fa0b8011c6a4aaae472eb11cc61f -a04c2c5e2c5a7673652919aecbc5fe09a636fcae2d06003ca6775018112b606e50bd2d6ae6ec6131d2a9999837186bd0 -a00ddb29776d2747e3a6e68eb51a7cb00ca0066a9aac5a2da632f355db515b32e2c441fde870c9731a9dcc8d9834557b -85afeeae8bfd92c51522320cded430c2fef57b1950f9f966f47ce6354e492e9c40f950a7ef6d5202fc79fc020f7a6260 -b047d214201744cf7e675af5fbd29579c3b26020c5e0a53e2ce078778b3d3a673f0fd87eae8af8f0fba3bf0f8341b63c -b8aa5364d914020158d11fe82c2b77197ed2b1a12492435200204e20a9209d3c0b4fdb6fd3f0b1db71ee3b986400ff46 -a59a903fcafaa8b5876a3eb1d79a7db17c37457dca018e393324d8db3be7c2aa3ed2303eb3530d6fe1612fd75dd92e08 -b1929c1711ce44465daada15808099234c0c5c8f43b050b2792b6ef9b77825996a74abdcd84d6ef08d648e77cf804357 -85bdc33f8dda0d853074e0657688899befb6356c38f0ec2ac27c46c39fff06617edbb1c5cd220314335bd1b792f1e240 -862047e51f9119f5a0a607469496c0574b0087d566bc58cb5b61a9a841a3cb693b89837a7c927c542ca03d0106055438 -84ba54c002150e5989f59064b68989413abb5f289f3ccba215b923f86f76c19718be51d503ce3bcec68322a7c7d5446d -adc9ea06c11bf3f0d704b321005020917e731e6706f18a5aeb1b56dab3de39a94fe8aca3c248a47565ca5ce82face9f8 -868324c4ef80bae55510316f3a8b13aa40e60c8a3d55f4994439d1dca6f5928c4cb202769d78c21597d8737e391536d2 -a6e3b57e9909b5fbea2114c352b34235a4d4147417e480580c291308b4b9cd696b36278480893667e8ba01fe3bce571f -b92e1d6ba0a2a244ac5ae2e7b20e152591c1c466c9b4c658c72cc5985ded0392b04ec00e32291f1652d21dcb633919a6 -a3e2bb4dc07ffb1e8dc9055ab45bf22864980f64b612548ca7feac85ecdc426f773d6d48bb7e6c7a578025bfe99307e8 -af764cdb70d5afdbb49dddd519451218db4e97ef3ee622585880425c3d85a8df88613f4b51ad40a1f6635e45b2efa5f5 -a426230b8ed77eca3d1ef7f4735fcfe0e51ae37efea5b96ea3bf313c241bd703b91a592f035e98056315c9822ffe8c26 -96a3ae7f1b80690f97372d086d2d13ea2b40802bd053980f73cddfd37045364ebe38064a8cf3531e9bcbfed421040f20 -8cdfbf0663bde624b703d7e6c36c5753282487147e10e5a24fdec75836f7034e4c38f3fa3df373476af969a4f835cec9 -b7f7a549cdfcca30b78349b831ea5173bf5b91d56dbb999b2dbf6b85d8c22ca8a9a62b38e37dcad7ee5136a32edd5743 -82ca90321c43d616670a7d85447afaa9034459b796b51792c970fd5b8f124e47a13ef661291a4ea58a495e68aa36dd87 -a824a36e4e2db2bbc513d39e4e2a841fa81106437eeb4fca9ebd78050667d0b284b7217a35ee3eac67d8be58c0af317a -9370dd0c0f9c7585761eb5f06e7899d75eac07e13c140c64d4c506b90495fb8ea914f222608c478708d4b47163dc9907 -88c07e19252e905faf129e3e877dff8dfe93e81b3903b150aa33a93a7eda2820a8471be935825d709dc662d06c9f99b7 -81e936c00425f7db8f0dd88b16c3c5208e8d95a5072e69524f3b5de45f4e2dd25f0aba8ef17016bd914bc8f5a42fcb6b -b23227dceec18d6dda92a15b7dc8623d9928d545db93b3547fb068c99cacb3fcf3d7f88e4357801de8a652b919dd907a -b23f1627219587773c17070bbb190e1280ab27c5d7e98b43adea0e1f5017790149b71f90c3691301bd514d20238c5e6c -821b7bff6349c204ce50e00e296982536baff68031165ae4c639122195e7295ea0c82ce66fe32a1b762f6a311aec384c -a26c15bf1ef4d5543c4a006e4ad2a450d44c93c62c0f0b035698530cbbf925f6705d375e1dc8b2c6fd9a2c69f4126b77 -b5c5bfff4697fe13a5177fd87a8e293fd1c6782cfb3d1f95c5ddcb13c309dd1ddbeb14cd359c9f3029b57ba52996c9a1 -87a0d37f04155bc22ade44f567dd8a81445facff15d643886cbe6534aa44505e331bb75c9ea2f27624154a5890aaa2cf -ad85c0e6345e2333a0ff76b769592f2b24fd0661984498dec6fbd2d9b0cec5f139bd71331a28b13aa490baa7fe27b635 -a9e6298b90aa8d3f4385858e08f393b3bd61376ac3dc44a0907ccfb372813bbfab1388d544c1a4907aac38a87dab2abc -b5cfc8bbe4cd3ac1a66b1c8138c5c68e643f7f4c310cbf1483f6e48d4f7e2d1cf24b2704fc687032eb03978f18239072 -9493895ce0c815b60b0ab3a989f63c6ba4c752976160f3e52290a724ddaac9075e07dfa913e113807e0e57725b1cd593 -b1e800c2aa32d34d34b24dcf890f6ccde7da60b98c4646a5471fea7cc6df8862b7a9c4c40f38d0554e33e2984fd564ae -90a18f877f149a314767f5dc15c8726efe5d20a8e15ad4922c6042420a2cd82018be813debf02c6d69b96e8a27c0c5dc -8fe35142442c103e7bca602445b87cb017c76befc83d66894d4f810e343b3a571f3fba14d94521340ee7c5ccb13338dc -b43547cfaaae899fc6295f496f213916e5adf9b0d75805c32df0f969fbc1b4f8584759b2a06b81546b48004d72f2e8d9 -9410d55865098325c7b559eb4e84fef8a3ae890e1d6053b3f173ce22e60ec6563041ad8cedaa2dedbb59f3dd645dd1b1 -b127d9e4b8280e10434d53207a7191782464ae83b4463cd8a32026e5d8a7a8c5306ba43ed9b7ea637d65f64d6a08bcec -87de8fe67524c7d107d7033d4107659206c347c47cbbdf85e3441b53c933417feedcfb049465c67f4c4156219a4f63ac -a582f976e77b861731595ea8450c6b525e371c6548cbf7911f05560d4c7a4b62a425d5c785190628d1aa1f8f27c43b51 -a195e358742d924fe2a7f955eb21ced7b211cfcd5dc3e598e0d2713c3639b72f986aa586b7a22a75f8547bfb46cd52a4 -97c249b70ca2f9da728a256d18d600bb923005ebad3e1d541ebd580af3fe07123fdf87f4e8f98fdf9dc8ddd826ab7344 -8fc7891e2f540d8f20464a36056f227ac2ef3bcf2b6edd4cd2d9024a48fce19480fba36afc7f5c4bd7234787b8d17f31 -9047512fa27e2d8d901516b5714133c1845494b6f2aeb2a0570dd8533852f00a8d9a8ca64979310e83ac73fbeccc33ef -a1be9cba454617af0dd38865ec29e7d0777d7c68968c856f90b5bd63a7cc4274fd8b179be54143bed972b921864424df -b086ccc8a705999184f51e9b45c76975ca8b108b32a3955e122711fc1ee007d8417a85c9cef217f28d6c7799b60aae4a -ab0938a72118ee2980b28dbea9f7100c6f54fa82d93fba8bfa81b6bc34f9d2033a987e5d6d3816fe0bad53cb88bb8c2b -90fca0bddc14f70282f11998fb4c289fad5c0e78c8e8f9e7a811f20413459a05c9d107ae771e9da501854022d827f2b8 -84cc69b7200f63c2214375a7a0a5ccc14bc02ae45bb6f3b27f67ac538d01e628c66b40e5c40cee38bc8634f1a3c3cc6d -8a07a1cc0a96e6c6da0d27a540e235c2ab6a95d087e624c90cdccd781a9bea6abc0456d896574950a9e21e7d87fdc582 -87f2084a2f2218d7f9eb7725617ea37db0a19fb0bcfd7c95501f62fec0bb6bde3950690420a40d93e26f426fc622c825 -8c9fc9b470dcf8e576af943edaad28c29f53ac7e24657618c21d910eeba6d7b16f16c418bdd5cea3d639c3919e93b7dc -8f026883d9d8c7c2a5c04e4c7220ba7061a48392a8a7794a3e290a94967d14caf040a3da3513fd9b4e695376e706006b -83bef852b9f387a2aed0d3537e77c895799c639310cac98e7b699e9f5d74b2b21cbca58ef910c6583e0b849d665ad379 -b08a03accdc64474490706edce9df7853b78b719ee731c195f70871b7586ed274778d99b84ec3cb8cc0b5e38c102bce0 -99fada688669b2ea8d9b7cd730b057292ec3fabd30cb733ea3f7cb76f756b244cfb26df03b9c087b6d9c58f5233dd1b1 -8eb0fc7ab6b4238f2317620191dbe835d4ebaad0882e22e8f0857053d25d6d9077754251202472d875303669dbb806ef -8fac2cb38c3a1e361aae5313ebdc1c7e0b7d1a440482fbbe24389a7fcd381169fb325c79e430be170452326cd4931732 -92bacde1472436209032f0592973a5a40d505a9b2c9de648eed1ce392d0c18e23aed9114a9634ad3a7e6afc4ea80ff21 -a28b394018434be07323a2356fcfd6c70b3a4b1c6b6ea44da1da66c389a659235e0dc941019bc5053ca41f10d9b6db2e -a6d23d7fe7ef475bfe6486ad4a99ea376c6a6db3e70a0a7af421ef6e6c4d6b9cff68d03a7239a56eac784769f63b2bf0 -a1232e6747573e19df98a088fdba57116745612cfdd4ff21f8df82a66c7d5df7e0a6c0cd73117121a516dfaabd0f5016 -8dc574376016b73f6730103cc45c952c5df5d047d0b4ab3da0303f66f43f7d147b5eba5300750e885c621e72b4a64b43 -a66e9eaec79c958e624655fc2adb7b89ff3da0393898e028bb07cbd6511ca8d9318e1d60dc11cf0265a498290e756ecb -8e5299b661dc0e088527904d2c2fc0256613a1fc2b92bb92c633acf145edbeeb053e82b468a3877f6f14f0878fab57b6 -969943ce7b54f6e728724b26cfdf4df90faf9f9796bafb910ba66d96cf34062fee6ed9121abd193c9e322950c8eadbcb -ad29ce021d7fc875d1e61ad3a99e112ff092ffd7900a608bad30517e50e2270e0f8dc7fb5cd42f1bb995c17d86268f48 -a55fd82520f4d35434066bf93a9601c96549cb4714d9ac05c32e16803daf8763e23c3125d2005eb229bf5d7e2a91ec3e -a95eccc21af531c5e1a36ce88eda6b87732f5fa680e851bdeaef73421c1c87c8e66bc314b07ab472ecb67a08ec53cd4c -8f48b5a0636bd89a1ee259223065449523984cf3bd9be78c9242276c848d2140bd94d1a6670e446b51b178ff694b5c7f -8a58b340e30f0cbabcba1c565b68eae66405fa2242b43a7f7d3bdce279af42fcb4ef58c85fe89cc2dc56a41a51f058b9 -99103a659e26c9a4d19404db4220dcc5defbfacfdd969eb7d70b4fbf9b2c91c92112c0097e8f0c32ddcfc35741da21ee -a088cc15a45094cffac52c38df427b7144d621cd1d12ae87d74c00a039d757e36fe3cc2fb35fda9b33b375553585497c -a0f1d15bc388f6602c975b4b9cb23ab83fe31124acd946195b999620c3c20c6610157a891114a43e3af551d7b8c3e4be -a571057592f3a9008bdf726254c364975705a71bce4e084a37915c5317f635528088a2f50afdbe7240c14d813e8e979e -a31e425feee58f8372e2bd4c21c48c299850df34044f27db3e4df55fc5e7c042cd19be59500acb375fd3478379f06053 -94645ca6400f80d9a90f5b1c5b515816d6049ab04a552109c9c16b41366a7f3931d49338d944ee8eaf2ef5c77062c362 -a61fba865027b7ccb03a4ea966081325eb64db5a64c5d765d2893f6a19411d40dd957d8a0b34733aeb3f002a4e0279bf -8199b89ea13ef8eb2f54d27bdcc781a5a7fe5bfef4ba4444bd651ac6021f4d90250b2f2cd8c63fa3ef237ac6eb1bab36 -b39e1e98d07c95a4fc19ab175147547e5a20e66c044f29e4855818db4a7d0e7e2c24192aa8c89fe378f8d8ab3e9f0e1b -b807bb0069474e190b40bb2b34165351e73a392ffb0de83879ddb181989a22bccaebfdc90748f54de81c41ea244e7ebd -8b058266df90032a1a9befc7abb759b64a23ab628edd051da8b81db4211c72fd63093dbd94796b0690ff2b0c0fe16cd9 -865decd95200fe45947a4249d2d8551ca5d7b3d7955adf10f94ada3e69d684e5c5b8939fee9a4457f22d21bbd3ce9670 -95fb5ce7af13976320b36422b5cd9dd46379d13110fce619969308ed6a250cf3eb84c73e8ba1d32edc01aa2f6e367707 -a1a176350aed82d5ac01a072ac7f3cc1535e20fb597ebc7e417921537f9bfc4cfc0d490d4df831f0f8ecedb6be970a15 -974ddd091c1aaab7ed356b65c244748a713e98b133c5606436e531c31b31f6ccdcad2037b12c68fb54af4b19bd1d82ab -8ae9b7a8cd856087300ca90799ec3265b92f84da8ee9e98c6ede1be378dc040d0fe68b8ffc94b146f2521b9fe3d19e54 -ae17df60b83e4530af584991b545bf4b3cc1045416dc15250a6b75a9a04defae4c0f60b8bfbeb54c8a21fa84fee58e69 -aca1e75d4a05282b0cbe6256925c0f269a4a8323888bece4a48aa0b5e7bde7fbf1d3e4f5cc38fe6a38aaa091ccbba4f6 -ac19171d3ee2f2e5021418c37a0eb25c083de6a6396290ed35b4771abcd07fda745fd082e3c32c117bbab7d9fec2b67c -ad8a35eebd3bb28e08b9ef64bf2d8b75ead69db29c96544d71686ccc0819ebc6823e49b3b879ce0e5ee3131153900632 -9479f12dab191269b020b70132996cb32059ac087e2a3f3e559d297494189e1d6849c340ace032946e12bd4923a3908e -8885e680de6c158cd67d66c142b2b4ac42b96e97eab8e2dcb90c3b454dd214bc530fbab6b5d5746064b9813775b6d5a0 -a16d8d27d9b2fa04c7eb8436062a53ee0a4d679bb205d7d7cfc24e5f28e3752a9959847e9e31496bb0cb1c11caadc30d -951b00c69dfd9fc80b17733b843c440c58095989bb8744fc9db63a4a6116f24d5f224a279478fba8cf57753261bde217 -8a693564994a1dd298f0b279e618b46bed349c53236fed9d8e05ad9383ce55fed02b8a361fb8c09ec5ffa8a271cee015 -a09fbd62995a33904b4a34ac55c80f6d4cbd39a902f5db1038d909f1a2d385c3f5eab04b157b5662558bf35ed29cabc4 -8662373988373409a4b31d45c5110afc32aa008bccbeab39d5b09a0e10370dd879684e722a8856b0da278e2bb91d67a2 -8980d3cb8a82b3a827ba65f44e50efed0a6f37d6c150d70e4dafb67b1db173b46ca29d487ef9db92d37ca8312d246008 -a279558faa11850aa4f0dd9ca8bddf69cb98bcd4edfbb0c19f22d1bff85d808e8f2cc026d95afd09fec2d15c116bcf73 -a3fadf9c3066c93aa6a31d2346ad0a1d012c12ca7a24630aee46a087eafe5fa518d20647856d44ac03576bb3a9f81a76 -8a8a19b09417e1b1607aeb54841fa69f58e094b46971c6a5cd0fbeb2aaa98c56599ac242272e6973ca0a9d2c09ff8d77 -858a636f510b494edc76e86b1718228f076b8a21306b02abd086dc2a96c7a034704d743ca5d89b17903fe7b2e43e6fe7 -b031b789e4073b82bb8c78f9d3fc2b901d75278733a4fa0a5aaf985a298269a735217e85eacc0dd554375d610a425359 -b8603ce7cff755f5e07eaeb4d74dff179cde405234bbd7b3f62fd903054aaa34a9b868b04617d7d407c2b8e377227f07 -aa41829c941acb3f9f0e2008e852fe855e153960cd3c85c4b8ab9f97ca91b7a5aa18f997cd023ba9e03a653f238a4f46 -a35639f920619dff592176aad2b4b071d5c960f149c3a75311b16841d1872f29aeeb7c155cc9bff41ea7ee56f799de78 -b252195aaa52e9a34936ccd1aeb40d28fc262cc4570d4f9685da8c591080e97438edf64d4d4d074491344bb5e86b6b23 -abe2e52d10620b503dd1aa584e005d857294565ad90dd89217a77fcce4bea7b0c72d54dca7a1c31b5a9042a9602557cb -818085f2f1b525d9b2322c8785bf27a6759af9aeb231b0977cdcc7d7e77cab5de056e522dc791e72b8d9b93a9c41e833 -930f64d40ab26be006e91deb854c5b22bf6951308dc406b2c7c7791d5dcec470529957fbcfd6a3c9655d544d974de7ad -92b28bdbea8c7588ad3a27992c19d73bd3a478b276f0e11c4e82ee2482e4e167cbcfddd17a1ac6bebdd862be65f54098 -afa6a85fb906f5ffe52b6e9715435dcdf9f7892a396d740d67560fc42248d23bef470989663a73190ac9da442cfe6a82 -82d3338e58fb316d66694ff4674a5d99bf0b13204dd251fdec95d48382f2d2ac60176a19e5ecbaab5e00af2a39a338b9 -b30cd35eb15b3910b8b8f91cf04c223d79d587a7ef713030f0ab93f446caeef52c60ada365f8d3d645b477e7fca61d94 -89554d2a9a11dd7e56f0b568f2a50c72d86362d95eab5d94a2386397012e18bef7c9e01a2d71fd325c0692e4d316dd16 -ad58326fea1c00e0f8aa92923661be4b3ecc79164d68e91c4d1366c9894b6d049a4f31c9bef6e5f21466ec014ba6b94a -8915a16afb0e68a84fd12a9203f8f348954920126d88136ec027a81f541b67c421b84ebb3d6e8f085c38c2499c28ea61 -8e246e1acf655572863481367da007e94bc1bdc1f28aeaa1fb163dc05a51c3526a2bb9bda0a14fc6d658d85a9322e44d -af83f9ad3c7c1504fcf60084e0948624fccfe3a9892dbcba8f166d0d67b475ce57ba008f286069da20a0da0cffe3b4ae -aec86d2d803612e8d27a01e3382e0a876164baaf2f3b8c4e9455ea00bc2e525378018e6a41ed9686c6408148e852bec7 -871bdd8c84abeb1456ef73595360de6cf9f92ca9e6a8b6b816ec7497be60a9f509ef2c91332d17cb5fbd347bb0113d2d -9503ce513df28b61d721fd5e8667272a28f210ef787bee58538f786acd16f04a412387c6f5e6313c43f426a70aab65b3 -b2cb0526e7e524ca9fe918e951c19460aca911d2b5ebf97c2bc74aeb69778a28316dec8916a4e3628b46bc51586c1bd9 -98f52ee1896b632dff5153e3d1fe389c6200b14cdda6b27e12d4a4182763b63e0f587386aed78c97a32114dc286b975b -abbea974929c9ba70551231e3833d5cecc71c60988826771f792f190ca77c80efee7607dc1d6bf01a53796d8d9b73017 -a4cfea1d06cf840bd599b14c011b6b204b2cf6f57fc7d7f310052062a4fe8870f02504e6c837c2b556c925921e543556 -b957529d7e5d1fc45c5a822a6e0e480e46af2f5cc3801c31996b9b1acacfdd8d142265148b3e1453a0df0c5e6cffc5e6 -b7411aaebb1b6a6a75568f81d052e60fa7752a64c20dd7cd5457f999f0185807987de8fb72ed94ca9d1148c19ecbe1d6 -84be67a5ca80a1fd0f43cce4c00a465f167445e42232c2d2cad5e1097a62d3ad564041a55f0c76a340387503f15e0ac4 -98803688f8e7b445c7ad14277b9f5f12acfba4f9a4ba6df9e2b7dadb726f1bee5098fd15e0b5308b6686a38864f84912 -b085eaa421e566276bcd45d8b9fb71475c4530d63e90914eb2a33c17333d5628c1ec8a45691cbae82ccad97d4addcc94 -a08ff7dc59dadb183dd0b5d336b6174464604bb2b49315e0c42f34ea08a8bca9dc9207750638bb7ebb6387257411956a -94d72607cd8a75b2fe2e9333959bb9d5b54d74ec36fb8c123c157b19a17f01f310b3311116b34bcfac305e9deabc79db -85fa61a796226ce555f8195c792ff6f3d483f62dac41c17b7e8295bd49ae6039574896548728fad4ce966be84a62a6ca -829ab1087ebb61db05c59e3c9d03e7010f8c546db117a6409bb813f6fa04061833771c8aa4c5e2981bd1ee551df0ea59 -97f5c5261db0b130bb8352fbcf65002327bd6d8a7d4fee2a9bc293173c8c54be37ae229c5488c1983bc1f7857c66188c -8756439e5978ba19e2cef95dc55f706d53a05d1fa964c64d89b0e95470b5344b2f8d44680080626c37c77a00ff0e6b00 -915d33f90980089c33f403ba4fc5c689ea7f1656f5c4e1110db987c59eb981b6a46dd9fe82c8efe7d1e3504f1d2c4d2b -ab5bbb84884ef036c9b00a84f7d5ffa2931854e2afa5a63121fe64d548531af4203495b977bfb9301bb1e4679d42665a -9830b846a9041e4539eb858a179b4db6da89b507424e6d858ca4334d973ddae255bbfb04ae25c3276ccbe97c46f5816d -8e35f4563b8a5c9a76cc1da87ab21cd894de393dd61bc977cf22d3de454de350836e032ccf7d6ea55e2e6b83c4424146 -b6338ced0f05806c625905cc51b7e772c5db3bac144e897339f67b6949f4d648d41b7d23bd3f299f4879507951ec031a -b3afa470fc71b92f415b879a814feb0702b6adfa08e395cee4f7d8b0e3537288f16c83b28ad4e2db02c1fd6d39e6afad -b4fcf7af3196bec84fe1f6e3bbebb8abadbcd46de02a37966d0ebe20972fd890803d570e4a201f2a89f479e09f19191d -a21fe1f8f57691165d0c7d8436765562cc935288f24fe765351be335f906c6c4dd1d0714b134c51255b14511c957319e -880a3a8f6b4ba410be06628a011e6bfd38d86919cf8014b4b4e1c930f8e3035749579389690f21bddc4d4699de8a4b1c -907d93a7666d847a140367c0a0ff80a96d6a8295b07cc4ee52d3be987f431d8dcb95d3717dfd248a5643c5395ec2891a -b8f38c78b8a2c487874c1a6a92d15cf0dcfd26319d4cf65c2f4fa9432203ba5ffefb02b7324022c34bfe0da369d96d65 -8bd4ebb6d720fe52d626a621670a06c8a304faefca3846df1f619f4d456e14f8bdc547fa7210b8639b89c6584ea5c5d3 -8ebdaa288a71a2d3188d6294ad0948a4f72c1eb6a2e921ec82cecda4d315a86e3e6233b5ffdc7219f34a99e9b4555317 -83320fb9dc62119655bb0055192471ae06b7641dd4af64670a4d9475155733555ad06a93ad2fae72e029049601780654 -80b3d022738318238dd32f122bd88cf2f734a61e315ece521e9e038f4a9bd7b54b5e67784f5949fbcc5fa911dd4b048a -891a23b4bf5cb8558b4540b66fb6b9fa54e9d0b2c084f660c8bc77af5ddb97cb5d8042b538f61330d9fa8ccbee6c8a41 -8e5651d9c95aee23835bb1a06eea76efc9d5c881cf87ee847ee5149fdbf3d67dcd8ad0675dec8fca6cef25368348abaa -86bf1d094bc4fc7c21b21cfc7adbc750db0b27c35bb160d306b26fefb2699cbbb1fe624df1b9e7f6f895f1b81a829361 -aebc3cb2623344315875029378c71ab7ed3cdc9d3d42d4b835b373c8420adefd177a44e532f3f06f74f0a40d53713e5a -9527f659e93a740b4c50d0d3d9aaf1a85936f04866ffde1aed30ab2fa1c1d565b46bec5fdfa510fc3ea934137bbd46df -8488673a4bc29c3ce9133cbf41c546fab4ff28c5d46048a21e710a8df4f2bd1c77d0ee242dfd962a30d646e5ebee8c01 -8cf29773c0e0fdb75bf6f52d7066e7d6e9a3ef056bbb70a98026464b32316189addb5766822f57df63bb68b78c85e1de -810c6c1aa53f9c3fd0018651b1bf25215fe24687b568f21a121e0bebee576a75e5f0d08ac9c6c21085e52228b314c6f8 -b529a87fe47402aa9ddaceac63a060a6640418891f931036c6e4098a1b308821a6f1a244fd5c1c22a6ed5f72f6bcf825 -ace9284ce89b5c81049d329db2376a85feeacdd9f735cf00038adc51865bb78bd9bd5d060efd0b727c509ec19988f99b -a2e7a949c951bddc99e68d80b3f3fc4ab960b682229fdd794f9eadc80bee91dfd5eda0052149d05c74fa33bb40d75ecb -86bac22daefca9143e0b1d25534900b1f7711ade4437642043c4a8c65f0d963cd1f0f958c7391e5a663dd3c59ed9de60 -b7d2a6e2d44edcaad19498ab3368bfb87f9ab039cf2249d6e76091dc3db0c3bf45012779c02811cc818e95796e6ad9c3 -ab474f74e1ebb3dc696e7a6bfd8845ef15fb6411fa28426c486f7b0f789a6af3016ed5f7da2a36215729f5cca0b36b4d -86616a1a9dcb50d1896f3eb937bde67f213558feb401aae9898e41cf1fe33b443170c7c2dbd1648c9e3cdd0c24289286 -a466169a2d95a5fadb6a69c7061cd2911c3eabc0b1a2488e216f8cdbd2c5bd87e80908b002b9efa51a67f02d7af2155b -8368af8b7c0f55f3c4f7036fbefc9d6a0ee9ff61197cea8ce48546753bdbc0b61eab604b8fe2c1aa91ced7a879e5899c -996c91779ff9767232ae603c5b1da5bbe0e303c4c2c72ad2d5944ee1297af3535f6bb3548fd1fe8a92cf4b281e1d83ab -ad4a93d1ceecedd27389c658b38dd71cb13c729b27e490381d8c3ed4815b11ecbc37b1f82c0656e0ebf77e5bc35196b1 -a3538c7ea3dddfbae80d67caa9fc547938bf77114559f9fc5180d9d0ab837d7fb1b27bc37405686f212f2e98b0028e59 -8abc9fe135fbd48414f2ba28344d9f49ec2d5ce94fcb314ab8dc31c754f3ab7e6ab268184a67dafe8b1fb811a762c112 -99ace100d8db88a83f1727b7b48baa1cf45b971d08112e452f5003566815ccba0ac3f8b1df6504f55a392efac8e3e70a -91ff50978ce629651f1501708908d75b490c18615e933191cd37613a83d4b605b0b48d024d27807637e662056d76276e -8e4104331ff1a40cbee9f489a814cf5bbd6fe4eaa1cbe1e13625fc3e6697b27d933265e5ef8728cfa8fc4ba5b19a614d -a442360d49bc9ce3e75eb40bf2ba05e9437fa594e8b8de34bbc822cc7b706dfa0dd10bd6bccb702d8556cd1320924821 -b6ed6cb0aa34d5793e929e0d9b9651e41da3457a0b20c1bfa93a8f65bbb65bc07c7507482d71c1c285f5f663ae60019e -86d64df2dcd36d0c7348c77480c8af33dfd889bae7bb045888eecbd317cf3e4731b96ac18f410a99ed33a3f22d448f77 -b8dd25415275d5ef8260bf5195ddb9b15b78a8799e4d15cca7d6317a18eab7bcb8fc759be61360915a28a8fcb5d6ddfe -a325a334c84dc1d9acc0a9315b399d4be93351c7049f474702ab58b4cccfd69aa50b8731ffd598ef0144ca96477c273a -9012a2dfedda5147cb9ceac681fa9e75e2901eeb3c94d87465a44d11250de4bc66d1e00ff674f2da1d800b43f686df9e -a1049d59da2a942d4d2aabfc0d972ebf3babef9c5d8fc5598ea23a048c2e58f7f17b4d860e437276bdae221d9e41e3b5 -8c9d9a8826c812943d74c4d4f0fd2f1c8087135c37bcd9647b722b59801b01775a644e38c24b43e8e70f83bccc4afa27 -b9cebd7bc7b041c18bd35b970f87e9b5183e4ace034e21117001fff8a05b2a7f9ab65cf6ab8b818b8192d1db5649312c -826710d6432ef97625db25104fc8dc3225bea594a10cdd4473d5ab72be57b74928ff356d210032a61ca590bc68509880 -a18422ceb8c61af305277628e154d3a9c49f47e230a44c6216128d73db7c3ca9eca9f87e29cb2126f1c312f423c61463 -919d357886de9eaddcfc46cd43e2b3dda3f82e926a3aedf02ebda9159faa00736bd2cd7aa044c76ae238a3a95a5bef38 -a822d5a726f5c38e9d4a750ddec80bb965a6e5374a3d87757e2e48a18421f3142c3985450d1833f3ff4ca36e3b838c89 -86bfb86eece6f6ea8f51985e312171b9bc821e0c3ab4cace556da28dd7bf89cfd5be3fbdadcacc19f2371c6a11c564d5 -91b42643b297d8eb2c1bb3f16b57ab2964de99dd22bcfa07db1d0010715ebde94d11851df575f4f1ae602644e454fe0b -a5e444ed3d5fb3c5afd2c9c24d676adbf396f5d1d47bd532edbc72c83845970582ec49ed026b3b982c9c1ea725192cfd -8448387a14d84aac6afef682a27be67e5b05d31b59346748d2940072eec771adb53339f335daf4463f555da2d8543f18 -a5034b66a26bad0f753be56dec722fc98a072bcdaeab0bb9cf35a56a573d9424cfbadbbaa8ae30690f7c6c6495331fc8 -9317ac32da1772099f41564ddd8247e3532528b240db753a1fa6fb35cc039c6a4ac4546597bb2fb28721684bdfebdb88 -8b4b0001a6234335502c8b17c4de274b83b0610960b5c46b9075c6e41f357ef0d8c94e9b14bff8be7849435512626ce7 -b1aa903511fe4219acabf8761a8e4316cc4f8955ac8640c68a7b547cfc65365a8fe0843a4098f9f17a4c9beb75624393 -8384f4953395aba4939b24b0669853df78f2fcc01b2145c08d3fc333ee2a7d4adc12f2d81c37d0cc187ef45b5f69f59d -92beb5a3c14637f84ee7a3c9b4d9b305b10af8963c087b86047e9fa959f41ff362d56eaccfe887bad1ccbedc488abe2e -8c60e16dbdfed2d1c8cf3f1bb0b0f462489293892f9d2e0221b1691321a771b163fbb599daec4cbd917da75f5f662de7 -a8a6e3041a0c2a12c76f51139b221b03ccd1afaea3b72ba2c3533b797d5f67d8b90d3474b4f6f8e19a77894fb90842e4 -966aaf74560bd4d164ee46c7d393b2c628e307019ca4289dbfb6a9a991608ad80efc1ee6e9847a19382ff8f3004aac8e -adeaec475d4bfb6075be90cc37d61d45ce14da77f8a9a508b9f829ddf2abf91683aa2fd0372d3025a660c94b0f612685 -b3392bd1ad0c202d4a95912e0e06d8c64d7e2a8818dba8f895abcd0f6932efa9a0bff8a2aac107046d3478782fe42d33 -ab38804443da16d32f11c0e364449ed351dd36b7c82b5c7ababcc33a930acefe09fdb5261da04f6dfab29421fb1cc017 -a34e0df9e953841bc44c09e16d69235a26ff390a6d128339ac97aaae5616865f86153d8d7466519dec6c52ad592dd3ad -99581db106391e6816403b1e9d13747aa05bfbfa5b46696cdfdedd1627b60e1ddb92215d138e007770512e93bc6184f7 -ae60c3b1ae3594aa4e3f08eeba3951157921aa6511148c6d32003d42157654d4a3a39efb1bb317135620f09729d134d0 -adab0bc35ca3fefb14729259b16907a34e10ddb6d78a23f28596d3d9b244709651be7719537df33bcf003c0e43bb1a66 -a31b7b2f3411f986b3415870ae42f90bb678a9fc44c942f6613cc4f90f3dbffa4b5fb8bf3abfa4361dd8e396d9a3c5ab -a69b188a8662eee48fc98201fde6f0d14f6b54db83ab79c2ec2f4b6be809773231704fae2cb281fed8b05107c63f2fda -b79e1e7a9045af6537981f54dfeed0a1335606301b73eff001880798f01ae9c0fef6e427e171afbb1d0a78135ba912cc -b1b883fbe379995b3741836a849516a0f21b18f42a34db2c8cba01f86711a2baa5d14910a110f1058e36431dec163cbf -87bc463b90123cd9e177f2284d72a7f4a1d4151659e1e4e8900bc21986f641af2f9a3386aba56601e6fb64da630b84a1 -97a51bb7d717495f943db162837d3bf700ee0653da9a94b36153443584602156e168fde97d77407d0861641d8d373094 -8b02561709564d0721b5247775dc66c6c09cf68a8ea62fd7dd361905ebcd98bdbb2c554fa272de71c6d22b04d33e6902 -a914b9406e71c09deae875bbd628af3f54de5ccf811365cf229dfc69541d996689d05679eb02d42a0adda02be6e32d2d -85dcc5f3f77f72cf0818bd04c037cef560f0b0eece3191e06fcbb54228d11f7afbb8d9f8675b404bb39ffd04a3b65bae -b15bcb96a98bc6cc7b802dc29b79a903223b1712a10a22e776f45c530a4f767665dab1a3c6d1b52157f4b79055d5ac81 -965e353e665b3734042b61951e105c1800718eb3c46759952755321ff5c639327d045c58fe90befa896e96b826910298 -96776a5cd26b69f08a68af0201b2f739cdfb9553b466271063a6c8b8307f2a3f51294ea12c7e8118c0e6b884886e1bd9 -a369453bfbe7ef0b2445231704abba25527b073bf735a968758975fad789c74110a573bc7ec50001368209a0ff385500 -8e54dc4f2a557703b2d8bdb74ff107bbb239034ed363818197b2569c03572c14cff21273e94802159563d50205edd651 -a1c66a1a82c60dcbd139b8ef4de62be423e7641a6b94ce0d0468e60bb1b000d268755946a028d3961d8b4d3722016ad1 -b14b3c26dd9d17d6fd8eeefc7f706c177ebbee9b8d05f9b01174deb37649f77f97ef1a1abc0cd4ca7a13618a4036067d -8fe8f9754c5ee102bf96ba6b6f29a14fbf83cfe3c5f81b5358ccd4db87fd8c5d88760172373bdfaba7eaac98ab1fa863 -a8c308c15242bd9c7b28e110715315a1f9818ebe03662027a6f1feac13a5dc9bb111d29444d13546d8e441e49960b0a6 -85d87035d74a1f4662f42a8c6d26782daceded0aecee9232b78139b1b50fb764e87cdc5d1ca9d6905735dd9c3dd00dbb -986c31370f594d4c8a9096c091cb1484c1c0755804819a9462ad1b67937c6b378d97f1e4c27900405b21de2646be70ca -832b4b427f3347b0073c24f54e17ac16d5a80d04261c1d464f89dce89f42750d69dc8a83ee0481e410f94cf1d108c0ab -b13e54d91d5d414223caf43a7fad36930300594b8cb3ba97c0c873cfefedc165d05f05deec8d74a0412d5f0932813088 -89c931d595849c8e54f50d550ae4a5d71c4bc74af436965bc32adbfe829a48ab15c856a69070b4a4602e0113131ce4cf -b03731793db466b74112a1b9dec3344fa952e81bfcc7fb2bef3cb20f566c3b2bf60c16a93f84f77f4c83d8f2a535a2d2 -92e8fc80d49001139363e3201c93db8326c41322db51937ab641ee7f1b2f7d03089e20eab19afd27abc23de039ab4b0f -b27d95c90dfa91886aa91c9c8c85ce09fc875279028bef49abfeaf44437a0528ade620c8c2b3d712ab594e73c5c032f5 -a42e2598731a792975feb5b24bf00b1e7cba1620922f8c2319dd5878419ce6099663b448299c0623ce400875c48e12a1 -b062840f63b555a254e3bc36e9075d57c816ed2e9cb0e262f9de0f3692456d94eef702489e5b11c9746b949b5e84c06b -886226745d906664c476615dd41deef6c338ee10380657fdb75cf9ef28b4d9f56e69c8d0ef01e9cb80eeb42f3e5773ba -854a3649dd5b22def4f246eb0d1f1a206d3dfe42b5e44b5fa963a7c5b8bdaaf7f35b542b3e9cc53187e66a2315ed9f9e -b5a48cef68a056955ef4c080c85e4044e9f8a562f2beac9fbb5e19f8d618718c86794338c6dae8f94b6f5e9f8e98404b -8f8bea7304cab80d0009b417c198bfffd166eed6f6db19f28b7616e8b0733cf0a4d54d204361d7f8f179985c8c3a16ad -8af81f10339e2f75f6b6fe22a641298bf90c8676260abeeef90bcd52f46ef013f5aa4bd9d0b5ec15be61b7c3e0f32350 -b0397c64034598c825f9ef653ff16f680325546695ee6e9c2957d3c87593161a063c5219304ce6a16b7db75f1a2c5f7f -8d2e7677ab6fbe2b0f5ab6dc356190bb3ecd7fc468c698d512a6c69f22ea97b71fa961c88635897a5b539ea51b70b4a0 -b4e91a693cca1007fdaeb7e679c6837bb8eae0bf61aae447560ca6eb5ba918cbd9952b41769657978413106b359e169d -a8331a907ba7d95a5e4090a7680d1bce3cd803db49fb84a48996e96514701de1602c4eeb4b5e0b1c2a106c4f678a72a7 -b54dd28a97a5f934a34c2817af91a41e57f88d7eb5fb584d3b6692f2d1c4b2a4e273c4de5fa33a0fd1fa02c9d7cd1fb1 -b8b780e0f6059ea27aec9f3693ac9adf0b93f75fe7fac5230deee1e7471df0bce9b5b2f260a6a0a346afa723860471b2 -980e9847ec83d61442a86cf8c7464b357694dbe67aa5de3a8c88ccd1a038256453101366dcdfe11a565065d78ce89807 -9350a17e397bdc3d2bfbb84ddc79a48bdc6ef5c3d8c1ea39251e762fddf9962b69cdd42c563d03f64615b72c9dab07bd -a34d24b69089cb5ffc5f06eb2acfeba13c96a1096d1af9620aea28753baf3d0aad0bcb30037ef3a5ac36b178816e878d -a7c8b9108fceb4e0377eed48af9846530114df986cbdd35f6d54026104fe6bfb3b58e57fa2b3a750225528f8dcb8bb9b -b0f71f6a04cc7119db96033f89530853d58a445565de2efd269b1e3956397c35a49c328102325b780fa5d0cf5adc2a4a -92be082f04722fdf3abca7ebfd162b7062939c3410ec204d5478dc8de2bae2b25e2654441d29fe2c350895512d333ab0 -95e7afbcac22dc2d04c5635d7a8c6293f6ce29bc6c932850d24ab5216b449251bdf7aaea838ef40e0e4eee1de8f63bfe -ae0a877b488865f21194470677e12ea7e357c5d63f6bc454f608e33df9a3b20e9aaea5b6aa42e8999779b8b445831c39 -98df977479667e23b897b91f2db8f4cdee7ece7fc3ecf8a07d752efae090d8bd34d781353ec1394550d8a207bffe582c -aaa0f1bfece62a63f3bc76862b8789e2593b4bb40b3c413956e9e5c4eec604e39d722cbe1db210396eca7c2293489099 -b362703d2b72909d06407d139531fc144e68ba94e55643cc3cbb9ed24145223aff460b1627b41eb9a3b709978aee5a58 -b020025128804bd642fdb1d2b70b07d181e5ba30a5ee16f6bd00d7e2d0c6af782e454cec107304823be61647e65221fd -a409894c0030081a2c7f8fba27bd0ac53997a31b35a33498d78bbcfa0b7ec0a89b9efa99dc1b8770ba889060f39d56e2 -862f9eace3f54288749ca8402c22ddd7829f0454d17ff4891727c86eace899cbf72d302065f5f581169f00186c23b4dc -91432f2a823c3ce95bdeb5854e8dc7faea5031fd65c82dc69e4adbc5ead2e5a5b58a9cd1428d3f526cf94a217f37d7de -9543a9038fdecaffecc4d3023fd67f7976dcdbc7014e82edb4573479b1789b4c610c3964643e031f69ac7a3e3dfbe241 -b4f31d580987f47c550eabd2d276678a294a612ac26806a06634b8812a571391151d84c29b6b82218cd84dac85bdcc88 -8d922ae4eecb45ebc23eb1a8404aa1524b281d0f0ceda58ea93a0cfd4184efb894c047f0a46e2d007704f5506544907e -98973979672d1d52e561cae7331b730a577c422258c22720edc344aae35ce071be1b017816d58bb29b9cf5c433fd64b4 -a46be974ea72c5e5bd16de591bf27087d97b9030fb4a74743bde5e480052a0de58bd962dbbf0e0fbb0559566c3d9780b -b2b4464973322d865207949afa4dadbd888c9b0230737561c3b76a1953a85ea9439fbb1db9d0d42083c62419db512450 -ae811a9eac5f4ee6cb3a4dab456a3e5d95cb1ab303c19e76fc4b36ef6b4c83ec0b2803ab8680ad1663bdec0ea2f19aaf -95a426f3d2ae6c6069f888010bb20c392bcbb65d0986125e0f0066d4206f4f443f70dcba8a789da042b57a36980e75be -a9ec01a5777d10275153ba7441f2e27ba3d6f1a875f204469220ad999bb8a0372369278bf5a11640ac0709771b814a31 -adf1091e24bdf10d848f1a0920eabca0a2087220fa0c3f8e5b4c72ca0424ff3e0c77ad4c259c12c3cd1c0eb0cf32c67f -b9a57eb8642729541088164b9974775934d7a4c56a3a3ff2a190d549b294fa87002810f31251170b0407c7e9695cfba2 -8625501e5c56948812b72b3495747412e03ede90096be089cb8040069e49cddfe697766ee72505bf715802fc77c08fa3 -8a745aeeddd1be100474d96aedc737208ef19a93a8ad72c10bdc0218073fde6209510048eb46e271553b04d8e6529f46 -8b8d9ac3b91ac0333094c85e81fe2b8cd5c2207073a33f66bb1939e8f1c84ef064a8b2ee984a9f450f0a6e54bb56ccc4 -8cace31444da99fa5dadc7c46f689fa427949d8c089af3d90c604fbdbe0dab052392fbad4b5aeab707e4caa9e739f366 -8750c8bd1f1abe5acfb29ecab0923008cb4455ae8a1db01bf3317df05e1e02f9df3c74e879d9c57b8f59877591939ab4 -8904a39ad86cb42c06692d4801b3718bb63a07a2dc5ef13de16f668b08968db34966457ff2e4cb770dc61a216f4abc5e -967d1750b0db53e977bb9ba65aa820d7970f8c75d5355cf12a3f4c509dee7e9b6c0f7a828474b167c25b15d74f0e9cb3 -b37297bb6c2d9175e0a7654c5bc6d248f47f7183c3b10375f07e21e9f3e66f6581caebfcf468dc0f8c04132a2a0ede55 -803862e6fbca945cb6c0ba202257df5c7e1e1fadd78b842970206575f70c9757d4a54e9b1a0a269dd37c4f830a40d2d6 -a7a27f2fc7a1e6d276522177f0ae6630dcf5205d08c19319c315bacb165b687d125832d97ed689960885bb7cf42fdf36 -87fbc08506fdf980cdd534d4ecc4dcfbd381f3937dafa09db402e07a67e1cde579e680d3f77865b5669f35fc00901530 -8fab8bd57f76d187f1cc22e40b51736b1b0234e70813ca02559ded9c7835cb3dc71a24c8f679081510c32f330d6ca45b -8fb917b7dd71e1728bbf32fcb55343890aa6fc890740f41f42e9620b5bc3ef8b1ec67d9c047e4a9de0863a5eec18e5f9 -b7429e758850bb7f69db000d49763df43d18af11460ee0f158b741dd6b7575527c5c8068cf54f7f78098f9ddb92a82db -8bd3c73c1b6f88ed2696d53d2a0617f74bfada964d2eef2afb5e1cf00bfb646f552643c55d5453cc622c9ecfb23ad492 -8e025e91b30b0f328cd6b79df9603698f1715eb6209e64ef8705cdde5ee1c4ec737a61d9b8a4e72e83b2157c621e1590 -ac0b91bbb5ce5bbc8e8d6c0d9d4e51b3960169c608b6220a352aeb13072133aa9d934b4e69d7c5c39fde68d467fa8069 -88255d08bde3b967dfb1dd338dfbdec12a2079851aa796be070a1d70204048c34f2739b7461840136b03429a8b83b1f8 -97a83477e765f3f17eef0d3243ba9bbdcc50fc581f904e92a853a076adeba917279fc0e01aeca42de1aed8af9579bca1 -b0d9f1afb807e0e6f839632393edef25731ab2141cfa1cd965e986940a4916c8788733a39def0cf67afedc516dcc6ce4 -b563e9ed9ba2134011d7bea6314af5d71f63caa1bcbf878c26d7162dfc76343c38308955215252962fd0c9c87200f1f7 -838d4e97bd67822c22cda558f0d35f971a0ab7debd3da3f15c27f7d4b3301b2c17b60cdbca0da8e067f23fc97d136ae7 -a7bccea326cccbbc4773de402fdf2cbc21a028197be98cebf6e691a7679fc948e6bc4981a14fbf493a254eedc444dd7a -8b2687732f7aebb153bd6030dfca0b6d257b8f2945eb8221ffd36ede50d463172cfc4bb17dc30bd21d8572aae2540d6f -a4a3e87ec5984c3a755cb39fb04472583a0d2c771552b0701788f03b4618c87690a13a905420358701777e8b5ff2d190 -904c4dee5dfff129de3fb8cd0a6e0576c18ed3d77f49b8f0601997013cdd4ecadb86690389555ebe8a436d8084024f2f -ad1d9c7a6236b22474fe8d45fde2e1f072101b5cb7018ac73c0541c0f9ebec4d5c4469e0570cc188cb5f5ba1d8958be1 -87fc8ca6f737cfdedee973f1586b94d971564a1fada0e4d65894222edcca6552764f1ca0b02782066f19f871ba5842d8 -851829a8b39eb6b91523548ad600bb876408cabed98d30958056367c686bdedbc876e1903b8af8ffa3d3618e3580e3db -b99270859bfe7d8a4c1a22e2d88a644dfd2f100c54070ffd9c4e1044140fc0d21d62c61214a2b81a9cfadf944327ef8e -b89a2ddc91c59dc2ed9b8d11e4838002e731b0bcc576e0e18106238cd3282264b14cebebd8a64f004521cbdc690c4182 -8be96bb11a025d265b7b3ff3151e9e227a8416e6118595ac29bf836ef751504eaa3a9cc05bbdcdeabde11f2dc3d20c3d -87185ed410be571fb532e32d0ff4ef68e98ba2d3d5fbe92180cf1fe8ddfbcc89fd1e03694a9fde1a12ab905db89323d6 -97ef023f71850ddb282f244b3f39579eab69ce5bf3fe5dd2159329b7def4982cdbdb4e71476471acfea0f7ba5a7fd061 -9944324d804fd3978e7e137e6e65348d7473ea23c591136d55779b5a31f45f9e4d866d8a18c76a3a0e8cf2ee61cdd041 -b9930c9aff260105d4d15fb749aa33436f6fb52cf9d50e39dca19d9cc7938d752773f06756af86369e1f5fd5aa71d5ea -a85ac6bc027ade2a9bbbab2b231241cbbe56e562fe621ea19208a8ea36e1baced89ec9ab8e2f83b602539e5c053f5764 -9917d40d37549caae646848e18ffcb49f5c6c4e396ebe7e74129a41b0cfe2726b4dad34d51f4bc706063e654da898824 -a25f8a4d8ab34724a732dacd2b316c80a6544d4b8c1f45115c4f55c3efae6129b83623ffb31da80e2601f70ca51ead16 -932b54b2bd26670936843a92346d231f2f3e3659542f4d4def73fb36ac0350733853130a5e5e9d8e386d34f817f5a91d -871bf29d7263bce62a02690681d4e1c3c2f9c2751de4e35810ece13c9480eab93b80a00230ef0ffb858a829ee6bd96e2 -ab9643bb1c32dc2e8c05ef49bbde9937072af214c19c3932be137b7b75268edbcdd81d1370089be44462b8032bba3c57 -b67d510c460a2f14b7cebaf9a15642a14b2542c13ebb1d1690596447ddfce6a86327ffa377c28891f6bbd8febc2c17ca -93a5ad5019a8e680bd053a524e0ffaf8cb18adfcdb22ccb6cbed67012316bcebed65294bcc0cf4f4e2915dbf19ff0948 -ac7a7fc1140b1197f2aa424b053e8ceaf48abf41819efaff87a2e63cd6e962c278942c2b97742ffbbedc5cd426a8df50 -af0115d9c2f887ff97ee15a1116ab06af1920f2f42700b75cc010d4c8038eea941c9bcc8e7cf4a41036813143ab3e8eb -90c768d880b6ac17ed7ff9bcf76cbd5c1c4879247a757d8cc8b31c4c7bb0ec763d746e6e06e361afa8ee158e36ccaffc -b3f10561432a97c95d02c1a6f317bb1ab5b98cc88cf5d56e1492ca84eb2ae1db92e9e31fa454de562e719b71442e69f0 -8d94729b5fb0afc196064991f9b3c8e04c0858199aa951f49421ab890079804179fe00707978f15637b8d16246794001 -968515d07a0f0eb52adf439d8f70ecd1f6655072abbeea45431dad26c8937f4aaeda552a22a420598d2136f576a966d9 -91f50e6f292e2bbbe226b221cedb9db36bcd459bfd74fd6356b0620766d96869266315e8503435af1719d8ff765467ea -968b328d79e183ec560e8f0de113298755cb23a893a631406defdd26ecd52e4b6f28934ad2e219382837fbb8f87f4360 -94c126a9035059d2d817c4fb16cb13fe6047c356fc495aeb369acb1c45e89306554631f50d313707e82624b6107d2fa0 -90ee85deb494043a1cb280d687e3f55345085e576484308755df1bdb6f734e7dd25fd2489cea746be5d2c6384e7986e0 -92a4f64d98e7e633271bdafb1eb88474013b5ed2c65137c243729df0d79ccdc6b210118ed3587ad00d3f0f757400e47b -af31031fcc867a53760216cc1f467901aeaa3b28438fb3ec90d6a1c8a46590062c40fac939bc3c7e7a7deff8f83c262f -94306afe09f20d5de9ea26f37f5fc8df1e29b3a6963caa94df031efd428545493d53e0d8d7af12ee525e2e21cba23324 -ab6285371b981d5443ecea699af9da916f9320b3ed0a11c15503f3b10eada3ff5dc95d24a54f5aaab97d3312de5b985b -8e9735364ae128f790dfcbedcfe0e11b991602dce0c90ab3cfd4aac74526c30a798fcb51a8ebcc5528d88c724e9c2b02 -89a3c12bcc68129b14fdc1d9b5db8d26d11c6c9467f5bff7c40abb8ec23b193746697421ea4400d5ebe53bb3fbfe59d9 -8368e44144947f9ecfa5d126f4a57bb1d3728fe3c5d3bf83310174d638a10cea02ae79fca91d5489ecc9fa679feab49c -a0474ff532e1a6a3dc8f16ae27e77d6ab72b62535ba0d3ed09da5c692c6fd34424141cd68470922e1e147fb7f7479d5e -b9ae0e47fa8d999135f78c733cdcad786b96087a340f86e4cc2bdf019b07fd4a76f9b4b041eb397f61bda20c31d27838 -a7262ca18a7179924d28161d64e6b6cec5da35b7eaf695642dbc127a7bf4a52bffad82b8d3fcd010b308dd72eb567f26 -a23ecfac8a3f978f9ca8810458973f528846de6bb92fa6422b9547d55d29d7db7d8bdc5181e9ee2257a458466f714449 -b04c32403400f82677d831314956acd3cb507520ff14d856cf8ec4fab37a4428a5d24ecfabfd2c6086e4ea6d26b005e5 -9669b2725cd5965305c6ea48331e693086f4c1c4ca7dec26bc6290e9a8e70f9f0bedca6e36985c39ea35b412abc7f4b5 -a6f68cecace45317a758658463c5fc1f005283d8c3d3de9364e7dea453007d8d4bc849a21205d61ef81019e0d25858fa -8ee19ccc1c83b2c4d7c7b712bb370c129201bfb340c5b49d991207c995f870de2d0efaa88e05bc9eac567c4c36e20175 -8a530ece1992d1de92c4e845e71a1ab24e53a8a0679aa5bdeefc60fd890ca3cee2121f66c6f4b29c437440e7644e65d0 -924338d7f356da9b8477b3aeaad6f754a8d8f6a791d70c3ff23c2a6d4488efde9b9fc351319f3ea1f545dd11cd23ab76 -8eb76f86e057cfe9f655ba29bac89cc97db07f0487c86e7b41555b5549897bd3d042cd2ede35e312cbea357df622c6c2 -a2c0da965489d15ced574f5e27cd4781a1dce8fa4f17762a25fef1320096b9eddd92a007d58a194ef57def3aaf4e925b -a3fc89753e8896d796859c9e5a00d184be7d37c4d5741ae8a60cae9a7a30c5d840325d6479701e1f61e37065fce81870 -8b2f90cdb3add567b94f4c7fc89a8a57a0f06877639c33df2697f7c39e52c1869aadc98a2f8b85a58fbb02bb1bc1a441 -aeb2c22d9186725ea40d3a4bf551482bddeef42c0ad33801e35361d3695769429449c2a13955cccab55778d3ff29b664 -80bce007abd8ebe2238d465a312c2d125d1a695184b93108d728075595c7716786f9188e90ae37fea89009d087e71b07 -86f5df2b83383c737bb6db4e435f496ebfd56b51300612c402bea9ac2f439ee7e98cbc2655d31646472ef983aa6ccbbe -880e8a19af5ad76f14cdf94396b8dacf061e02eeaba02d4c29ddf0d07c6d2a737c987d69ea2eee52f0db5a4dec318932 -8b82368968f9b5bb175c95862ad403beee68d199a20d5dd618395daf11ff0c2e1fbf3a31c23d3e582556276b44e70b99 -94a062abbdc5ba740077fb9de722ad2ccf3f6ffc8b4a9dfbb0bf2ff789bd529e7b9d8da520d0342af91808fc00431638 -890b4ee1e9837a4c215616819dadbd3c6ed7586ad391498012a54d735c6df0b72c2dc3969d1b24cf6fe822f37f9c10e7 -a7dfcf43c9c22fd22f47db490e8f0b8f42597a5b4ae3e7bc4a9b12252b32f89412a2aed946eec19b133cee89b4a70322 -acbd9e85b9d9c3b068220f893d7b6368984f6cdb1cd06a784cc9571f0c632775ef890dbd51371e8701894cbf667d04f2 -a9b1f84f053ef6f41c59b1758836a82d53932cc4b8ee9c2cafe705150e1c717e3f5c15fc21a2532c071e9dd9bccb4dac -b2c63345748a28d04680e3e451d1f7d430bc8ff2031b6bd4237a1f55dfadaec20d1854ac158cd6a1466dae525c1b9b06 -a23e7b2e5b8f3e3b0e350e1a461708be9c1434d49fe2e51473e2e360bb0be140a96f8ddac99e3b804557cc25d3e44776 -a4c4729a38f5f32f155ca4d1994b61802ee418b276486e2dcd681fec13316f3b6d4a8e76eb9f48e2df0339543b11326c -93be67dbdec2655edfe40dcdcc0a7e761b7259a9d909ebb12fd7c9a5d4efa10de065d2eb049660ed01ede2f26388d43e -932480849f97e32fb14d4a69af4073c377e949af7293951b3ca371a306d9e2096157f51c8e5036a44eb73c7c842c5aa9 -8b5e79ddafd675ff88d8f65176321a08183429d42d7fc1e7cc3cfccdef0dc5824ee40f279a05edbf4d50418a4cab2126 -962bd6fcf7c7f2a9c569d584658a735bd16440de2ffae236c68ccbf2ddc5e13836efb163690062537d52f7d8bbb24222 -af80793655c0b3ec3029673c50a7f212d297f9f80d7d1c7cb1409d292f3bd7dbb8b24581017d9f3964e3432f46e79ca1 -94c8cf3c737c102e9e91216752c82b17e4e42074e08ce44e701c2f8ac7c08902b911cabf38c4c5bd41400eeb1fc97acb -8708ea7af8c86b2a1964edf64a9e9c56c7febffa742c3ff2e3088a61d3ccd63e135811212878ba7ad8a819e1859f4e95 -ab8e726d468417c168c892c10c7e2297e50c67e4283e5b48c3f3b014981ec482e211374f779faa0c1ead906f5dd4114d -a93911e672aa3d8dd686280cf062f128bd8eefc058fbaea52cc0a9bb255fda84e65ea546f662fc75fee4c5b24bdc61fd -8aae6d9289d8adf0f81e7990cc79cb704d0a975f03b9ec02be66089d62954fd9a8b005c5ba8179cede366d25ccf40869 -91e44ca55de8ad3ab42816504813cd9ed9c6d64abf6373e8891f909cb49c8a951ee823cd1f947058d542f0bf6290a11c -a377f97e075b66e740b8476f085d50ce8ac21f206802384e2e072f6b9700a5f9cf0e6f2236307775c0e0d6ae8459d864 -953c08d9f2a9d6ccb22cab906efda69ec1c228aa5c2ab93822b6f71c007fa3bced68c6a70ac605c6145e4af770b60de0 -86d8dcf5a9ba81cf6a3149b2fff96e36639767e9de461bbd3ccc870634e8db331b98a888d7e8d3d70b6ed241d8ce54da -88db73952866ec07c49b484c6b18de70d439e67d971c1b436684d489253cb96d793cc4d9a4362b51dffce837dbd03bf6 -970b7aa9070334b0649bea1f0b4e53fded64665f87e055e3527e0e567cb57a0e97d369aa16a005155cb69000073d7695 -928c8aaf72b3f51e38c866ab457f75cbd7131b676817a3c6d522fb8f876b01a9ab3a84238eaadaa0a095ccd6c1ac060b -9561e78d16061b5361ba0be11387c3f6029415f83bcc8477b8729e88c55f4bfe74b59c1b24bec0eebd9779cdfcfbc96c -aef133788d1e04ac64f573f3ffab473209dfdcaf2c675fddcff83724d17b91d6340830409b391a94405d6ade005cd01b -b8ad4ab0a1ad6383e4cb12d479cde732f202687ebf886184507371ac277446b3bd1648c49c89343920e5d57fa6b255c3 -a8d00257e331f342b79b3d25b74d300b070326b358f690edbaad5e325293d8b55078605a43ecd9dfd27206013db4c286 -aa71abee2720052cce7a5a0c3968e64c2c540cc852dfe08b742fefe005dbfd10397f66386744c9bfbbaa40779c2ae190 -80c6680857b88afd3ae8801677720100f0fdcb9e49c82f74b8ca5a27aef34e6df03462cf9ef5f80169c72da15be567b2 -8c2f2865e132869fca5232ba5e6844ac0540a53a66971ad54ff91f186e011e5412450df9099fbe0b987be443867dfdb6 -89cf681e0506baaa528043a15ab3bae09b8817853e889f0b3de138992e52612fa3e50d54b3686cbca6428a7644f58208 -89ddf69b72b9ddf7d535f742bd3c942000061a5a54987f2ccc7a09e035be978cb32f653df9568526c5857a5df4321f59 -9908a3288b9a9972c3f3f0d5923d9840756b74f31ae0b24ef2188465efaa5247b1ed13b774991bbe4c065c7e71b487ea -9454ea9a664390fb1ba79fbb5c0cc765d8ccd32a02d946a14353290fa2a1ba911605ff2e302c340e9ed6fbe8543ee6a9 -aa4f4d9ef843ca3ba334d73af634a0ee800b3393f8f7701cd152274f4296eb79d63869d452b5e83976eca246203d6f03 -8fce1e2e59dfc4fb46f3741d27772579fbf2f48acf1a38c49b0e5dae7d35f2624af3a46a48b89bd835b7d452ab0cec80 -810ec0e58504ed556e788e23067296a8e4b4ef31257d508f05e5245bfe6d2c2f658fca8c81538c6c9ea6ed05a8f249a9 -b6667bad0a7d49cd2dc60af85e373fdaac2af0d34fdee51a9fbc1fe8b77470c162a04da38228fe68b7d5247d43026734 -8982971d57bdf35e0f34e867fecbe0c140d94101484ef4ea01b796633beba184f980c3ced28b24ff42de1dc504dbc854 -86d8d1f3edef9e61058a58d966169a05f07fed0d93bd4f4a7cfca5a872b2aad0d1a78f8ec7784828e5813c8da577469c -b491624c3d5e517c9019258db6284d7533778e44b1a0060dec5f655a7b79057141079115f5cb1d8d97a90af33cd7563e -856e1cd4f9ab7cf323f5988bb5d272857d2fa90527f800362569a39defd93e37be2a60c11f498c482654f55560356f7c -a08884d0e642c479fc8e5a9837d1babbe63f3165c02a57b19d0547fa1fdc18ee382ea82a86cfd3135dec8f2aff793f53 -b1a4de5ea703fa5ac8a70ec515bc65203a9415f6da109b67fa32843a39d7fa6232c9c13920d78c0f16e99fa5f6a27e83 -931a2ee3220ac7888157c426d1b33b8a56f8879fecf1461af4cd6c85f94e193bd6ae6f8dc3946fc689e42bee213f0027 -a844a78e65ea6f75bb55a5db1e78b88896caa1d54b624f218eeb302397dc98a084a2ff4b964acd0650667160928ceea4 -b9c214280a15b423654a36b11646c928fb42ed2a692aedc01441c67522760df29c6ae7bbcb9237938a823188ad4d83f4 -a19575f9bbdfccf970bb3754818e49c709d1bf0af015541182fc7203f7aab51cad31544072d52c0234a3b649d03d9a52 -8cd1127b7485ea7f349e2c89a4b78fab3e5fabe5a95ff0cee10a3f4fd48940e431ca5e526f6342f7da93e32e8eaa1448 -9906abc725e445092dd7dd0aef90f989e3c78aee96f3c0a67ccb62fb2a51363c71d783490fa5fdda0ff9ea69f5b9233b -8996df92e014c226e5ac724075c19d19a9204b2e086ed5e75a9bfa1f8391c4c77fd5c0b85a29f28b302a4af29d38735e -90225c9490b39d151a80a9f4d9a7f2595961c44779a54d5e195ec95096f77e30157c6c629cb1c36d995f6c3ee129ad20 -85925b1dfe3884ae3a0e993b67b6c49685deeab6cf0d9997309961b7f727cd6133797bf04d21ef7b620d1d6392450b64 -88a6c518e577a820d83f87e9d5f236f43d262756b1bae0fde72af241fcc192417ca9724428d17a3f9dd813712a772cac -8f501fd5634fddd00a8411c0e9c6947bab0dded26339821bc3543a64c519d9575c3129f6619c6079d5e95237c11cfeac -af2b42945d7c81bc422a1bcdeb80027a1a243f89c65c173294d6c92e4cb3cd650740cac17408e7ba1a34d37d865b9bc5 -abfa5e76f1112602ddf152aceaa9f588beda3aba1115d0823d6a6b074d28389fd4c8178e8a845262200b9af024a33a88 -9732a0e3efcef5ad4d43811bcaffaa1418c791d3fd6ca4489d6cbbb7c44b55156d218f0fe86f2ec96ac306fefab2e694 -8837a6c4e60839ffb0b59e94b37d81bf1ea392d44cc81717c1c9104468d31fb5fc3c35b1efd9991b5e7e9819c66a7221 -b6545fd0b455748ac3482e0ead3b0157563cea7bf6bdd5ae2af7afe1ade921e5ba80466885ba73a89657a735c92658a2 -b72fc49fd3be541bc26cb968ba4eb3078ce7c71fe0ac06340f7ac25c0befb86af03c4cf8f31c857f9e5d946401e86bb0 -929f424548e29c3b47fbbd59ec00d17b00ee1c4f6b966c1fa7e0f8528d52078278f2852da976b8931fe813b0c3b71ac9 -b37861ba981001aa6192cff06c13f041410aa60f965ea03dd48068b4295d61d2fa276c3f477f985f50189e33308c1876 -a73c7cdffd646cffb255d2519d8e08dd8d9a9eca0610211177e259230b8f8c7ec8727015853197a0f11eec8b59d4f2bc -8da1260ce51220ad107c3127e871715bd738639cd90824d1c9f5b6181304f363b8bdbdb42c21e4e360cbdee496b573a9 -aac6bbc35bce8b54820ef8d7219a4092c49aa5d4fbb187968cb91ac04bc44fa119766f8c630a727ba184cad19278d9c8 -b964de0bd31847ada13dc3f6e1bdc679f421e262c03353e39f0ef1df720ba05e6d806dba15b6e10df559519ca125fc39 -a62e4336b61f85eaa415f57e21cebc7d54c68f6febab02de76bc04a69658ab1d2f7cf0104da79448e32e2b7c92b684c8 -897c6ca595bb2884b643ce8e69078431979d7e6e1b2dcc6effaf5a62fc906db6466f85020bf5930597adbd99e2ff90d3 -932956e0ba09f6499f1ed231732a444b0adf17080237d9345d06d4262fe8a5fb0f704c919513ed42473751069c57dafe -a24b9cb4ea9c2203a95b0056bb95342c4fa0d91bcc25595fea0161e7d6f45595f7ea171e0ac1bbde13a6d8ca6ad10bf5 -a7714728bc3318f6ac005e350de94f59495ef3972b328c673c5e608fa9059be3277b48f03a5a9634c3d03397af7d089f -b98732aec7a0a9a7998ba51e2b76e5232379482d0047f4876cd39918119776ae2683590f7fe5e44d12b3b3efdd916e8a -87700c3fe20cad8fa3041976c87ee761941d323f2d64a9818f20fcdf0259f796a11e55cdee31446bd19307cbe8becf09 -a37cd03fd348694b2ea5cf081696d12dc4ae108da8d48695bf74c921b90612d18c1aa71b1071bbcc02829e05ba1363ab -830e4e7ac24fb3f64294e5c64563ab5708ebf0e133540b35b985390d68c420a6d680d779fc87245bb1f5c58e59c5ff39 -b5922242a82565753dd2c1438008462d531f820af1b565756d4d27a30e3406ecc503b1e5b628012ea0329fd75561dd7b -91068438d2bfbb0666824d3cc2be488f2eaf3a8a9f21805838f9f2d582ca6bcb103b2f0f313b57bc86f87704aad7c7d1 -a9a2133fe55e99114e526904f5fb3e2e141f31963562887a9fe6a262496dc405c756bf6dfdd6acb8853ef5a0a5146037 -8e48e79f9eb1f8757b4c4afc4e3d6da4d368bb25b4d54e3a1f34f3af13d8037b0d465b29894f68272b79cc60fa676071 -9378b90495b0e6468dce3102a97e9965a5d21fa4a6494d401888b8777bd58616b99d49177f2eb2796476ae84d20b67b7 -b0aea247d7d7c7767519b87dd66f56c306d9eec88b0db8060bb97370099892957e2c950fa2e05f24f8ad097889cab087 -89d0d48769ad81699d5b83f26ac49a29c3e835caee03469e93c11e5f4b8470eb02b52290bb2c37f06afb0746630803fb -94de42d8554583b24317d9ea283dad5849e2f124f659d0afa11414898ffdc4347a9c4ebe783dded21679337b58b67f4d -b76c3047eaecaf4a4e6fb6176c7f4a1d393fec3a360f4c711d6293a993aee39d5aea654fc6429c2e4d4955b12fea5c8e -a307fcef0915e3e3a27b94ddb9561e5d210a091714b73afbc0b3fa5e8140e8c3818f4914903975e8f78d0492d7784c25 -95079c4a5008fb6ae0d653c00ad901a108df0b8c442a68492740eacd15048106b7c4cb5ee88bc6b1dc089987935bdba1 -b65a354aa8e92d6ca2e11f4ed3c1ed011852bab8f0e5b8157a10c26db2748be688512423c11d582b3dc1da57b9d6a826 -a32c2fc62c38eb19dea24b545d2537dfe596423f8ae530e562ba7eaac34139fb443d88f18f39d65d36a65ed1277973ef -81b83b37927e9a6a7c34cfe587dc9cfbd560db3ac57a8a88161fe4ae9a7c66843d32f6f568c927e2ff8f21d8b4299475 -8b6993ef73c2021842060ec0424464412242aeb711da2c43d3985f9d15e4d936eb7a1b5098bfe892fcd3b6ba8bf42369 -965535b46a18f94a1203fafa4dee5963742511ab77e98e471e03376847850357d543dc6ef2dbb765cbc1f03f66ebbc14 -a9386ef496b4f96bd591847baf6dcf8520f7cb5aaf1713025ee894b40b10f243aef06c553376663488377fb8b1b0a022 -a6bae4486fc16ec1f12817f2d47871c8bb61f5f1a2db5f828c6e2c06bca64b1ff7cf4c059a10d6bc2f561fc3a12aa38d -a2b6cda6a75fac16f324935cc1820bfdf013ae02c209802befecac0288d90263a7f84762dfb7c9aa1351415c03288714 -aac87216619a8c50b5d54432ed5681b1cbb2c7084f33e9a91889bfbb94fd18c8071b79ebdb403ad81fea495bc1e37dcc -8bb3b3a7ceca82e4268ab52c00322d5d0822427e43c1d8b88b2f43c3dfae7100f6a29832d16454e093579cbaa1074062 -a2363b4506b1464391a194412a73d47d0cd4ea1ffa541cf8b936c97a46bfeaebd1fec409c6aa2109d277bfae0ea7f0fb -b56911be2bbf1e564715191a526c2ae73bb6e85c45e3dc22bd9dd87cde620de93875c48b11e02ea66eebb68f533f353e -81609eacf4b2e78a9d7f469e0882ad24c86ad98dd18f466d321aa32a762171cfc334dcc049962ef5e63248ef48244229 -866b26d3dbab7837edec84217c85653c6abaa617e0ba2657d67757fd1c7dfc0c7f83f6198fb85a49b402108d6fedeea6 -9771f5796d5d47d22100c7ff7d191795677d53796f4a1e1aada949b372ec12decb6c49e28f2662e729d44f0e09eac063 -a9fdfbfbe114c7f93806b988c50f8ae4e13a4d433f2e40c72b81d0ed7fe879db5e89216a0b0c8392a6d9d54f57760ecc -965336222244229fac41336464c36dac8700d5289c0aba78016db76e436289a0797af8c96d52583618f8c6dbe7b3562d -99719ac482b72d54fa515395847e9a65b733da84f7d10a0be82f34afc20159d64411aacca15041726251fd90ae06a9f4 -ab96b7ac88842ad0ab61f7550b7b4697d6a3b651cfa3c10ad404e7505c742e2c1364bbfd08ad0039ca3b81ffa9d6a6e5 -ae96088cf12f76140888582f6f6404b6f2666c048950166e37bbe46c1398fec343fcacd3e8f332f7afa222ca13fbdb87 -b5b5c1ad493b2e72ce8ba698351f596cb85841f7f7055e31325cadbb4fec3e8045b335643190d6b97c3049d10551764c -85f066c7ffd2bfc4519f42f0778ce0e46195466768322a22673a073ebb66cd77c7b8b3a14157845cdb369d3f40911421 -99f4f10397cb7ff47a2d9d2f29021d1ca96f0da01f8afd76f72457cba6e6376f925fcee28ce77475b90c9466042ac414 -85116606b18f6e5404e9176570bf6d7a9d86116e5a29721a1b20d6b28a733886e2085a7563cbff45d1f11bf3d552ea12 -a17d81b236fb138ed820d335dde2640ac3a44cccb5f11fc6bea5fe3132c4a9247b874e75fba55bdf8093f0f56310a999 -8a16a5cfe10c5dbecb4fd9f4b0c370162071f88198e016111937199b87d006d1b24f3f412d853d7c6541e1c68076b70a -8cb83fd2b1afbad7c454430fb9dbf6530230b782c7dfb01443c2c16563e833c5b230f4c4268dc37a55a681a5f0bef420 -b8851a8dd6a3a17619e7c84b18f29ac9680b456c03e8c8489376e6de9a22ea75d1730787ca5d269af44eeae47f87bc24 -a8f990c9290456e849ae4cc0c320580fcfd50263af8945d01b00baddf801aa0a7bef2ac119d4d1b4be6290615c781656 -b0fa1c28c8c67ff87427691047c362aa35de0be9b0121d83b116b23170ad2b712a0b5bdf6a57a25c59201ba165d5f0d6 -afcd2f5e66a277cef775b636abb598ee9d7e3bc1b48b521da787dc561cea8d7ad963f593c3ac6f23a66a27c15876b775 -92888863568ef01b40d51f467e8364cb1b09808238644bbee5ed118b392475e90c6a1e03a0ef826dff5ada8d10be716c -a8ddad388f2dc94294371d0ebbce02016c463a65bcf3a5366419a7a910d3d24748fb5716ddd81cbab44a2362ee3c077e -8b8ef4f818ca3de1683064ea7e968edc8d9fe2675b8bb2ae637a5784a20cd909d18eed45140189eb9f080c53c06376fd -a52d9c49db4819cf6280c220a6cd306a5851b771de3032f28c7f8750c20e80cbfda57323a55a8c03085b41f4f236b5ba -b01fbfa0f80ef574a1d6733899002a8672cc309e1014fec8e81ea1e96a7be9c247a570f825b7862e814e1f006a8227ac -b07e163eb0f96a51d74aa8a7fab5d23e44e37b1b1027ae9c4155280d8d159f0cdeecd3258c098a7358c5bf2fcf1eb7e2 -80c4512a5bb5e8255488fed7b7e297988732473f0ccc1192cab716a88d035e23cc374a937fca7da87e18048ab026d9f7 -b3e343b13c1d4c98b7706edbf362eab12b1fa87510d5cf168e510844b24c8a9624f1e7e0babf455c6d425741c23e1ca6 -83e4b53953ef683c512756b3fea37756b3c562c88a15cddd902eeecf0de82d0345fb05feeba511e8a6de91aa1f722ef7 -922512dd5ce444df62fded2c53a73385570804e7305cde401116c06dff5ec7812b776b8cccdfdafe422f1ba53b2b56f5 -8d1f7feee880abfe9f09708ccf72f376013b2910886edcceb76018759b88b95cab9c0e8f176faf042729b405a10242f5 -abb7cd087d0cea2cdbb47cdf9be2c6a0c6ec113e1ad5fac083f66a027697d477ec69f46b9aff40c239ad9959b9854e11 -b10592443daa8708f8c882da795da07465efb9829305170bc3bdd781cb6651b503d3b21eca027486d413f1748f40f068 -b14dcb895ab22335373d2b736628c1ed0e815072fd3844867ae24638aec60f8591c6885869ad0bfe509fa3fa3101a5f0 -89631708996651bba6b2113626a2fe1ef0f2ea2f21857b2a1e5544ad31e8a53e755b6d611546ebbba4b2213acde65e72 -82e9436700fcc5b842ac2f0482de4248ec9d1f206db3dd36917c00c7749bda257fedaec513d8a9ef3765057bf5aff25e -b1c2b26d93658451fb4e9cfcd77209dbfea909b2212c000fcc576ef29b808061c9f58827682cfa09e357c1722c3215b1 -8be32f59768777a785d8b257f941215f37db8912183aef4a39a856b88cc680ae7124789c58cb3c6c6f06a951dc96a1ce -8cb60a3d0c9a1efb89f89f78e6f0e4bcf5eabeae6cb215e98cd7f9eb58699ed70dabed73a8b95daf32a5e4bf0d411d3f -8ec7156d6b672e631ebd88467f40caa9ba5411ab727602f3146b468bc00ae54fe44b3228572670215a0dbd59feb66e2d -97b7162101d740aedc894bd5f74b8cfa7ca7e7fe8363b05491c15e8cd54f21b0b09eb41f756b9089c379ea0ab189c468 -8524c9de6be47cb6808df761ed03c505932ba715e757dfb3c97b6deb462433d98953ee6cbc7a576b6837e68eb16d3188 -b024c8fc3fa4f602ab73448418548d9896200065a95e8a001f6c8d4cc3f53f18ec8b85524377fd93e2d2a18eb4c48b57 -b344dc93d3057465592460b7f35dc015f4f8025fbcb44a645dcc3dfb37044d5681d8abd81bd544272dc57cd50048f29a -a7b270b94d9870f8afec3bf2ed58afb76f4ea576a2175502630d0d3f92f9152c1ab0c019f175f566eed29713dd97712d -b86dd953c40d4f5574bc7489323d71e9798f7c6f2dff8d41f6295655c5a275179ffb4bb8d2408b88226c98583a7c26b1 -b73074289a5b08aa695de03ce2f5b106107c6cf2bee8061e3195056e799b0bd8b4172deff7f413ce8e477391ee6294cd -98b801a58ac7e083da541ba058c64b00ba709d4d0ba1683e5d83dfb80a29272fc2a33a18f32351b103b227abd5123da1 -a7cf232c6ec6b9dfb32d729b9d4216688f6d2b6e68053ddfb293ebd5774218c69133baaccec7ba3da9b221af619c2ed1 -8cc1d33ffedcea05f3c593e5b63dbfebdf26d05a5719cbf642997be929336b92457fd9df0d6be6c063918ada8fa2d322 -8d273497dd9f822984f1d8dffd471cc703d03c342f022b2bb24492209a3889f010c4f7ec124f9fb9f884a1a11f84a414 -b62cd013944d8d9d72fbe54897a94e804c93eb84a24beb0880cd98fd5d48fccf5dedf5076abcb1b857adcc986b729cb1 -a1bc703a67ee709f7776b2871f2a88d8574c9e2910690c9242c162ad926ef2263d5260f5c19015ddd5ee1c8ad1a444ae -87de434e8ab5b1d067188cb9c12ed936c26ddb0ee76c4c9cee9bd1ea916e411a354bfab2ce77ed8c8ab5d8c62038f933 -ab128e9de30bad31dc2eaad851da1e39741ea61bd203b48e5671e37f7b4e3db86687574d3cea1f561bbea84f68cd17c2 -b54576c9c4bc3b43270b83b89eb75cb7e89057c99e14021ca42237dce393dc6a8614c5af5c2f69160001b2ecbb407c9f -93adf38f161ea886f41e4af8e42c69c53a51074db9ecd7b7e4e36c858426237167aa49b79737625c9f9826dfd22f39ed -a6907c8dc4073d3d4d40df8302c1637c15f9197aad8511dc95c210f6a60b06f3aab2622b826d16596af27e42f2c9d5b2 -a8b0c4a3a5d3dd5b6a85802039f48fc80350f6f0be2e55bdf75e3197a22f6547ff4a7dce38ef3667006128141364625b -8a5f4c17c729509309b2ac7e0dbadfbf0baabbcfb1fab02f91d055238faa3b66aae850ac9b8d7b7245f0a26bc5253c99 -8bfc5d594700287da2a85a78630c616af8e555cbd7864ea604ba38eb75742fabf6aca12ed99a2439e2e046d8f048a29d -b0f91b7546613341cd95ea112e04b0963fbf7795f118c393fbdc37e37dc25244d10d987c13d6fa6eff3c4721fd0a328c -a70b6fdc66ce4c2e7f1d830b7765b7f0640ceb7306cc85778488964cbcc336ac378b74b9c4ec27358f27378380b3dec1 -87387cd6b643721aac8e1a8533c27602d9632168d3a3532059163dc5e4613838bb4f07803e6852b23c58f7103d134f92 -888722a5a56f5b6b00daba53991ab6fccc32a029a7f1748f779b57732285e56e09ecdb7d4848abb3dbf3e167cf8033c7 -b7f5b9ffa8ba66f54cac387c197058eb9025cb3761550c78429db95f9e1e3b49c208ce86b6126c162a62939e1080895a -a53f38c068233b584211157c66d9d2452c811bcd340d8cfafd32b070c326169306975e558745d63e1617f4b4528a2399 -b1c3e9b0f19993f973f038bc45be6a834b1cd3d56f112c857711c8e6c30303eeb0b205bd5dfe75e46b1f4d4bbb68fabb -a81fc28620e640ccb57dedd40c79b73b0c51565dc61097527b2341bbaa3e1c9ccf20f9d8da1c16704e881b24df0b7335 -910a7f4960a0ec2aae66cbe2ac98f43646b017de84ef3d486c19b7809aa16813400bc2dccfc80e09c63422a9d4d88f56 -a463868e3a8c2d2a7c49850be2740e01c7892c83063d381f405282b4c521cb6e3317361abaa92042c38bb68695c10bb9 -991957100ea0f66cd4ebd23d9f6bc7aa62220f6ecb71ac947cbffc6f36f7891173670977bc58a6f57b9a1e8766100c2c -961dcbd2e6cb94574a33fd48b5d87e0623411574666d5d37f4ff7dc587980e2644cf056e002746088c3c3b0ee7044510 -a27cdb374cdbff217370015d78c7f5c4674ec9948339475cc80a5805979a4c6a2614b6904f943374e96bb838549ea517 -a567bd4a59f9df9f5f30a70cd9f6cea7dc0e19b7fca37fef5846aeb1697dcf7925a4735367be0828f2ded5007f711f03 -823937a900e3b8705b657d40470357d91eeb339324f0fed58695ad72dda7c64f2a6b7bb7ae4a20cd1b2016cb9edbdd1a -b07f2248802ba7dce15b2698a60a4896323d37ecae6666a71cdf85878094bbd4e9c0e4733bd8bc6e9c850e57727e1d86 -adfcdea69c5608f02630db045e5679f9f0768fbfa9c8e97bc9cf9cafe1f747d3813e7bb1adc6085cd57102afd71db133 -908153d3eb2eb2b93c15aa606531b08981bcfc8b76684c2483bf869f335f9d8773a9aa3986ee54d9392856daaf82b684 -8fbb2acf533e7d6e96e9b68e77f7a1df2ea6c652cd8862b946c93c084436d7349ef4a0c453197a9769e986322e9174b5 -b83cf4ddee6140c9df0a08a39bfda79c0d55516fd799c1c24b59397b87a33ea5a0885b2998dadc354cb6f65a4bd946a5 -957a52cb24f19106d80d4115a8a0843d047d157c4a8535775593c1dba9be24318dd434bf43a82aa7755897f895d2ed15 -ad93dbc2c055f9d7e42717391cfae64962a78bddbb9fd102a05cea520654d4a9cb6634234d3a188693c87c5b4c78959e -8dc4b8e49de9b05c33d2a98973e223c01ed5745eeaada3a4c0e474cc22430644a53a60c3d6efb1212ca298c4331763f7 -948b0172df27db83e70fbfdc896ed82696876ac4c51842d270d9ce1e7f1fcc9487d781eab97f40074861401b809dd7a0 -ace190f75cc102a79412fceebc013bda8cf329798db4b4dba658e63228ca7f141bf0849d30139ffdededf98986f3066e -8f968dd6d7e06008a1374743b965a6204c11a610ad92705e8dbe6df3c58baf36b47c5d9988e4a417c80ffd5e7725da7f -b8ba0d5b36cc41f6839543d43166a08bf512f7b56040891ab80efefc774db28c833ecd444a703c75547fa1404fa1ec22 -a29944dd0e5c861eb37c744c429a0dce596cdb2e5b0b2d2438a259a0faaf3d261faee1434bd28ebb2e6adab59ff3951d -85c70422fde0ac6e7a0574512eff2a19df8049757bf78b5a7d7870848626850f17e8b0a5661e5292f3df0f613886306e -a5ff5c3ca2c70b88d15633f9c38d2e065bcfb0e447adca33301a0d4f05b761049c8f795444f11e39357fe6bc0d7f1880 -a2167cdb114d7707f1010e0be9cad488fe56cef65941c35a5878a100adbe522a8abdf7eab7bc689b8727fafb174032c2 -ad3f526ef9ed367b2a25c95453135510472581a758760d47eb9f9b57b04f8c061152e5a792584d6ca7124dfeb7e21703 -86443033ece13fd386485115765aa95673be72b0543fac2138e1488d22419591176423213ec06e5e4549a025eb6aafd8 -887e4ccd58603e6c9cc99bd2740bb1db2fc4127e8d3ec9cf41bcfa3589b0fe1931ed2a6140ae1199d323d2870882ef6b -b701f7d7637662ea7024d31e94245a5f745c7ca889f4f7a8362537df82b0164eae83da5a107a21c0ca889926aa50de49 -ab6bc11d6049cc5945011d3973eb2dbd5a3d786b3824bc125786e734887254a6ed61fdc2a97ea34e6b37b13cd97eb781 -9901a1f44122bf5aec7cea28e9405c33567eb118752edc60f3cf6c80642370f86557cbd76478d6b0ea33be92a22c746f -b9f453650996f14629642bef8fea66c90105c8523f3875d86694100f8022d4fff2915ac9f9b9efd6f425751b113d5623 -a5bf9385a1c94c09ec326c49b6b603f2de987b2878faf0263ed109410536543095c07320f762fb6fe56ee72a082daed6 -ab003c86dd62c801cb16b727fbd1037aeacbec0f76e8abda4c6d87066cf0a33dc1c61721f2134c3b78975efe013cddb7 -8dd8c580c288168f896fd7ffbcf5c8167a55d34f17b2c362d0ada0f33a08cc0568b37b01cf0cef1fd5e2c2e250fcdf7b -acfe675aca83a774d3f526ad461f0deeebfc73a15ab3d37b224f8740ac2d9df238373e6cd1f03ca78a9daa0a796c96f0 -a45cf3242600fb9733dd5e0dda1994e8d37fc483885a34a76cc16bd245f6d9c8d15bef360ef59d0a2c3cd59114280b87 -b64097145d97cdc8b7a84edd1da7e84f8aa44c3c2a4823e6e8485fc3a44d94cde7d7ce8bfb3da5d583386461ccb42afe -a10ec5859c274c0972ec39ac80e461c29995b35d03603dc97dc30ff826ef24c5e52d5dc9296319ffc672b9e1d57d7936 -9702ee805b70a1bfac7318e8470667ee20739e3db3030bbcb9a08568e96c9c8d2af2cbeb26837c43e04997457c623486 -acb3f5a663333d1b4d54dd76a23c6601fd4540e2b050ec2a7fbf0b850b6f592837155e6bee5ca942406643f98bb2ca83 -a577b96723f64d2671f1253fca72df86ef3247006c92cedcfb26eba4b4f4ba71bfffe1d5eb87b0192378d0303177fdba -8c397ac56cb723df015d0ef202fe486d1acb42f8129d3e4b37125a7ff9e81aefb1e19f477d528be1e6b18e7bced27ba3 -a7a6e6994324a80ee0a85e8e8cf818f5f8d16d299f21b2fca8a9f65231982584afe921e76723701abea873275ce0c15f -82c8ee7a39e49528efa60ce1cbcb3017904de6beaeb751c406b64a94aa73af72932e32b63c1d3fa22619498fc46de6bf -a1d0193ac8bdd44ffcd37092a5dcf6e775824e5dee4c0aea5bd46f2e25b312fe58e1e6b9dccf9dd14f240d7ced4fe071 -82c48967f22b8aa1dc63dbda0f66ff2f40f3ca9a7b3e752e1a950dd7daadf9afd81ae1fe3d0e440259dccbc1520d4e22 -a69d43e6f962b728d223f6d474a923dd13c04eb8858f7fdd2df2c25dd4d13a0a69e71132f450613e8e2d9a65938f31f5 -a613b731fe0d23ebf376cb1f3707ab9b2d428d1ea3a95faca9988a1ff4fcbde0a077b38b5942590e594307acf88c9db8 -a7d2f249ec666f59dc51f9c31db6168f33a94b17ab95123d4b19aa00dbe9e1cdf340dc6f64bffc6dabb11912e10edbba -8e64b8f99ada5f317c6e2fd64ac17c4d6e5314c82848efe1eb97a5a52e6bf08923360dcb44c05d3fa59a82119610a898 -865d9512ec4a18ab31e4062b2ea6c43ef32c7c58d89bb0afdad9fe57dadaddd2150f78a0e85086454812855bf09f31ef -b2d23f01a0d182abcd6862ab6f4bf924ccaac399ec143fe2614908dddec102e2feb8555479bfb71ec3476cbdd71b1137 -b50d176e628e06258b518be78c6dcbc3c9b2b4a1ed4ba10ee822b3ebfeaedc4fa69c61c1985e1bb20ea9f3d6df7a27e5 -8174953f4023e31e39f1cc3bad674bf2f1605ec9fc053948bb60dbf2cabade885376f8c76f45b638c95fdb14f5bc562c -92b95a12d1fb1ec489943b3a2a1c8e3c8c6a30d0767125b87fb491f9d4f8de0629afa39fb5c8a84078b08bcc26e88c4c -93f4b80d76689d5936aff6cf195d579ff5328ccd0f04db42522a225f96b0bde2088706356675f185186548006940898e -a5f7f4577943741def19df611c2ad3d459c386a5e3c765eaa5a0cb6c192873675cccbe62845418dbe47d7a9822e4038b -b59bdb196d59928326572807b2ff2edfc93a28632542b270ed462567d32bc36cefc40300619aafe4cd1e91c38d6c9c30 -90df4b921e13ca1e63e8a5c9968ff64bbcc5b829e3421d74bf7f678aa1dccc1db9ed9dfe5aff05539bcc5379dd59e575 -837b0b6813249c456631b2f2fea9402a2303a454a114149bc35efb400813397366eabeb4477f2cfe037f722d78a5849a -ab5b33ae561312d9791bcafc8faf6d65f2c4260f126f11ab5c20c7626d88f2c00177588ec62ca763a7ca44c6ed60eb0f -b0ed2e48cf650a4267c3da1378b8164cf6b774200a5898155716f85f7abda093a60b802ce549811644e5f075d2b26067 -8d47a4e27f448773fa2d592f052bbdbdf30cbef152db6d8cbeb3d7b1a0dc0f2c820ed7572eacddcb51c19a8268426b33 -a56ccd0961bf238ccd197e5bbf430d7c637ff6e01590febab3529776403682ee32d0a776c3dbc6581f60002dac86c38a -9163bbdbf468be88a391698ab1f40a919517beb6c780062d4bab3bf8fd42eed6546a8c743e249fd61c3c347ea60ee185 -8d59f46606f063e68198457917004ae50ebb99cccb07755825782ddb25b96c3cf8973a6c5092c9db71a4b8ed075876af -8ebffeae4fef7a83d81f31a88589e05f885dd0c0b4360545b22a18369a3e6762f187ea6a173f25419e70031861936463 -96013c6b47119e017c8bf473b3d643d0bea1cc12d84d412c2b9f6f55f22543a6e15ff7e818e9799af43984ca2ec3bfb3 -af46ef7696d9908fb343a6754de37e31cbb41dc1a4ab8203d2a2483d1cb0dd3183e5015d8048ff146ec34a6c3f2eae21 -ae047ec4584a962a7ae9359292c98f4d8e0916dd98a414e2e15429ff30ffadb3e0296282f0f7e257495e8ec4bc0e5328 -a16de787896a056d31e3f174418aa3882c03c879a292246a43dafb81f8e0e05564f1cd3ecfa251cdb159f63777fc6346 -97d1c4a94182ada88aa3cac95520711802cd3889e3e057e99a72a69589fd222b241d35a54b04f42503756ec3c1a3d701 -86be4ebe8b92f5bfceba757e1e2eb649f9803c8cb10130b88b13caab6bc04dac4e26d538b7adef68413b047ab9031252 -95d4c0b08caa283ffa9e307f78db15470fca5b577189a33bcdf14c36d4ae3f571d004c5aa1e69172a4068e72b7dc25d3 -965b7053a1d14f9091de5df8bf033a07b9f8d39a6d66979ab5424bbfa32b803075afc2d74e71235a0f881bacb6704689 -a93e72836e2efc704f87065dac0463ddd4b063eab125d834df583d8833873f575a0179781b72aeb2a35533a34a395481 -a2997d7c377060d910654550316ea7374a0329fcf30e743d613e2ebaa15b1bc6c936c2529f5466ef0e60ff53aa2b709f -af5259d4d08617d9be068d1b79a8209497972910938831a435487395512187691d0cb021bd57eff0f694f32efc1487ab -a78b8318838b1049f308200782c4409fc6c97ca5bb6af28996eb191027c8935b7a43a41961ec046e6c8539376c1aa293 -a4a6a9ec652d1c95883d21d3767b13a7e1dee73be907dacad197cfee025755db3cc7a8fb9f40146912f8a3f4c2c49c14 -a8a8ab62334a3c67793fa0691a0d2e80ac1681ce64a02df93b78e4a2f6fbf3af9b160d9ca6b4e835d58ed60d8ce627d1 -980c32e492464a6f36ce12ed06541e3b2eb098934c0ebccdcc984cdbfee4a506d15afe1a30a84d642322c2987d9d51a6 -8ea8c1adfd73747db98705e9fe1aec441484d2e4862b84817cdf1262fcce91f56cd26073d4dd23b04f836e0962428593 -b0f20edb8552d2b08613cb574e9de1c4dce1eae55ba9ab05dd7f2ca3590a7496d63d55af88b3dff881e16d8bf9147037 -915af4e9a28b12ea126668db7de6ff0c2cc9935b138022fadbb1f385f327fdc927388c945b93d252cb51803c242f7e1f -a553e08f67c61ecc5c8955f7251cfe18cde02e6170845e70db1761bc00f42a31cc10de26d4c904200166311f32a3e56a -99f4b066a805512e16addb0bcb08d76f017213ca6aa6afb5c2fc621805c4e123bbe0aa85eb5a0f89d3112635905093e0 -9236c5b0f4d2e58033735d7bd5d53ccbe82c05aa290149286a16a318043ffedfdca9d2d07817601d4216fed50c1082f0 -90a4c7898c58c9af83f94095f6afd5ca65664f16c0af4c8121407cf0864fdeb09958500b2bd0b78950aa9051e3480928 -a589666688e6e7f8e4d99b84d21a1f9ebfe681fad346a237de20a11a2b210eb99c4d3e2f645b23a85c93bcccd51f63f8 -a010849ed4df0e3a8eb61f7fd114d05a8669bfa36cb95d089bb1964ea8f5fa26be0cd10fcd9b38b259722c5a14ba3a1f -b21f974a10a2dfe9987370ef4b6af294cbe8f4bbe35ce9400d0538c5f71287498054d73606e26f93e2f19584aa18e285 -81fea77bad05c3bfa8d5d8409b189fd5c759613cd69ddb19b2d46673d4df944b2c7293989f79580d229d20959c74b18f -ac962b0819a03d2a2fa42c492f54c3d293c6d5ead403c50f7a1ccc2faad58beeb0dfe888a928e505fea9e09807e13a23 -b78b913f2ad9622d20c175ed23f80f235b5336343b0353f82383fa6aab99aef77cb489df822bb168e56496c1854f623d -8c06abf72913ffcb6b59bb8201c00034b447011880733aa6b563acc423e90bdae19f2a7a286943b55488fc863d09269c -b34168972fcd90c78286bfc6078ce559e3c216d8d1885ecd5044bf9f23a4ad15bfc9830aabb4273472c43e2980048586 -88350e0ffe9b5576dd0afabc6d8445d25b2b9a0945c71e6b9a5587649ac5d95cbd722db5ea1e65d3fb8230c794fda5fc -a3bec1fc362a33f38795158f1b869e9ee857a7f2e1acb92c6a7dcfffa64443a5b7f6dffb656452e7f855051ae849be3e -a21f64c49334720883e1243a27575648f53637a644c308ff24f5c26bfe65cc690a5e46b8e432171f31c4229aff4db416 -85dcd8ebef8f7f44372912b4a3a0dfe66a56f16c3757a8ec01b71aa81eeda9f8e5082f92e3ae8cbf3c1eddf5e6ffed03 -af3c1a770f34f2acc504f38ffa7a18cc4b38f8f84f310cdf2d7346b18824ebc7c7663cc0e00b44cfb5494fe6081aff84 -a5dc7c5989fb5cea87c2d878d8436d858458171b667ab5200dc2cafd8af2d9c2bfe2515b0c002cdc9c3e61e4cfe4b444 -b136dcd4577ef3a3a8bc946cf2ec79d3fab301114ee2a692a6c219e252c9128db63fedebc6bd6695a8ae58e7d28501e8 -91d3a1ba625632d59dc963ed54c0310d0447df3e1d9151299722d10f8b26161bb73e0020d408b748fa6fd1db51adabd3 -b89f1a2497b04b3f1b018dc88b52133e1d7470f97f846965fbc934d34dbc8d38f2d8b07d218e62c609de33b61831cc9c -92fec43fc5af23fda5dfab78234f5ea7813d8de34f8ec269c5fa35dd916b9143ff0033d35e7a284c0ef4f41047e98fe4 -8a0b89cd35ecf5b6db26c39705b416a4b950aafaf3b00a9d75f864955e9074aac03826ff9393456871107563eacc024a -b04db63ebce71161fd42bb878e89155bc9e887329e164481077c6a1db092477370a362810d291444f5463437e0ec5906 -88ecd5275592f8b133928770e2273a0e0c23424d72b9e505130b0599ba28d1c11eceb2318a49dee054a8ba0971874357 -8eb0271197fb9f1eeedaadd8eb603b8753ada11abf04ce90950034f51f756ed6ec6a6182a47e1f3ae51e3a1f3ecdf467 -81cc996bc6b12ac56a1ae3add4483ae4f2e2284e9d304f5fa1723231d0e5b196813b6dbbc20b70f5d51fcbb65bf284bd -8e1d94ecca2928c4c68fbc13199b6281f8782c75c119b763e0eb122f81c35f8fd079d1bd76b498393371a08dac95dd1d -a92f98bc09f8a91fd165bb8d05e3b5ec50121d760b353d7e4ea23c0e04ff29614ad9028a4a16bdfe323f2af647e515ce -82e8dc99a14da065200699e458150dc6d49ec0e098bbd91ab8f1fc1767e8732f53855499c8f24da7b9dd681100633be0 -a67b6cb4eeab4fe5f4ebdf5649b7d61bf5fbf7b6cd2d357fdf348ba32dbfa9d6830b1265ea76a1c666b266e30d119182 -a64e3af1d0e600bde18d7f53a4e8d89d296eab4bcd9cc3a9f476c5b8425e6e8082066948fbf40689f626e27e4830edfd -8f66b59782cbccdb31cb1bb2d6385307633ba4db31c375c0a8424a497b2fdf309e7ec1c95490324b9a909bb43041998d -b93f4817eb1d91ac78eb650c110f7c29df40df47ed1d5d3209c3abe5cf59a5e7aee3d1cd232bcce77e157b1a9daa2557 -864b6cd72029640fc041fd3efa71bb210edb40589a26981724b944192c3c2543352b4b757836a7b0b13bf830f22b8374 -9064a0ac94f2f133e287b796363f6d27e9646a8b531cd9ac0eb45b99fa73f327238161a43f7c4fc914036d69abd1473f -a40e60d4aaf9f50f7bfebd0e714fcfeba64e0f7ccaa0f4829144a7efeaf15a7cda2d62d771a76f98a45cda9196b0522b -93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8 -99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d -88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659 -a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3 -af565445d2ad54c83a75c40e8895f5ad7219a8c728bce9d58d7a83716e095432993ebbd3f6911c66415a6f920d1a4d171478509b54a114308a020b33bf4487a7a8d0aa76ae4676a9b54e765a680f562d3a4fcb2e92c58b14b49b5b2917cc258f -8aa99cfaf514cef4801599cadd780d222194ca1ad69a34779c2bcfda93e5dbeb931e13914421b5809a6c81f12cf7038b04a35257cc9e94c33761e68565b1274aa6a6f9d66477229747a66b308b138f92aa4326a3bf23df65a1fe33b3b289bfe1 -99ba36d8b4f56bde026099278548b1afc0a987cbd7c9baa51fc8e6cbb8237a17636f1a44a385cec69b05a5802059956a11fe793cabb939c38800f9c239ca2518e898ade1ec2513c9ee492071a35aabd78182392a09123d28dbc233313c9120c4 -a7dc40c36afccb30a2eaff250860b28b227c195cf05674704c567d77d6655c446ae835f8fc8667e71147ab02afcb2dad0babe60cbfa37d7c2cddc68d2dec54f28a4142f8353590a3902d5ddaa22066ab563dd1435dda83f276387b9767d69120 -939e6cc97a8b88572852a5b7f25e4838556307f60aeafb5d2b6961edbcafd4b48cb6ac980ffbacf4be963f324ba81e3d12de4f1459d8c746d0762c66ae1b166027f7fbe641d9c48f3c7d97b06d956b0be51dcc9aab65f3e99e1388e63bdd79f9 -b391e156541dfd4003d1697cdb7ec815b309807320574906b2e652ef0175828b356d215cd374b1b34d9f470b3fa0e643113e67b2273268f922f04f072cfb89008358185b25cd631f82911a3f20f90f75758ffb99bebb8076458ae1e9d1ae898c -b9ac9c84934cc2a85c876eff65577e1dfce1935cd6392c877dd881a7d2f5c3e9344f28c04f90c62a6db4237ca00f9e0d00cb5f63e3f060fc7303916e19273b6fe455f331cabbe2fe5a22d584484f0d4176120fec9819fbb0a01e6d38695acfcd -88209eb030c5d78734bf2c2a5c539653fd3c24b4c08e624f9ddc4a6550efbdc1054a56eb0c807595aad6de56fda326aa196d032a8b4b48d40140a2d77df3c7243eda6507936389a321a5811eb38e32ee433c788deeae1eb928b00940e2944bcc -a8632ddc9cf7cbc1e8b74a05b7d4a89618c64afe30367ca0c9550ae7d320bf4e51c5a69e1501a1d8bee4240d13d7835501aa39fdc401a74f4d5734e268a7ce29a1fcfdb0a8bc64e0dd4a9e8578d6985bc2bc6a3764ce7a3703f6fb2e52557a2b -a037ac67e8bb6f4193ac967e05d080a489f58ef8d3d30a89798246f3e4936121ee445b03e410a09e8ebc0db2e2477d110aad0ade99b0887f1eb016e750f42135866907f150bd6f4f99a8cb94281474166874808ebe03b118c5daab16dafdc38b -a50d9143116bffa3b237da8e1805327e81e9cd25e658289bd727d5f9e0020172cc8690dcfe31a240e5cbc48353b88c4908baa1dd7320165556e0aa633f62fcbe7870222d345a3bbcdb7ab6c07f0fd86be559964afabf56f0a8cbc0b4b91d477e -afa988ea6fa4f40c5ad07d2d580d29025ddf56d6ef1171a8b8de3464203f70b97d6f5ace72747345204b35150e06154d1477516a989ce8eea7871cc0d0de00a077c0fb23ad4837e409d0b885bf3f2dde11a30fa6273d662e68e09f461e52932f -97fa1a943ed8b81574304a3d03f4f15907f6e6e0cd36a66bd2ad2c75afafc70a61d3ff69b77ebe4dae9ca0fcedef80081062705e60bbb6ea0f1f398c84d2f8e4a3ac142ac66426c21ad5e9994ebbcc406af474c4aec5e32fadcb21875af7c9f1 -b30a564614493886f14a5dd71c89457504f8c59a7ac01b665ed167e9a8f9ee5832198fd319ecd234196ee57031bdf3840bd5a923e203a1938bc795c704b5285389750e1fd10d7050061ba19db00a60a2c0384a7d661d7d48ebe6962272230859 -84c8dea942cfae71cb02e705ec496d967425793ce8812e7ee53c2f23713abeaff566a658cd1c73dfd18187d16253a6ee0a623e82cd18e31cd1a1875d19c078835dc9292e141686150a88065226ada264740143e87c03a0f6c4da8c187438ebf4 -8c3abae8aed60338f8c4ff80aab22f8a2ae56756a93566c906f490a97151d34a1c3318054e1c494c60cc53327ad86a2d02c6c76a406726ce4f88635bc32eff0db0b61762dc518b95fa8da82e87e4bf3de54f1d72180ef53ed7bc5413e6a9a510 -a328230c92a6b1cef6a444bcb64edb992f71e3d7b93f0b6b8b408ba7c908db746d92ddb2c7588bab438ef3bc61be1c2f0dfc86ba2ff514b42b35c80f89b2e780f813ea1dfb977fbded2cd9b553b747fa952e227ebd8f071163d421fc337f04c9 -b482cab423cd5f1c5df036070aade7aa016283d69619d664025c3feab866a0a5691d344b2ee2bedc5dedd1f9a73eae16003a3827c9e5bbe22ded32d848fba840ffad1141ad158f5c40bc8ae0d03781b9705d851a7f1391b096c576c0f4f2a6b0 -919ee1df27fabcb21237a1b7b98f53d41d849e1b6a8f9e28c3fae2841c6b5a250e4041c737e6725476e5cd715e34d3880f58d80f61efaabc261bdc703e8750f48a923e9bf8980931b9fd9e40014c66c54b3e7c98241d76d1aa47af43313a65a1 -ac94830145dbe9a8f7e6e0fc1f5fb454502d22abcafdc2dd96c6933c604461fa83b2b37385f4bc454875a02a6d4157841250956783515d11c7456e7f11b745f12856d89f5feedaf6a61a483a6c33a21cd2ba0c18eb41a1a2e7fc33bb53e4c570 -b209c699f1233735c5bb4bce848e4365fd76651ae2184d2279a90df0c2f69ffa2a24d84a9b9f274021072953c0d65e1a0202d490d6c37186af240114e445d87bff754b4824937e4f2c90a574061b1c4910fed88d90f698025a2a264e656cb8a4 -93320dc0576b0d069de63c40e5582b4486d9adf5e69e77e3ebaf3da26976fe42147a65051501bc8383f99e7ba75479c70a6726c2cd08bf98c7481f1f819712292d833a879f21a1221a9610bc748fb5e911055122fdb4055cdc84e8bfe0f4df9b -a4380b240e998cdf668591f71a0c88ed143b0185a920787627ce65095f8223dc606fa5bce93377af100de92d663e675c0736d7f1973603a84a5c4162fb5e01c88c7493503ae1d7e9fbe8ece9b418397d68c21eeb88dae226e09875d372c646dd -aab48517d69135a16b36b685adfe9b2544a709135a21ba3e75981a2cba4ec81d1fe28ac0f72fde0c0001c15300ed6a810f58d3117bdd58d0149751d6508cf8a1a1ff7b63dd02d2730a9d6fe96c77c502fe8ed46d50a181ec4bb35e37dfbd6af4 -8277265fe75ab89ce4ec65b33fb4084bec0a56d81faf2f7a9070d2ca3065678e03a790350eba56323a54e0285bc32fe8007d5259740fde226e16cbde8354eacd562294eb9b7f727ed72ffbdad86f467cf057c737b34b80a41deb92634ed866f5 -aa40a24cb2ebe606d969392c03020070f044c95088d80f57f771b837c048342d2cd3474600d7660441090ffb8d2ffb7f0eddd67eb378e3e1477a6ba0bc38096d5d2d3355bc8b60f605f57f0c1899da591457440352381d2b38c0aa9acc7fe419 -80815d10685808cb630820629bcd2fa9041c9b74433630c0b9c1b7f7e8edf1440b520217f76ec9a50c125cf4438aa66006a1928a9ed2321da7ea325c3d56b65462b72118ca2c99a0ea733aa11da9abbeda6cc71ffeed301ae70213a29e697dcd -ac235d079f91b00b1fead7523da8f73a5409fa8970907af0c5d5e4c6a0996dccfcdb0d822d08c7fbc0c24799457d011d04312d20831825f23cf988141056a6814c8a1cac9efe37bdcbfa272aed24cd92810fea7c49b0d07683a5c53643872179 -b8aa59534d75fa5ac1c2c3f963bf73899aff5210059dbde8a8635561c6249e5143affee3bd2fd57575213b52d9a73d5702525867a7dcbb1d0a49b98c2925556fc5463ff0209742046a24ab29e74257d6419401093cc4371944d811cc300b6a67 -80bbfc5b816eea29a6d84e2217dee4d547306994d39e5592515e1b0807b67fe960d1d5addb0ff1a20c158bdb294c04bf093d28996121845a2c9268e2c9ac0f4067e889c6aaca62f8535d35b45036954bd069e3afa84f04721538c26003304c20 -a535c17d0e151d0e03d42dd58ba8c715bee3fabca2890e0e016071d34184b6b34e770d2be29c8ec76b69bcc471d50f4d043c2c240e9b93a81cff7ee2724e02018dfd9b534e40be641fdb4884abcd83b76f517557ffba508f1ba2f56313f4de94 -b237eb7465df0d325a3aa58269be2627e4978f9863f4f100ed4c303cb1f6549e606f2e3c9180824d8049191965c8dacd0a0c76cc56cb22cf1bcfdb39372c8aa29b4f7b34582b1719e6bd59c930d87d5ccd838743b585d6e229d5ed42337315c0 -805c335a2a9d2de30809cf30808ef836d88e9453c510716f01696f14c72dd60505eca8f128970edc8e63a9aa1f8792ac0dd50dcc84fbf4cc8b32349c682a6a27bc7551c7aa273a94c1606d07710188d93579afe3be1781bded15a34ed6047922 -b25dadf385ddd3c39bcb0a014d3d4f66127946b1aceae8809e3a03d66cc25e27142ca108316391f857fe82fdea4db2520cc73793b695eafbf3ade00ef7ec747b0457e49303f5e1a370f5263b436566fe24a0876e5fe088238c7be37a0718d65f -b0f753081cabe2c8fce73aba82ff67dbc9842598b3e7fa3ce2a1f534536f8ac63c532fe66552ac6b7adb28c73ed4c8a4184849be7c1756a4681ce29ebf5e1c3aa806b667ee6bd68f6397aba3215dc1caec6742f21d681e32cd1160d6a3b1d7ee -b798771eeb3d7a17c62ba5916cc034bba870da6b1ac14c2e1cae71af3ad4e0c0d1ff983f691e0e55289d5a33b131f2ec12430c9566dd71f4d8be9c79155357a5c30c5efcfd75bbe1bb6d5ada4d50604ea49ed838d3641f268ca6e25c9c4b6b72 -b52554c017388b099804abbe565346591a086d9979e10140ddaccc0a3680e506db775d7cbeafde67563adf0f09f5c2420caf19629f4e8f03e6fe02e9416ecd5269989e482b90004a083967d1141387eb74865bac6bd17e7a6d5f58225e52d4b7 -b520ff694520919023d44d53f98a7de2f78ff37b2d9193dcaa35556a6a0febf767781a4c961dce7c804bfdf81935f8f0082865253da52e79dfa1c5ff74d61495b2da76e167d46114709e877a7791a3a95e33a42f56b83f5f5afe271c67ae997c -b721401983440797a03d5b99f2088a0b249aa911969c34dd6c615b0060325da555d2ad99d931170c0868b0488a2234a4114cc0013d5163b833f5c45c5eb536421c016cf85788390176bb2dc4c196d6be26bbbfceae048b82f0d8039222e71c94 -acd9d833ba0a8cbd8d1ba939a11ea0fa5607e1bc6e693ec318bdb097aedd042d76e695dcebebd142e2e4ac30b1905dff03ec36d9cc70577e4dbe5e9ed7c20c7afb13a7f0155f203c6b83b9f1ad3d20a0d4aef0fbbbcf466ffc1bcd482bc2f5e0 -8cc1795de015f2b0e72116f169f3b4624b7738ceebea354e0bd9051c27b86f647ea36cad57ea6884c1a8adf9b45cd83514fa687e68878bbd613d793aa10986d5a0411f081689229e0d72133b3667b9f3f1a02211d0e680564eb1ea43393e1f36 -aa9281c61113c343a108de1036570feefc72fb7a96ff11f73024de12b83f29631f5a8a5900e6f10b15227c6f7462881511271bf785ebdf95ce288100e5dab391f664f6ff76c72b65b34479a4f43e5e8eba292209d6654157286ad3242ac342db -aaf16866275082e59d415db317aa874267d048ee405a553e852e6d175711d31a1fee99912345915bce121f43bc3e00d81338e5fcd3c8a1012fb4f172a9fe15622dd368b4d9d5cb60d189f423b071791fe26cea7676aca8df07965cacf80b0cd0 -accc80b3d8a6ffa648487a3d3c0ce1aeeb5401edf3cf2e385ea4a6d5fc110054fcce38f01f1da7141bbed30eb7a0a6810c82212bbb9da75d6033082dbcf6bc6a5791f85aa0f045a10da5de015edbf369b4d23b32b0c058962d2ee88e6911f994 -83f1089395a16077738cc7c9a6d6a3dc9033aac4abc508af5a1f007ca92e1a80b2e6f2dbda7fdcf0d5646de790a6201d0a9cfbcb6620a1426600e3a6a425ec004384f49fb9dcd166691a47177d45dcbcb761a11d46220b0aa09fc946131f7aa5 -9246bb586d43cb817c2e15ed609156e9f1cd284ba2f4797bbfa51c0341e1ba382eaac059aa9f63fb88d228a1a932839a171e7c7d00199dc7c4d6c5ea038a02cbc3cc5297c70401520e70ebbcffacd6a703f62896f3c788f94dde3c33ab0ecbdb -a316cb7c74feb0563c56cc79015e2774fbeca458bf8e9fb07894f9d6bcd73f7fb9428e87c816e5629e4bf7f3ec567fbc091549471b75492dde08217cb334b716b4582b24384586e53388873a78a90ec01bd7c3bace9cfc52161467df16e27c33 -ade18c74bbe60d1d69f4a570f8e5fd8696c26cc9e02829040b6b14cb9c49a4b3263b5bd5e16ec0b29010b4be054c16ab09304e23442af7d7f5fcc60bc6c5634ab6e4aed7ef334b2785e4c7672d59a687278e42d310342db5e5975d716e6d1595 -b7728800bb2039acf228fa3d8028569c426cb85d28b2b5820bbef938d5ca8c4df981d3e01a309e26ca101e8295d0f6990c03b8c239798323575874a4ee5bfe46cfe99b9657189142aacd8f8d1f26cf4c0e73c6397c31ba8f18102b9ea315b638 -8fb14f2a9be193f54977ecd3021663108ea143627b9a9d9faff85d1a86b855f6c437eab435fad3304f245bd7732af07f1173494cdb802fb96e85d2db89e1643206e183f3b228ca8d3f586e71aa9308eaf0223100bf07942fc39e465016d1f775 -ac1e025e53d98fdb3380489dce82d9d4bd3a6c98f0a523b841cb09a6f26ddd4d22efd98776e78d10fd996995fd00e81e08d3c25dd14a54b25a9d483677a24bbb8d1cb41a443b2c71038e6893b1b30f70758424e0f2039a48060191389033ef55 -a4c017311b9e930868132527a9849072b91db04fd36c619ae39c98da9e2174e6201d3c2ff1246c06b1b6815bbf3ea4a1116564f55ee2fe4c4d655e2294c0ded842cba209c255ca3d7b7f82d162f97890dfdeed087aa2f87cbfc61d61815da39d -89516315a3956b455843c2555248bd94dcb19993060fe75fdd51f7aa9c9147ab13997d8a98036a8f04bee5c91d78d2990907e35a52537a8ab3ed15f1a71afdcd38044a5b6e93f662b9d36c16933a881927cacae668c4c06ee6f004c9e3989bad -a1e78a011e210400c68ca76045f7da74119bff3cbe382efd2bd2ac76567c52d68d75536a91999d084043e1ce2d07d02e0b69fb99924101d2543521747536fbc51b0454aa9a4cbbec101121f597863a5c0fee2ca5eab35dff9b9085bef8b2b0d0 -830fd8d083e39153ecab43cabb22e29d7b44a55fba467af4ddd3f069439d2972ef53c3518de788f96b3f4f64963987d0155ba27afc28643af3de8e476ff515a68285728167408f45d99e574680bda6bacdd4322e587e4aa99386e035c0e931ad -b89584da22237e3061d991b1a55a5e55dc637b8b671130d304587729348138ef87885180310efe9f9f6d3580b9d7fdcf0649e8a79d2dec8c25a9f53df0fac5d517db999029cbfdd7c2cbd3e9a5503e5d267d3d8ad752335915c92b850b14bafb -959b8030733799882c5e3735479924b013756e57b893f9792bab4043e2d362d77cf308166d782e3989caa771b8a0c0a01302cb7b5e8ca12e2d6cebd59d4cd173c9dc25f438bac597fab17b4ff44997a489c168e7204b7d7c21d0938f0a2e3b51 -a0a9e5503d9afe0027891dab890c687fd5f5fac5741418490c64d7c15f59533dd603a50163c79402afa61bd02de486761983c94501da17e6bbe78c497f2122210071602f578adc0ebe7a4679f87fe77e09c8c122de69105f13455fea25f08e6f -9811487283ad620cd7c9b303ae2f348d0e6f5ee17b504baaa817ae207adb912a00d3cc36dbf48745eb899e6b6e22f09f0f9ba29d949ecd7350fbbfe87a8c7cdd5d0e687fc807751d07634aaf7c38baf3b24a0670c38fa6ccd7431436fc95525f -8a13aa5071c526e560def7d8583393942f07d88c9d8d26c98738fd65f57af2e3326dbb1edff0f39fe98eda4a13ed4fd71844254b954690154c4804e1c4a53df9dc4643f4b7b09d0860070f6b2318d0d63d28fb56bf5b6ff456a18dfc72fdfbbe -b9c90ff6bff5dd97d90aee27ea1c61c1afe64b054c258b097709561fe00710e9e616773fc4bdedcbf91fbd1a6cf139bf14d20db07297418694c12c6c9b801638eeb537cb3741584a686d69532e3b6c12d8a376837f712032421987f1e770c258 \ No newline at end of file diff --git a/evm/src/test/resources/org/hyperledger/besu/evm/precompile/verifyAggregateKzgProof.json b/evm/src/test/resources/org/hyperledger/besu/evm/precompile/verifyAggregateKzgProof.json new file mode 100644 index 00000000000..49827049907 --- /dev/null +++ b/evm/src/test/resources/org/hyperledger/besu/evm/precompile/verifyAggregateKzgProof.json @@ -0,0 +1,6 @@ +{ + "Count": 1, + "AggregatedProof": "0xa5cfdc5986e55ff1df6d1d8ef737a813bbef4f8b71846c6cde6013b910a10c499c13a09b528484fb7f8378d41e73e1e3", + "Commitments": "0x8211e2190c80040c537e0da6a16858486fe82d5cf86a3a3a3f6ab3e7d9c88a1e1af7df2f62203ea7c0f09cf268351909", + "Blobs": "0x89504e470d0a1a0a0000000d49484452000000f0000000f00803000000098b0019a00000000467414d410000b18f0bfc6105000000017352474200aece1ce900000000097048597300000dd700000dd70142289b78000002ac504c54454770004c627eea627eea617eea627eea637de9627eea5d5dff627eea627eea627eea00667ceb5e72ff627eea8080ff627eea0000ff627eea6080df627eea627fea6d006ddb627eea627eea617dea627eeb617fe9627eea5571e3637feb627eea627d00e9617eeb627eea627eea617fe9617eea627eea637eea5d74e8627fea647deb00627eea627eea627eea627fe9627eeb6680e6627eea617fea617dea627eea64007de7627eea627dea627eea627eea627eea627eeb627eea627fe9627dea617d00ed6480e8627eea627eeb617fea627deb627eea637eeb627deb627de7627ee900627eeb627deb637deb627eea637dee627eea637fe9637dea627eea627eea620080e9607cea617fea607eea617eea627deb627ee9617dea627eeb627ee9627f00ea627dea627eea637feb627fea627eea627dea617dec6280ea5e79e4627eea00637eeb627eea637fea627eea627fea617ee95e80ef637eeb627dea617eeac100ccf7627eeaffffff8198eedce2faadbbf4637feac0cbf76480ea6581ea6c8700eb6883ebbfcaf66682eb718aec6984ebfefeffb1bff57b93ed98abf28197ee00bdc8f6738ceca1b2f3bec9f6bbc7f691a5f0f8f9fe9eb0f2748dec889def700089ecaabaf494a7f1a6b6f37890ed7e95ee6e88ecacbbf4b0bef48ea2f0758e00edb8c5f6879cef7f96eefbfbfeb9c5f6aebcf48399ee859bef6a85ebecf0fc008ba0f08da1f0d0d9f9778fedbfcaf7e7ebfcb6c3f5b5c2f58299ee6b86ebfc00fcff7d94eea3b4f39badf29caef2849aef7a92edd7defadee4fbfdfdff8a9f00efc3cef7f5f6feb4c1f57991edf3f5fda5b6f390a4f0e2e7fbcbd4f8f2f4fd00d6ddf9e1e6fba8b7f3eef1fdc1cdf6f7f8fecdd6f8e8ecfcf0f3fdb8c4f5ba00c6f6c9d2f8b3c1f5d9e0faebeefc9aacf2f9fafecfd8f9c6d0f793a6f17c9400eea0b1f2c5cff7dae1fa95a8f1bdc9f6e4e9fbb3c0f596a8f1d3dbf9afbdf4004f05b1c20000007274524e5300fbdd36db3bf102fef5ef0c05fd04f901eb0800c9a807ced9175a39c40933e95e71e37fa5e1ab6f0b951968f77799880af35300c0d214425684d7d0a2ca2db31b3892652f669d4cbd20ed74af58cd1dec523100e6fa4425a023c77c826d96d591b6df408fdeb9273c13cb2a609b634f460fb000b87bd1e342ae00000f764944415478dadd9df94354e51ac75f161d1d19148100041441c41d05441157dc3545cd2c73d72cdb6f75cf39b38502828a823b2e8900e256b72c35dcd2cab55b69376f2ed7ca7bedda6df947eecc20c8cc59e79cef0073e6d0f7679d733e9ced7dbecff33e0f6326a9cb807619992316f7195a10bd00d26eefc8f31dedf695d10543fb2c1e9199da6e4017f6e751a7b4818b5fe8d600995754e7a2b7fb0f4cebd4e6598767bd15dd81d7ac0ed133b286b755ea949900e34b1cbc0e45958c9f99d2c6606de939dd75c1b668c99079716d85b65f611f003b0f903da930d7fab45da78ccae3611a3436a39fa5715721699b94f7ec2aab00d2be39a980275151ce300be2162775e6c9d43929c6626fe5295379629564d8002c83db63602c6f82620776b5046edca4b9bc49ea991379e4b88c68de44f5ea009b1c51dc2ea9a6e2066eec99110cacd2bbf311d0e8b408e10e18ece023a20e007d664500373ea7231f31e53d196f36efc4d17c443532dddc2f6fd6d37c841500b5d4c4b062552c6f01c59af5f28acf72f096906388291ec1b4eebc6594f80c003defab79bc859497418c9bfc1a6f318dea41c93b2b91b79c9e9846c7bba227006f41cdfe0b15ef930ede927264d2b81afd79cbea35829566a7b1bc85f5c29b00f0d0a8047f969b1a71bf55000ea05eec85e775fef701f0d7b2a16b9057086c002b8fcbc59d461a5e6380ce4602c16377467071774b813f688779d7abda13f000565cf201735f42d799c341bc24d6c67dc10f5c5681fccd8eed20de869d8277007b650098bb01fdd5f6001f64cc6c0aded2e3421330e784fe6e82e137d73334006985234233f08135d8e4c48bc678c7f522e1ddbfa505985b8ffde9ec0186d600934fd0ac048f098f81bddbb0bf5d62a00ac846b47eae135a0173473cd85f5f00a63f92208a8fd6dc0b02e6b6837f7fb0eef89728b4392c0403d7be0f3e80ce00f8783851bc7ffa540830b715ed08e8f2406625d0f07a5c4228b0f73cf818d30075f85c5d5f26baa11f082260eed777d0ce5ef85ee66422debd572580b97af400619e0d97f7752a33e6a220055cb3177d9c301dfaf954f985864a49606e173c002711960312ff1c11ef3b7f17a481b983e8438d0e27d33682ea86de29c8019f0028471f2b2b8c909fca71dfb64516987b883e5894e6fc710fb27cf74d411ed800bb117db458addfa62154bcf5820230b7d3833ede088d9e0e55fd4673d0200300ccbd07bfa99fd2f4862ea1bac0270565e0db6be16f6a2d15b83954bc570ea900007367e1c7d410378da35a72782e086ac0deddf0e587bae1338aea029f13540081b97de820829fac9a55a1fa04affe5a0330f701fab00e95fc4b17b29a24af00a005b87a35fab8dd95ab8d53a9788f566a02e636c18f5ca858df4eb5c67ae700baa00d98db035f6f29999893a82ef02e412bf0c952f4b15f55b8c0cb89787d00b951adc0dcbfd107cf968f1317515de03b8276606c06d5af81b2be5d2f22de000f853080f141c4dc1e265fe0f2e361017347d1273049269344f58aae12c2030006675079be9b740c31878877f7a13081d119549e7f4312986a91f5bb102eb000f723f0290c95e28d21e25d2f840d0ccfa0f2522bea241adef7bfd501cc7d01003e8bde62de9788f63b570b7a80ab1bb167d1799859c9e03d9feb02e61e80cf00a3af0878098dcde112f40173e00c6a91c87ba7b9c06704bdc077c14144a82b00ffac89418326606c19a6c8ebc9a5b1eeee0bfa81c14144fbe0ddf4f924bcdb002b0d00a333a8c1abad3e14bca5c70523c0dc06ba4f712e4985f011c118f02d00681091d73a489c49c1bb7f8b41607010914f7d471f138c0263cb305bddd3b600e904bc758261606c1031dd46baea08cd8dea02c69661c69096741c1010c0b7009165988f8b3e08aaa25b0a2a8d0173e780e794d8cc9bd201ce2bce8dea04460096613a52e8124a5b0510305705cca0e693d5814be446f50223cb309f277b84002f0a38e05f706598a31fede48842f336540281b933b0f38a6adaff310fcd1b005450691c185886d9b439310b0dbc53c002e3ca30170480678079b76dd1c67b00eae2098dc475a8539b11005e0906bea909f7d2cd1af7279bdd9a80616598b10081771678d951af05f7dec51a8e733b9dce2fae9569204665501dfeb7563bd3008306e1b326483fb0d3f9ded96a75625419a63f7e1888053ea9465bf9afe66b00da04ec747efadb65d5200254863901beceba724819f7bb9b352d14cdc04ee700279bff50213e8b39bdf13ee017a0c0ca41c3df7e6efdc43e06f6e9836b5ec500f7162683bacc070ccdfb9f55c2fd5f084410b0d3b9fd5cad0231a60cd3977100e93208c8dbf8bdc2a3fb31a70cec7b98d7df92278694610eeac2c6212f7099001cee969f24be3e22609fbedc479b414d817e958ecae446bfbe23f9b1950276003a3fbc21f33043ca308b91d1bf6441a5efd1f5caac2da4817d0ff326e92f3300a20c33159908972aa8ac747965dfbe72c0720ff36540063513e8584ae4460f00fdaeb4709407f67d991ffe2afe0f9b8d9fe4083618067c47fce87eacb898500002f63fcc3bbdf80cea625c9625b4a0f2f83fbc2aab271560ffc35c830e229200d850106f4841e575af7a44a00aec8b2c7eb8852dc39cca0a40c055418f6e8d0096305703b0ff61be8b2cc31cc9404dde5b15545efdaa4c9b91a109d8875cdf00ea61369a418d65a01ae996dce8bd9fbd1a8d1badc07e9be04c0d2888c8669800e615cd0595d77fd18c1b0eb0ef616e8e2c0c66507b32487bb0a682ca53dfd40070e1281c60a7f368dd494006d5ce20c1526dc0952be3384260bf4de0361c4400746488ad77be82ca301e5dddc08f3c3f438d6c1c08608feb3aa7473a809dce008673b5e70d01036ee9a3659c79c0bec862bba15b1af1d2daffae89c01b367a000cbdb4209f25cf7b07cc02de5d6af0b3045a78946f2e3303789d517f3a9bc100e607ed38430e7c7087e1682916163cf8b4ae8a1478c37e80533b12161e064c00ad0f6ae980af404a4da782cb2cd7ae275a4b9f06ed954f025a3c4ddab6930000784305aae8b23f41d9e1c19368e08f701b3e16b24c38305fbab90609bc0ed900b16611c288af10d58eadde0a03de232ad35a6ba4aa672624d552f58da8bbfd00f97d10e00ddb423f459eed5546e2c3624832cd73e173ef5ed16af3b071e0dd00e5e23fa4d750c62505932edd7649b8b42bf45aac51fb44a901ffa751ea51310064e3f9d2a5ac1be25df0d0ef6789c2b68a5d06800f8a3e45e5fe97e13e436f00ec25b092874039e9b1fda24fd465bdc0a275a4c7e9af63ab36966d59062b6a00591b483cfc7862ad68b559ad0758bc8edcdfb4a06930769a4b71654b1b9a9c00f86fcf85de888d5bbde1028b3f458d67bd90a4f8eb3ee034d027fdc6236bfa00c241ad86885baba5d1729b9c30ba068901961e7a9a930f95f777683344dc1a002d8d96b0d3f0060847601a26ca02d8d152c2736967a91643c4ad691d59710d00b7a538165b3e5cffb810fe9fa273dbb14903b0d8d258535706cc0ef709002f0080adcc6fb74a997eb34ed51071ab5a1a41cbb55ae39b1ffedad4fc1e065cde00ba8ce794a8b97fa821e256fb145dd907ee49b42200dc0fb7c963f777adab0000bedfe4513444dcca96c6eae0efd959e3a7f7746ed3b616606fd607c1751ed7001b940c11b792a5515a1fbc62b90bd8f8d0bc176f3c30c00e29e5a9fc6a9bbc0021e256b034426d9332c456e2e68d5a8540e0c6d082f82d55e57286885bf653002436c620a5a5731e010f43762b6d10d55b7e7b4ec61071cb591ae2b87217c200c473b434e481365896e88f76618fa421e296b434a4ccedc3906dc489341ba600a576d24a1b226e294b432a7de1c574f7cc22da12bf51aa1f8d9421b2536c690048acc77cfa0d736231544d0f1e4a56111f17799bef7bb4acb839ee0fcc16e200041b59b7344eba4efc98728d955c92b91ad494a775ab96422cf05a999e343f009e5078f9c89611a03669cd216cb6b4476ef792d81051f545500d98835ad3c0003b00de90df86f7a9c43f5770be4ea01af28c226de2e991ef4b5379bf220c6f0013d7277f4a701f5ef400da1df23b9842579b8aee35ac6f9a3d99b8455cbd52001f80568688727e02d78978327913c0db8abb101f19229eed8a19a85a5c87870062f2368fa59f296f88af6d54cf31e246d71688fa5ae213e3e7557a017c7f4e00add0e92cee641699d1aa75abc12e0f55b84a078956ad14cd78ef18022e034e009cea6d4ebbe5c67b4680911d88634c6aa8ddf0b97ee05dc0f670920db5d91b0078607e9f6ee003c85e6953a407d314e181151b8929017bd701cfa24866b0d60040824bbcf1923ee03ae449bc6ee6608b3a5dc0479093a6b293e54679505c620039fb4311b81ada797882fc709a9504c06b8e870ffc29f204962b0c319d407100894f873dd8023b654a61fc10b375a320be1126f065e8dc56c50153346d883d003f85050c9ee391af3c258e647e898cfde122efebc8ab0e89634f918c01fcb000523b3076dc92235d6df021cd3880c39a816bb1830007ab4eb64c694f012c69007fb8687b3a06cce814f5e1a534334c82ab3fe4817fc01eb6af86e9b4b697490088b76a02aec2ceef48d4328e978da119b87c4703700d76ac76d4c4488ed41600db1f2eda0ee9fe3d3bda945c44427cf4941af035ec20ad6e5db58e896f47330093779f0af02dec48eda862a6590b498043ed0f175d7774bf1668e765f1cf9100106fbcaa040c1e5adadd1606309b4fb2fc08b13f5c7426872f5b388d85a50c0012e060fb2308b87a07f648a92c4cbd46021c647fb8c84c0e7f67b470953c9a0084f8f48fd2c05bb187494c0e1b98cd4a2021de25098c3539f89ee3980e0d8f00a2006e657fb8a84c8ea8154c9732492ef163fbc3456472688a9124359e84b800c5fe7011cd941eac9797d9de22213e10027c1b3ba874ac4d3730cb4d24b13f005c41c05eacc951d28f19d0806c42fbc345310a6e790a33a4f973e9ec0f178100c9d1f3456650636693d91f2ebcc991f00a33ac897602e080fde1829b1cedd3001940ed28c65efaed0f1774b6904f1ddb31886228c622fe11003e813439ec20005ec6d20996d53efbc3853539a6c730985e212886d878d5053539e68e61403d0043f03dae73bd0b343996cf67500d20c8479cc11507f323c731b0fa8de52dac00b73b31b86ce3adcb3b389e5128d3614ddca8458c48ab7a5a9137611e23d3b800e7acc75b328d112a79a9e51edf3846ab8cf656c2b5a732724deb6e1ddec4f900cc04c5e73c6d91b7f39038668ed2ba5981b7a89899a6ae599d237f79bb323300352631b2bc4fa4339365cb8ce0ebdaded7c6ccd74b4b23b4d4748c4a6191d100534323c13b74228b9c0a634d7f37e7b388ca662e72f6a4781669c565449b8500dbab6f32b3829227149972334f886356519779e40650f7421bb394627a0fa200a31dd43b9d594f6f4e1a49742fe70c631655da6478e6cd3eb9985959c953460001979c83c666e432cbab477e6f484e39a1f79caeac8dc8969e33d5509597a30064c8bc78d6b6342cfff9d1baa0a3129fcf1fc6daa6fa0d5f3023368c98ca11003b63c18a5cd6c6d52966c2f865452a5fe9414b962d9d10d38ffd8934202db500efc2fe49530ba2a367db7d1ddaf2ec09d1d123a726f55fd83735cdbc00f7ff00e736c967869fbfa50000000049454e44ae42608200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 4d06c3c3ce4..76c31095547 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=23.4.5-SNAPSHOT +version=23.7.1-SNAPSHOT org.gradle.welcome=never # Set exports/opens flags required by Google Java Format and ErrorProne plugins. (JEP-396) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index a71f2bbff64..cd2a9ded305 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -467,6 +467,17 @@ + + + + + + + + + + + @@ -518,6 +529,14 @@ + + + + + + + + @@ -808,6 +827,9 @@ + + + @@ -2549,6 +2571,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2604,6 +2866,11 @@ + + + + + @@ -2630,6 +2897,14 @@ + + + + + + + + @@ -2638,11 +2913,24 @@ + + + + + + + + + + + + + @@ -2980,6 +3268,14 @@ + + + + + + + + @@ -2990,6 +3286,11 @@ + + + + + @@ -3006,6 +3307,14 @@ + + + + + + + + @@ -3354,6 +3663,14 @@ + + + + + + + + @@ -3386,6 +3703,14 @@ + + + + + + + + @@ -3410,6 +3735,14 @@ + + + + + + + + @@ -3450,6 +3783,14 @@ + + + + + + + + @@ -3466,6 +3807,14 @@ + + + + + + + + @@ -4276,6 +4625,17 @@ + + + + + + + + + + + @@ -4287,6 +4647,17 @@ + + + + + + + + + + + @@ -4298,6 +4669,17 @@ + + + + + + + + + + + @@ -4309,6 +4691,17 @@ + + + + + + + + + + + @@ -4320,6 +4713,17 @@ + + + + + + + + + + + @@ -4331,6 +4735,17 @@ + + + + + + + + + + + @@ -4526,6 +4941,14 @@ + + + + + + + + @@ -4563,11 +4986,24 @@ + + + + + + + + + + + + + @@ -4576,6 +5012,14 @@ + + + + + + + + @@ -4587,6 +5031,17 @@ + + + + + + + + + + + @@ -4598,6 +5053,17 @@ + + + + + + + + + + + @@ -5639,15 +6105,15 @@ - - - + + + - - + + - - + + diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 0c677809ad3..54c62d8f251 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -16,7 +16,7 @@ dependencyManagement { dependencies { - dependencySet(group: 'org.antlr', version: '4.10.1') { + dependencySet(group: 'org.antlr', version: '4.11.1') { entry 'antlr4' entry 'antlr4-runtime' } @@ -133,7 +133,7 @@ dependencyManagement { entry 'log4j-slf4j2-impl' } - dependencySet(group: 'org.apache.tuweni', version: '2.3.1') { + dependencySet(group: 'io.tmio', version: '2.4.2') { entry 'tuweni-bytes' entry 'tuweni-config' entry 'tuweni-concurrent' @@ -147,11 +147,6 @@ dependencyManagement { entry 'tuweni-units' } - // commons-net is a transitive dependency of tuweni. - // Tuweni 2.3.1 has commons-net:3.8.0 which we force here to 3.9.0 - // Once tuweni is updated, can remove this line - dependency 'commons-net:commons-net:3.9.0' - dependency 'org.assertj:assertj-core:3.24.2' dependency 'org.awaitility:awaitility:4.2.0' @@ -163,9 +158,9 @@ dependencyManagement { dependency 'org.fusesource.jansi:jansi:2.4.0' dependency 'org.openjdk.jol:jol-core:0.17' - dependency 'tech.pegasys:jc-kzg-4844:0.4.0' + dependency 'tech.pegasys:jc-kzg-4844:0.7.0' - dependencySet(group: 'org.hyperledger.besu', version: '0.7.1') { + dependencySet(group: 'org.hyperledger.besu', version: '0.8.1') { entry 'arithmetic' entry 'ipa-multipoint' entry 'bls12-381' diff --git a/pki/build.gradle b/pki/build.gradle index 3eab6aca046..c9021b3a83e 100644 --- a/pki/build.gradle +++ b/pki/build.gradle @@ -31,7 +31,7 @@ dependencies { api 'org.slf4j:slf4j-api' implementation 'com.google.guava:guava' - implementation 'org.apache.tuweni:tuweni-bytes' + implementation 'io.tmio:tuweni-bytes' implementation 'org.bouncycastle:bcpkix-jdk18on' testImplementation 'junit:junit' diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index f804c4a33cf..a4e4cdb95a9 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -1,5 +1,5 @@ /* - * Copyright 2019 ConsenSys AG. + * Copyright Hyperledger Besu Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -30,8 +30,8 @@ jar { dependencies { api project(':datatypes') api 'org.apache.commons:commons-lang3' - api 'org.apache.tuweni:tuweni-bytes' - api 'org.apache.tuweni:tuweni-units' + api 'io.tmio:tuweni-bytes' + api 'io.tmio:tuweni-units' implementation 'com.google.guava:guava' implementation project(':evm') } @@ -69,7 +69,7 @@ Calculated : ${currentHash} tasks.register('checkAPIChanges', FileStateChecker) { description = "Checks that the API for the Plugin-API project does not change without deliberate thought" files = sourceSets.main.allJava.files - knownHash = 'T7W0Yg01Qs77rIZ+qgDe4p/wUxXG2PrRDj71EZSMpYY=' + knownHash = 'jxYLp4SMEdixHCmHDjylVvl7W8smMCWispBMKPJlFXg=' } check.dependsOn('checkAPIChanges') diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockBody.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockBody.java index 5ffdbd161fc..858285365ad 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockBody.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockBody.java @@ -16,6 +16,7 @@ package org.hyperledger.besu.plugin.data; +import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.plugin.Unstable; import java.util.List; diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockHeader.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockHeader.java index 4105bfd89c8..7f80e7f3db6 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockHeader.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockHeader.java @@ -202,10 +202,18 @@ default Optional getPrevRandao() { Optional getDepositsRoot(); /** - * The excess_data_gas of this header. + * The excess_blob_gas of this header. * - * @return The excess_data_gas of this header. + * @return The excess_blob_gas of this header. */ @Unstable - Optional getExcessDataGas(); + Optional getExcessBlobGas(); + + /** + * The blob_gas_used of this header. + * + * @return The blob_gas_used of this header. + */ + @Unstable + Optional getBlobGasUsed(); } diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionSelectionResult.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionSelectionResult.java index 73e31176f81..08d3683bdce 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionSelectionResult.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionSelectionResult.java @@ -143,6 +143,15 @@ public boolean selected() { return Status.SELECTED.equals(status); } + /** + * Optionally return the reason why the transaction is invalid if present + * + * @return an optional with the invalid reason + */ + public Optional maybeInvalidReason() { + return maybeInvalidReason; + } + @Override public String toString() { return status.name() + maybeInvalidReason.map(ir -> "(" + ir + ")").orElse(""); diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/UnsignedPrivateMarkerTransaction.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/UnsignedPrivateMarkerTransaction.java index 6528eed7e06..eaebd253cc1 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/UnsignedPrivateMarkerTransaction.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/UnsignedPrivateMarkerTransaction.java @@ -16,6 +16,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Quantity; +import org.hyperledger.besu.datatypes.TransactionType; import java.util.Optional; diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuEvents.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuEvents.java index e484d947561..9d5b6394511 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuEvents.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuEvents.java @@ -15,11 +15,11 @@ package org.hyperledger.besu.plugin.services; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.plugin.data.AddedBlockContext; import org.hyperledger.besu.plugin.data.LogWithMetadata; import org.hyperledger.besu.plugin.data.PropagatedBlockContext; import org.hyperledger.besu.plugin.data.SyncStatus; -import org.hyperledger.besu.plugin.data.Transaction; import java.util.List; import java.util.Optional; diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/TraceService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/TraceService.java index d3b776043d0..e49057d6bfc 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/TraceService.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/TraceService.java @@ -15,8 +15,8 @@ package org.hyperledger.besu.plugin.services; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.plugin.Unstable; +import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer; /** The Trace service interface */ @Unstable @@ -27,7 +27,7 @@ public interface TraceService extends BesuService { * @param blockNumber the block number * @param tracer the tracer (OperationTracer) */ - void traceBlock(long blockNumber, OperationTracer tracer); + void traceBlock(long blockNumber, BlockAwareOperationTracer tracer); /** * Traces a block by hash @@ -35,5 +35,5 @@ public interface TraceService extends BesuService { * @param hash the block hash * @param tracer the tracer (OperationTracer) */ - void traceBlock(Hash hash, OperationTracer tracer); + void traceBlock(Hash hash, BlockAwareOperationTracer tracer); } diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/privacy/PrivacyPluginPayloadProvider.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/privacy/PrivacyPluginPayloadProvider.java index 551ae3cd2f2..6604cba8b5a 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/privacy/PrivacyPluginPayloadProvider.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/privacy/PrivacyPluginPayloadProvider.java @@ -14,8 +14,8 @@ */ package org.hyperledger.besu.plugin.services.privacy; +import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.plugin.data.PrivateTransaction; -import org.hyperledger.besu.plugin.data.Transaction; import java.util.Optional; diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/KeyValueStorageFactory.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/KeyValueStorageFactory.java index 53f6c0688aa..17da810df57 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/KeyValueStorageFactory.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/KeyValueStorageFactory.java @@ -20,6 +20,7 @@ import org.hyperledger.besu.plugin.services.exception.StorageException; import java.io.Closeable; +import java.util.List; /** Factory for creating key-value storage instances. */ @Unstable @@ -53,6 +54,25 @@ KeyValueStorage create( SegmentIdentifier segment, BesuConfiguration configuration, MetricsSystem metricsSystem) throws StorageException; + /** + * Creates a new segmented key-value storage instance, appropriate for the given segment. + * + *

    New segments may be introduced in future releases and should result in a new empty + * key-space. Segments created with the identifier of an existing segment should have the same + * data as that existing segment. + * + * @param segments list of segments identifiers that comprise the created segmented storage. + * @param configuration common configuration available to plugins, in a populated state. + * @param metricsSystem metrics component for recording key-value storage events. + * @return the storage instance reserved for the given segment. + * @exception StorageException problem encountered when creating storage for the segment. + */ + SegmentedKeyValueStorage create( + List segments, + BesuConfiguration configuration, + MetricsSystem metricsSystem) + throws StorageException; + /** * Whether storage segment isolation is supported by the factory created instances. * @@ -71,7 +91,5 @@ KeyValueStorage create( * @return true when the created storage supports snapshots false when * it does not. */ - default boolean isSnapshotIsolationSupported() { - return false; - } + boolean isSnapshotIsolationSupported(); } diff --git a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorage.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SegmentedKeyValueStorage.java similarity index 51% rename from services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorage.java rename to plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SegmentedKeyValueStorage.java index 7d28d3495ca..21e6ecca6f6 100644 --- a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorage.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SegmentedKeyValueStorage.java @@ -12,10 +12,9 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.hyperledger.besu.services.kvstore; +package org.hyperledger.besu.plugin.services.storage; import org.hyperledger.besu.plugin.services.exception.StorageException; -import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; import java.io.Closeable; import java.util.Optional; @@ -25,20 +24,8 @@ import org.apache.commons.lang3.tuple.Pair; -/** - * Service provided by Besu to facilitate persistent data storage. - * - * @param the segment identifier type - */ -public interface SegmentedKeyValueStorage extends Closeable { - - /** - * Gets segment identifier by name. - * - * @param segment the segment - * @return the segment identifier by name - */ - S getSegmentIdentifierByName(SegmentIdentifier segment); +/** Service provided by Besu to facilitate persistent data storage. */ +public interface SegmentedKeyValueStorage extends Closeable { /** * Get the value from the associated segment and key. @@ -48,7 +35,7 @@ public interface SegmentedKeyValueStorage extends Closeable { * @return The value persisted at the key index. * @throws StorageException the storage exception */ - Optional get(S segment, byte[] key) throws StorageException; + Optional get(SegmentIdentifier segment, byte[] key) throws StorageException; /** * Contains key. @@ -58,7 +45,8 @@ public interface SegmentedKeyValueStorage extends Closeable { * @return the boolean * @throws StorageException the storage exception */ - default boolean containsKey(final S segment, final byte[] key) throws StorageException { + default boolean containsKey(final SegmentIdentifier segment, final byte[] key) + throws StorageException { return get(segment, key).isPresent(); } @@ -68,71 +56,74 @@ default boolean containsKey(final S segment, final byte[] key) throws StorageExc * @return An object representing the transaction. * @throws StorageException the storage exception */ - Transaction startTransaction() throws StorageException; + SegmentedKeyValueStorageTransaction startTransaction() throws StorageException; /** * Returns a stream of all keys for the segment. * - * @param segmentHandle The segment handle whose keys we want to stream. + * @param segmentIdentifier The segment identifier whose keys we want to stream. * @return A stream of all keys in the specified segment. */ - Stream> stream(final S segmentHandle); + Stream> stream(final SegmentIdentifier segmentIdentifier); /** * Returns a stream of key-value pairs starting from the specified key. This method is used to * retrieve a stream of data from the storage, starting from the given key. If no data is * available from the specified key onwards, an empty stream is returned. * - * @param segmentHandle The segment handle whose keys we want to stream. + * @param segmentIdentifier The segment identifier whose keys we want to stream. * @param startKey The key from which the stream should start. * @return A stream of key-value pairs starting from the specified key. */ - Stream> streamFromKey(final S segmentHandle, final byte[] startKey); + Stream> streamFromKey( + final SegmentIdentifier segmentIdentifier, final byte[] startKey); /** * Stream keys. * - * @param segmentHandle the segment handle + * @param segmentIdentifier the segment identifier * @return the stream */ - Stream streamKeys(final S segmentHandle); + Stream streamKeys(final SegmentIdentifier segmentIdentifier); /** * Delete the value corresponding to the given key in the given segment if a write lock can be * instantly acquired on the underlying storage. Do nothing otherwise. * - * @param segmentHandle The segment handle whose keys we want to stream. + * @param segmentIdentifier The segment identifier whose keys we want to stream. * @param key The key to delete. * @return false if the lock on the underlying storage could not be instantly acquired, true * otherwise * @throws StorageException any problem encountered during the deletion attempt. */ - boolean tryDelete(S segmentHandle, byte[] key) throws StorageException; + boolean tryDelete(SegmentIdentifier segmentIdentifier, byte[] key) throws StorageException; /** * Gets all keys that matches condition. * - * @param segmentHandle the segment handle + * @param segmentIdentifier the segment identifier * @param returnCondition the return condition * @return set of result */ - Set getAllKeysThat(S segmentHandle, Predicate returnCondition); + Set getAllKeysThat( + SegmentIdentifier segmentIdentifier, Predicate returnCondition); /** * Gets all values from keys that matches condition. * - * @param segmentHandle the segment handle + * @param segmentIdentifier the segment identifier * @param returnCondition the return condition * @return the set of result */ - Set getAllValuesFromKeysThat(final S segmentHandle, Predicate returnCondition); + Set getAllValuesFromKeysThat( + final SegmentIdentifier segmentIdentifier, Predicate returnCondition); /** * Clear. * - * @param segmentHandle the segment handle + * @param segmentIdentifier the segment identifier */ - void clear(S segmentHandle); + void clear(SegmentIdentifier segmentIdentifier); /** * Whether the underlying storage is closed. @@ -140,45 +131,4 @@ default boolean containsKey(final S segment, final byte[] key) throws StorageExc * @return boolean indicating whether the underlying storage is closed. */ boolean isClosed(); - - /** - * Represents a set of changes to be committed atomically. A single transaction is not - * thread-safe, but multiple transactions can execute concurrently. - * - * @param the segment identifier type - */ - interface Transaction { - - /** - * Add the given key-value pair to the set of updates to be committed. - * - * @param segment the database segment - * @param key The key to set / modify. - * @param value The value to be set. - */ - void put(S segment, byte[] key, byte[] value); - - /** - * Schedules the given key to be deleted from storage. - * - * @param segment the database segment - * @param key The key to delete - */ - void remove(S segment, byte[] key); - - /** - * Atomically commit the set of changes contained in this transaction to the underlying - * key-value storage from which this transaction was started. After committing, the transaction - * is no longer usable and will throw exceptions if modifications are attempted. - * - * @throws StorageException the storage exception - */ - void commit() throws StorageException; - - /** - * Cancel this transaction. After rolling back, the transaction is no longer usable and will - * throw exceptions if modifications are attempted. - */ - void rollback(); - } } diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SegmentedKeyValueStorageTransaction.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SegmentedKeyValueStorageTransaction.java new file mode 100644 index 00000000000..117107a9715 --- /dev/null +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SegmentedKeyValueStorageTransaction.java @@ -0,0 +1,55 @@ +/* + * Copyright ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.plugin.services.storage; + +import org.hyperledger.besu.plugin.Unstable; +import org.hyperledger.besu.plugin.services.exception.StorageException; + +/** + * A transaction that can atomically commit a sequence of operations to a segmented key-value store. + */ +@Unstable +public interface SegmentedKeyValueStorageTransaction { + + /** + * Associates the specified value with the specified key. + * + *

    If a previously value had been store against the given key, the old value is replaced by the + * given value. + * + * @param segmentIdentifier the segment identifier + * @param key the given value is to be associated with. + * @param value associated with the specified key. + */ + void put(SegmentIdentifier segmentIdentifier, byte[] key, byte[] value); + + /** + * When the given key is present, the key and mapped value will be removed from storage. + * + * @param segmentIdentifier the segment identifier + * @param key the key and mapped value that will be removed. + */ + void remove(SegmentIdentifier segmentIdentifier, byte[] key); + + /** + * Performs an atomic commit of all the operations queued in the transaction. + * + * @throws StorageException problem was encountered preventing the commit + */ + void commit() throws StorageException; + + /** Reset the transaction to a state prior to any operations being queued. */ + void rollback(); +} diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SnappableKeyValueStorage.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SnappableKeyValueStorage.java index 8ef5f95cdda..18486ff02fd 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SnappableKeyValueStorage.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SnappableKeyValueStorage.java @@ -16,7 +16,7 @@ package org.hyperledger.besu.plugin.services.storage; /** The interface Snappable key value storage. */ -public interface SnappableKeyValueStorage extends KeyValueStorage { +public interface SnappableKeyValueStorage extends SegmentedKeyValueStorage { /** * Take snapshot. diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SnappedKeyValueStorage.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SnappedKeyValueStorage.java index 032563e9258..64f762eb772 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SnappedKeyValueStorage.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SnappedKeyValueStorage.java @@ -16,12 +16,12 @@ package org.hyperledger.besu.plugin.services.storage; /** The interface Snapped key value storage. */ -public interface SnappedKeyValueStorage extends KeyValueStorage { +public interface SnappedKeyValueStorage extends SegmentedKeyValueStorage { /** * Gets snapshot transaction. * * @return the snapshot transaction */ - KeyValueStorageTransaction getSnapshotTransaction(); + SegmentedKeyValueStorageTransaction getSnapshotTransaction(); } diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/tracer/BlockAwareOperationTracer.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/tracer/BlockAwareOperationTracer.java new file mode 100644 index 00000000000..037f7325dc4 --- /dev/null +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/tracer/BlockAwareOperationTracer.java @@ -0,0 +1,47 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.plugin.services.tracer; + +import org.hyperledger.besu.evm.tracing.OperationTracer; +import org.hyperledger.besu.plugin.data.BlockBody; +import org.hyperledger.besu.plugin.data.BlockHeader; + +/** + * An extended operation tracer that can trace the start and end of a block. + * + *

    In both methods, the block header and body are provided. + */ +public interface BlockAwareOperationTracer extends OperationTracer { + /** + * Trace the start of a block. + * + * @param blockHeader the header of the block which is traced + * @param blockBody the body of the block which is traced + */ + default void traceStartBlock(final BlockHeader blockHeader, final BlockBody blockBody) {} + + /** + * Trace the end of a block. + * + * @param blockHeader the header of the block which is traced + * @param blockBody the body of the block which is traced + */ + default void traceEndBlock(final BlockHeader blockHeader, final BlockBody blockBody) {} + + @Override + default boolean isExtendedTracing() { + return true; + } +} diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/txselection/TransactionSelector.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/txselection/TransactionSelector.java index e48684640c0..6322bd81387 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/txselection/TransactionSelector.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/txselection/TransactionSelector.java @@ -15,9 +15,9 @@ package org.hyperledger.besu.plugin.services.txselection; +import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.plugin.Unstable; import org.hyperledger.besu.plugin.data.Log; -import org.hyperledger.besu.plugin.data.Transaction; import org.hyperledger.besu.plugin.data.TransactionSelectionResult; import java.util.List; diff --git a/plugins/rocksdb/build.gradle b/plugins/rocksdb/build.gradle index fa4b0e9f0e0..f76e8d80ae0 100644 --- a/plugins/rocksdb/build.gradle +++ b/plugins/rocksdb/build.gradle @@ -45,17 +45,17 @@ dependencies { implementation 'info.picocli:picocli' implementation 'io.opentelemetry:opentelemetry-api' implementation 'io.prometheus:simpleclient' - implementation 'org.apache.tuweni:tuweni-bytes' + implementation 'io.tmio:tuweni-bytes' implementation 'org.rocksdb:rocksdbjni' implementation project(path: ':ethereum:core') testImplementation project(':testutil') - testImplementation 'junit:junit' - testImplementation 'org.assertj:assertj-core' - testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.mockito:mockito-core' testImplementation 'org.mockito:mockito-junit-jupiter' + testImplementation 'org.junit.jupiter:junit-jupiter' + testImplementation 'org.assertj:assertj-core' + testImplementation 'org.mockito:mockito-junit-jupiter' testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' } diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValuePrivacyStorageFactory.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValuePrivacyStorageFactory.java index ee20b85e968..355cc056924 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValuePrivacyStorageFactory.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValuePrivacyStorageFactory.java @@ -20,11 +20,13 @@ import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.plugin.services.storage.PrivacyKeyValueStorageFactory; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.DatabaseMetadata; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; import java.util.Set; import org.slf4j.Logger; @@ -38,7 +40,7 @@ public class RocksDBKeyValuePrivacyStorageFactory implements PrivacyKeyValueStor private static final Logger LOG = LoggerFactory.getLogger(RocksDBKeyValuePrivacyStorageFactory.class); private static final int DEFAULT_VERSION = 1; - private static final Set SUPPORTED_VERSIONS = Set.of(0, 1); + private static final Set SUPPORTED_VERSIONS = Set.of(1); private static final String PRIVATE_DATABASE_PATH = "private"; private final RocksDBKeyValueStorageFactory publicFactory; @@ -75,11 +77,33 @@ public KeyValueStorage create( return publicFactory.create(segment, commonConfiguration, metricsSystem); } + @Override + public SegmentedKeyValueStorage create( + final List segments, + final BesuConfiguration commonConfiguration, + final MetricsSystem metricsSystem) + throws StorageException { + if (databaseVersion == null) { + try { + databaseVersion = readDatabaseVersion(commonConfiguration); + } catch (final IOException e) { + throw new StorageException("Failed to retrieve the RocksDB database meta version", e); + } + } + + return publicFactory.create(segments, commonConfiguration, metricsSystem); + } + @Override public boolean isSegmentIsolationSupported() { return publicFactory.isSegmentIsolationSupported(); } + @Override + public boolean isSnapshotIsolationSupported() { + return publicFactory.isSnapshotIsolationSupported(); + } + @Override public void close() throws IOException { publicFactory.close(); @@ -96,7 +120,7 @@ private int readDatabaseVersion(final BesuConfiguration commonConfiguration) thr commonConfiguration.getStoragePath().resolve(PRIVATE_DATABASE_PATH).toFile().exists(); final int privacyDatabaseVersion; if (privacyDatabaseExists) { - privacyDatabaseVersion = DatabaseMetadata.lookUpFrom(dataDir).maybePrivacyVersion().orElse(0); + privacyDatabaseVersion = DatabaseMetadata.lookUpFrom(dataDir).maybePrivacyVersion().orElse(1); LOG.info( "Existing private database detected at {}. Version {}", dataDir, privacyDatabaseVersion); } else { diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValueStorageFactory.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValueStorageFactory.java index 81aa1a37087..0f08e3c0f9b 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValueStorageFactory.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValueStorageFactory.java @@ -14,8 +14,6 @@ */ package org.hyperledger.besu.plugin.services.storage.rocksdb; -import static com.google.common.base.Preconditions.checkNotNull; - import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; import org.hyperledger.besu.plugin.services.BesuConfiguration; import org.hyperledger.besu.plugin.services.MetricsSystem; @@ -23,6 +21,7 @@ import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.plugin.services.storage.KeyValueStorageFactory; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.DatabaseMetadata; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfiguration; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfigurationBuilder; @@ -30,9 +29,7 @@ import org.hyperledger.besu.plugin.services.storage.rocksdb.segmented.OptimisticRocksDBColumnarKeyValueStorage; import org.hyperledger.besu.plugin.services.storage.rocksdb.segmented.RocksDBColumnarKeyValueStorage; import org.hyperledger.besu.plugin.services.storage.rocksdb.segmented.TransactionDBRocksDBColumnarKeyValueStorage; -import org.hyperledger.besu.plugin.services.storage.rocksdb.unsegmented.RocksDBKeyValueStorage; import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorageAdapter; -import org.hyperledger.besu.services.kvstore.SnappableSegmentedKeyValueStorageAdapter; import java.io.IOException; import java.nio.file.Files; @@ -45,43 +42,44 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** The Rocks db key value storage factory. */ +/** + * The Rocks db key value storage factory creates segmented storage and uses a adapter to support + * unsegmented keyvalue storage. + */ public class RocksDBKeyValueStorageFactory implements KeyValueStorageFactory { private static final Logger LOG = LoggerFactory.getLogger(RocksDBKeyValueStorageFactory.class); private static final int DEFAULT_VERSION = 1; - private static final Set SUPPORTED_VERSIONS = Set.of(0, 1, 2); + private static final Set SUPPORTED_VERSIONS = Set.of(1, 2); private static final String NAME = "rocksdb"; private final RocksDBMetricsFactory rocksDBMetricsFactory; private final int defaultVersion; private Integer databaseVersion; - private Boolean isSegmentIsolationSupported; private RocksDBColumnarKeyValueStorage segmentedStorage; - private KeyValueStorage unsegmentedStorage; private RocksDBConfiguration rocksDBConfiguration; private final Supplier configuration; - private final List segments; + private final List configuredSegments; private final List ignorableSegments; /** * Instantiates a new RocksDb key value storage factory. * * @param configuration the configuration - * @param segments the segments + * @param configuredSegments the segments * @param ignorableSegments the ignorable segments * @param defaultVersion the default version * @param rocksDBMetricsFactory the rocks db metrics factory */ public RocksDBKeyValueStorageFactory( final Supplier configuration, - final List segments, + final List configuredSegments, final List ignorableSegments, final int defaultVersion, final RocksDBMetricsFactory rocksDBMetricsFactory) { this.configuration = configuration; - this.segments = segments; + this.configuredSegments = configuredSegments; this.ignorableSegments = ignorableSegments; this.defaultVersion = defaultVersion; this.rocksDBMetricsFactory = rocksDBMetricsFactory; @@ -91,46 +89,51 @@ public RocksDBKeyValueStorageFactory( * Instantiates a new RocksDb key value storage factory. * * @param configuration the configuration - * @param segments the segments + * @param configuredSegments the segments * @param defaultVersion the default version * @param rocksDBMetricsFactory the rocks db metrics factory */ public RocksDBKeyValueStorageFactory( final Supplier configuration, - final List segments, + final List configuredSegments, final int defaultVersion, final RocksDBMetricsFactory rocksDBMetricsFactory) { - this(configuration, segments, List.of(), defaultVersion, rocksDBMetricsFactory); + this(configuration, configuredSegments, List.of(), defaultVersion, rocksDBMetricsFactory); } /** * Instantiates a new Rocks db key value storage factory. * * @param configuration the configuration - * @param segments the segments + * @param configuredSegments the segments * @param ignorableSegments the ignorable segments * @param rocksDBMetricsFactory the rocks db metrics factory */ public RocksDBKeyValueStorageFactory( final Supplier configuration, - final List segments, + final List configuredSegments, final List ignorableSegments, final RocksDBMetricsFactory rocksDBMetricsFactory) { - this(configuration, segments, ignorableSegments, DEFAULT_VERSION, rocksDBMetricsFactory); + this( + configuration, + configuredSegments, + ignorableSegments, + DEFAULT_VERSION, + rocksDBMetricsFactory); } /** * Instantiates a new Rocks db key value storage factory. * * @param configuration the configuration - * @param segments the segments + * @param configuredSegments the segments * @param rocksDBMetricsFactory the rocks db metrics factory */ public RocksDBKeyValueStorageFactory( final Supplier configuration, - final List segments, + final List configuredSegments, final RocksDBMetricsFactory rocksDBMetricsFactory) { - this(configuration, segments, List.of(), DEFAULT_VERSION, rocksDBMetricsFactory); + this(configuration, configuredSegments, List.of(), DEFAULT_VERSION, rocksDBMetricsFactory); } /** @@ -153,30 +156,40 @@ public KeyValueStorage create( final BesuConfiguration commonConfiguration, final MetricsSystem metricsSystem) throws StorageException { + return new SegmentedKeyValueStorageAdapter( + segment, create(List.of(segment), commonConfiguration, metricsSystem)); + } + + @Override + public SegmentedKeyValueStorage create( + final List segments, + final BesuConfiguration commonConfiguration, + final MetricsSystem metricsSystem) + throws StorageException { final boolean isForestStorageFormat = DataStorageFormat.FOREST.getDatabaseVersion() == commonConfiguration.getDatabaseVersion(); if (requiresInit()) { init(commonConfiguration); } + // safety check to see that segments all exist within configured segments + if (!configuredSegments.containsAll(segments)) { + throw new StorageException( + "Attempted to create storage for segments that are not configured: " + + segments.stream() + .filter(segment -> !configuredSegments.contains(segment)) + .map(SegmentIdentifier::toString) + .collect(Collectors.joining(", "))); + } + // It's probably a good idea for the creation logic to be entirely dependent on the database // version. Introducing intermediate booleans that represent database properties and dispatching // creation logic based on them is error-prone. switch (databaseVersion) { - case 0 -> { - segmentedStorage = null; - if (unsegmentedStorage == null) { - unsegmentedStorage = - new RocksDBKeyValueStorage( - rocksDBConfiguration, metricsSystem, rocksDBMetricsFactory); - } - return unsegmentedStorage; - } case 1, 2 -> { - unsegmentedStorage = null; if (segmentedStorage == null) { final List segmentsForVersion = - segments.stream() + configuredSegments.stream() .filter(segmentId -> segmentId.includeInDatabaseVersion(databaseVersion)) .collect(Collectors.toList()); if (isForestStorageFormat) { @@ -199,20 +212,7 @@ public KeyValueStorage create( rocksDBMetricsFactory); } } - - final RocksDbSegmentIdentifier rocksSegment = - segmentedStorage.getSegmentIdentifierByName(segment); - - if (isForestStorageFormat) { - return new SegmentedKeyValueStorageAdapter<>(segment, segmentedStorage); - } else { - return new SnappableSegmentedKeyValueStorageAdapter<>( - segment, - segmentedStorage, - () -> - ((OptimisticRocksDBColumnarKeyValueStorage) segmentedStorage) - .takeSnapshot(rocksSegment)); - } + return segmentedStorage; } default -> throw new IllegalStateException( String.format( @@ -241,7 +241,6 @@ private void init(final BesuConfiguration commonConfiguration) { + " could not be found. You may not have the appropriate permission to access the item."; throw new StorageException(message, e); } - isSegmentIsolationSupported = databaseVersion >= 1; rocksDBConfiguration = RocksDBConfigurationBuilder.from(configuration.get()) .databaseDir(storagePath(commonConfiguration)) @@ -249,7 +248,7 @@ private void init(final BesuConfiguration commonConfiguration) { } private boolean requiresInit() { - return segmentedStorage == null && unsegmentedStorage == null; + return segmentedStorage == null; } private int readDatabaseVersion(final BesuConfiguration commonConfiguration) throws IOException { @@ -283,9 +282,6 @@ private int readDatabaseVersion(final BesuConfiguration commonConfiguration) thr @Override public void close() throws IOException { - if (unsegmentedStorage != null) { - unsegmentedStorage.close(); - } if (segmentedStorage != null) { segmentedStorage.close(); } @@ -293,9 +289,7 @@ public void close() throws IOException { @Override public boolean isSegmentIsolationSupported() { - return checkNotNull( - isSegmentIsolationSupported, - "Whether segment isolation is supported will be determined during creation. Call a creation method first"); + return true; } @Override diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/unsegmented/RocksDBTransaction.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBTransaction.java similarity index 72% rename from plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/unsegmented/RocksDBTransaction.java rename to plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBTransaction.java index ffd5a1596f6..53f7a8fedac 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/unsegmented/RocksDBTransaction.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBTransaction.java @@ -1,5 +1,5 @@ /* - * Copyright ConsenSys AG. + * Copyright Hyperledger Besu Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -12,13 +12,16 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.hyperledger.besu.plugin.services.storage.rocksdb.unsegmented; +package org.hyperledger.besu.plugin.services.storage.rocksdb; import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.metrics.OperationTimer; -import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction; -import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetrics; +import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction; +import java.util.function.Function; + +import org.rocksdb.ColumnFamilyHandle; import org.rocksdb.RocksDBException; import org.rocksdb.Transaction; import org.rocksdb.WriteOptions; @@ -26,32 +29,38 @@ import org.slf4j.LoggerFactory; /** The RocksDb transaction. */ -public class RocksDBTransaction implements KeyValueStorageTransaction { +public class RocksDBTransaction implements SegmentedKeyValueStorageTransaction { private static final Logger logger = LoggerFactory.getLogger(RocksDBTransaction.class); private static final String NO_SPACE_LEFT_ON_DEVICE = "No space left on device"; private final RocksDBMetrics metrics; private final Transaction innerTx; private final WriteOptions options; + private final Function columnFamilyMapper; /** * Instantiates a new RocksDb transaction. * + * @param columnFamilyMapper mapper from segment identifier to column family handle * @param innerTx the inner tx * @param options the options * @param metrics the metrics */ - RocksDBTransaction( - final Transaction innerTx, final WriteOptions options, final RocksDBMetrics metrics) { + public RocksDBTransaction( + final Function columnFamilyMapper, + final Transaction innerTx, + final WriteOptions options, + final RocksDBMetrics metrics) { + this.columnFamilyMapper = columnFamilyMapper; this.innerTx = innerTx; this.options = options; this.metrics = metrics; } @Override - public void put(final byte[] key, final byte[] value) { + public void put(final SegmentIdentifier segmentId, final byte[] key, final byte[] value) { try (final OperationTimer.TimingContext ignored = metrics.getWriteLatency().startTimer()) { - innerTx.put(key, value); + innerTx.put(columnFamilyMapper.apply(segmentId), key, value); } catch (final RocksDBException e) { if (e.getMessage().contains(NO_SPACE_LEFT_ON_DEVICE)) { logger.error(e.getMessage()); @@ -62,9 +71,9 @@ public void put(final byte[] key, final byte[] value) { } @Override - public void remove(final byte[] key) { + public void remove(final SegmentIdentifier segmentId, final byte[] key) { try (final OperationTimer.TimingContext ignored = metrics.getRemoveLatency().startTimer()) { - innerTx.delete(key); + innerTx.delete(columnFamilyMapper.apply(segmentId), key); } catch (final RocksDBException e) { if (e.getMessage().contains(NO_SPACE_LEFT_ON_DEVICE)) { logger.error(e.getMessage()); diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadata.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadata.java index 49b54315b32..1faf610cdc9 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadata.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadata.java @@ -151,7 +151,7 @@ private static DatabaseMetadata resolveDatabaseMetadata(final File metadataFile) try { databaseMetadata = MAPPER.readValue(metadataFile, DatabaseMetadata.class); } catch (FileNotFoundException fnfe) { - databaseMetadata = new DatabaseMetadata(0, 0); + databaseMetadata = new DatabaseMetadata(1, 1); } catch (JsonProcessingException jpe) { throw new IllegalStateException( String.format("Invalid metadata file %s", metadataFile.getAbsolutePath()), jpe); diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticRocksDBColumnarKeyValueStorage.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticRocksDBColumnarKeyValueStorage.java index 5fc8b3c1790..13f50da388e 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticRocksDBColumnarKeyValueStorage.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticRocksDBColumnarKeyValueStorage.java @@ -17,10 +17,12 @@ import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction; +import org.hyperledger.besu.plugin.services.storage.SnappableKeyValueStorage; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory; -import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbSegmentIdentifier; +import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBTransaction; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfiguration; -import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorageTransactionTransitionValidatorDecorator; +import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorageTransactionValidatorDecorator; import java.util.List; @@ -30,7 +32,8 @@ import org.rocksdb.WriteOptions; /** Optimistic RocksDB Columnar key value storage */ -public class OptimisticRocksDBColumnarKeyValueStorage extends RocksDBColumnarKeyValueStorage { +public class OptimisticRocksDBColumnarKeyValueStorage extends RocksDBColumnarKeyValueStorage + implements SnappableKeyValueStorage { private final OptimisticTransactionDB db; /** @@ -57,7 +60,7 @@ public OptimisticRocksDBColumnarKeyValueStorage( OptimisticTransactionDB.open( options, configuration.getDatabaseDir().toString(), columnDescriptors, columnHandles); initMetrics(); - initColumnHandler(); + initColumnHandles(); } catch (final RocksDBException e) { throw new StorageException(e); @@ -76,24 +79,25 @@ RocksDB getDB() { * @throws StorageException the storage exception */ @Override - public Transaction startTransaction() throws StorageException { + public SegmentedKeyValueStorageTransaction startTransaction() throws StorageException { throwIfClosed(); final WriteOptions writeOptions = new WriteOptions(); writeOptions.setIgnoreMissingColumnFamilies(true); - return new SegmentedKeyValueStorageTransactionTransitionValidatorDecorator<>( - new RocksDbTransaction(db.beginTransaction(writeOptions), writeOptions), this.closed::get); + return new SegmentedKeyValueStorageTransactionValidatorDecorator( + new RocksDBTransaction( + this::safeColumnHandle, db.beginTransaction(writeOptions), writeOptions, this.metrics), + this.closed::get); } /** * Take snapshot RocksDb columnar key value snapshot. * - * @param segment the segment * @return the RocksDb columnar key value snapshot * @throws StorageException the storage exception */ - public RocksDBColumnarKeyValueSnapshot takeSnapshot(final RocksDbSegmentIdentifier segment) - throws StorageException { + @Override + public RocksDBColumnarKeyValueSnapshot takeSnapshot() throws StorageException { throwIfClosed(); - return new RocksDBColumnarKeyValueSnapshot(db, segment, metrics); + return new RocksDBColumnarKeyValueSnapshot(db, this::safeColumnHandle, metrics); } } diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueSnapshot.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueSnapshot.java index f3ce7103e0c..d51bdb310b8 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueSnapshot.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueSnapshot.java @@ -18,26 +18,30 @@ import static java.util.stream.Collectors.toUnmodifiableSet; import org.hyperledger.besu.plugin.services.exception.StorageException; -import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction; +import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction; import org.hyperledger.besu.plugin.services.storage.SnappedKeyValueStorage; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetrics; -import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbSegmentIdentifier; import java.io.IOException; import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; import org.apache.tuweni.bytes.Bytes; +import org.rocksdb.ColumnFamilyHandle; import org.rocksdb.OptimisticTransactionDB; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** The RocksDb columnar key value snapshot. */ -public class RocksDBColumnarKeyValueSnapshot implements SnappedKeyValueStorage { +public class RocksDBColumnarKeyValueSnapshot + implements SegmentedKeyValueStorage, SnappedKeyValueStorage { private static final Logger LOG = LoggerFactory.getLogger(RocksDBColumnarKeyValueSnapshot.class); @@ -53,62 +57,66 @@ public class RocksDBColumnarKeyValueSnapshot implements SnappedKeyValueStorage { * Instantiates a new RocksDb columnar key value snapshot. * * @param db the db - * @param segment the segment * @param metrics the metrics */ RocksDBColumnarKeyValueSnapshot( final OptimisticTransactionDB db, - final RocksDbSegmentIdentifier segment, + final Function columnFamilyMapper, final RocksDBMetrics metrics) { this.db = db; - this.snapTx = new RocksDBSnapshotTransaction(db, segment.get(), metrics); + this.snapTx = new RocksDBSnapshotTransaction(db, columnFamilyMapper, metrics); } @Override - public Optional get(final byte[] key) throws StorageException { + public Optional get(final SegmentIdentifier segment, final byte[] key) + throws StorageException { throwIfClosed(); - return snapTx.get(key); + return snapTx.get(segment, key); } @Override - public Stream> stream() { + public Stream> stream(final SegmentIdentifier segment) { throwIfClosed(); - return snapTx.stream(); + return snapTx.stream(segment); } @Override - public Stream> streamFromKey(final byte[] startKey) { - return stream().filter(e -> Bytes.wrap(startKey).compareTo(Bytes.wrap(e.getKey())) <= 0); + public Stream> streamFromKey( + final SegmentIdentifier segment, final byte[] startKey) { + return stream(segment).filter(e -> Bytes.wrap(startKey).compareTo(Bytes.wrap(e.getKey())) <= 0); } @Override - public Stream streamKeys() { + public Stream streamKeys(final SegmentIdentifier segment) { throwIfClosed(); - return snapTx.streamKeys(); + return snapTx.streamKeys(segment); } @Override - public boolean tryDelete(final byte[] key) throws StorageException { + public boolean tryDelete(final SegmentIdentifier segment, final byte[] key) + throws StorageException { throwIfClosed(); - snapTx.remove(key); + snapTx.remove(segment, key); return true; } @Override - public Set getAllKeysThat(final Predicate returnCondition) { - return streamKeys().filter(returnCondition).collect(toUnmodifiableSet()); + public Set getAllKeysThat( + final SegmentIdentifier segment, final Predicate returnCondition) { + return streamKeys(segment).filter(returnCondition).collect(toUnmodifiableSet()); } @Override - public Set getAllValuesFromKeysThat(final Predicate returnCondition) { - return stream() + public Set getAllValuesFromKeysThat( + final SegmentIdentifier segment, final Predicate returnCondition) { + return stream(segment) .filter(pair -> returnCondition.test(pair.getKey())) .map(Pair::getValue) .collect(toUnmodifiableSet()); } @Override - public KeyValueStorageTransaction startTransaction() throws StorageException { + public SegmentedKeyValueStorageTransaction startTransaction() throws StorageException { // The use of a transaction on a transaction based key value store is dubious // at best. return our snapshot transaction instead. return snapTx; @@ -120,15 +128,16 @@ public boolean isClosed() { } @Override - public void clear() { + public void clear(final SegmentIdentifier segment) { throw new UnsupportedOperationException( "RocksDBColumnarKeyValueSnapshot does not support clear"); } @Override - public boolean containsKey(final byte[] key) throws StorageException { + public boolean containsKey(final SegmentIdentifier segment, final byte[] key) + throws StorageException { throwIfClosed(); - return snapTx.get(key).isPresent(); + return snapTx.get(segment, key).isPresent(); } @Override @@ -146,7 +155,7 @@ private void throwIfClosed() { } @Override - public KeyValueStorageTransaction getSnapshotTransaction() { + public SegmentedKeyValueStorageTransaction getSnapshotTransaction() { return snapTx; } } diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java index 7c3297aa8f6..567b3f623b9 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java @@ -14,20 +14,19 @@ */ package org.hyperledger.besu.plugin.services.storage.rocksdb.segmented; -import static java.util.Objects.requireNonNullElse; import static java.util.stream.Collectors.toUnmodifiableSet; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.metrics.OperationTimer; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetrics; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbIterator; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbSegmentIdentifier; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbUtil; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfiguration; -import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorage; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -41,9 +40,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import com.google.common.collect.ImmutableMap; import org.apache.commons.lang3.tuple.Pair; -import org.apache.tuweni.bytes.Bytes; import org.rocksdb.BlockBasedTableConfig; import org.rocksdb.BloomFilter; import org.rocksdb.ColumnFamilyDescriptor; @@ -66,12 +63,10 @@ import org.slf4j.LoggerFactory; /** The RocksDb columnar key value storage. */ -public abstract class RocksDBColumnarKeyValueStorage - implements SegmentedKeyValueStorage { +public abstract class RocksDBColumnarKeyValueStorage implements SegmentedKeyValueStorage { private static final Logger LOG = LoggerFactory.getLogger(RocksDBColumnarKeyValueStorage.class); static final String DEFAULT_COLUMN = "default"; - private static final String NO_SPACE_LEFT_ON_DEVICE = "No space left on device"; private static final int ROCKSDB_FORMAT_VERSION = 5; private static final long ROCKSDB_BLOCK_SIZE = 32768; /** RocksDb blockcache size when using the high spec option */ @@ -96,7 +91,6 @@ public abstract class RocksDBColumnarKeyValueStorage private final MetricsSystem metricsSystem; private final RocksDBMetricsFactory rocksDBMetricsFactory; private final RocksDBConfiguration configuration; - private Map segmentsById; /** RocksDB DB options */ protected DBOptions options; @@ -109,7 +103,7 @@ public abstract class RocksDBColumnarKeyValueStorage protected RocksDBMetrics metrics; /** Map of the columns handles by name */ - protected Map columnHandlesByName; + protected Map columnHandlesBySegmentIdentifier; /** Column descriptors */ protected List columnDescriptors; /** Column handles */ @@ -122,7 +116,7 @@ public abstract class RocksDBColumnarKeyValueStorage * Instantiates a new Rocks db columnar key value storage. * * @param configuration the configuration - * @param segments the segments + * @param defaultSegments the segments * @param ignorableSegments the ignorable segments * @param metricsSystem the metrics system * @param rocksDBMetricsFactory the rocks db metrics factory @@ -130,7 +124,7 @@ public abstract class RocksDBColumnarKeyValueStorage */ public RocksDBColumnarKeyValueStorage( final RocksDBConfiguration configuration, - final List segments, + final List defaultSegments, final List ignorableSegments, final MetricsSystem metricsSystem, final RocksDBMetricsFactory rocksDBMetricsFactory) @@ -142,7 +136,7 @@ public RocksDBColumnarKeyValueStorage( try { final ColumnFamilyOptions columnFamilyOptions = new ColumnFamilyOptions(); - trimmedSegments = new ArrayList<>(segments); + trimmedSegments = new ArrayList<>(defaultSegments); final List existingColumnFamilies = RocksDB.listColumnFamilies(new Options(), configuration.getDatabaseDir().toString()); // Only ignore if not existed currently @@ -209,21 +203,32 @@ void initMetrics() { metrics = rocksDBMetricsFactory.create(metricsSystem, configuration, getDB(), stats); } - void initColumnHandler() throws RocksDBException { - - segmentsById = + void initColumnHandles() throws RocksDBException { + // will not include the DEFAULT columnHandle, we do not use it: + columnHandlesBySegmentIdentifier = trimmedSegments.stream() .collect( Collectors.toMap( - segment -> Bytes.wrap(segment.getId()), SegmentIdentifier::getName)); - final ImmutableMap.Builder builder = ImmutableMap.builder(); - - for (ColumnFamilyHandle columnHandle : columnHandles) { - final String segmentName = - requireNonNullElse(segmentsById.get(Bytes.wrap(columnHandle.getName())), DEFAULT_COLUMN); - builder.put(segmentName, new RocksDbSegmentIdentifier(getDB(), columnHandle)); - } - columnHandlesByName = builder.build(); + segmentId -> segmentId, + segment -> { + var columnHandle = + columnHandles.stream() + .filter( + ch -> { + try { + return Arrays.equals(ch.getName(), segment.getId()); + } catch (RocksDBException e) { + throw new RuntimeException(e); + } + }) + .findFirst() + .orElseThrow( + () -> + new RuntimeException( + "Column handle not found for segment " + + segment.getName())); + return new RocksDbSegmentIdentifier(getDB(), columnHandle); + })); } BlockBasedTableConfig createBlockBasedTableConfig(final RocksDBConfiguration config) { @@ -239,49 +244,58 @@ BlockBasedTableConfig createBlockBasedTableConfig(final RocksDBConfiguration con .setBlockSize(ROCKSDB_BLOCK_SIZE); } - @Override - public RocksDbSegmentIdentifier getSegmentIdentifierByName(final SegmentIdentifier segment) { - return columnHandlesByName.get(segment.getName()); + /** + * Safe method to map segment identifier to column handle. + * + * @param segment segment identifier + * @return column handle + */ + protected ColumnFamilyHandle safeColumnHandle(final SegmentIdentifier segment) { + RocksDbSegmentIdentifier safeRef = columnHandlesBySegmentIdentifier.get(segment); + if (safeRef == null) { + throw new RuntimeException("Column handle not found for segment " + segment.getName()); + } + return safeRef.get(); } @Override - public Optional get(final RocksDbSegmentIdentifier segment, final byte[] key) + public Optional get(final SegmentIdentifier segment, final byte[] key) throws StorageException { throwIfClosed(); try (final OperationTimer.TimingContext ignored = metrics.getReadLatency().startTimer()) { - return Optional.ofNullable(getDB().get(segment.get(), readOptions, key)); + return Optional.ofNullable(getDB().get(safeColumnHandle(segment), readOptions, key)); } catch (final RocksDBException e) { throw new StorageException(e); } } @Override - public Stream> stream(final RocksDbSegmentIdentifier segmentHandle) { - final RocksIterator rocksIterator = getDB().newIterator(segmentHandle.get()); + public Stream> stream(final SegmentIdentifier segmentIdentifier) { + final RocksIterator rocksIterator = getDB().newIterator(safeColumnHandle(segmentIdentifier)); rocksIterator.seekToFirst(); return RocksDbIterator.create(rocksIterator).toStream(); } @Override public Stream> streamFromKey( - final RocksDbSegmentIdentifier segmentHandle, final byte[] startKey) { - final RocksIterator rocksIterator = getDB().newIterator(segmentHandle.get()); + final SegmentIdentifier segmentIdentifier, final byte[] startKey) { + final RocksIterator rocksIterator = getDB().newIterator(safeColumnHandle(segmentIdentifier)); rocksIterator.seek(startKey); return RocksDbIterator.create(rocksIterator).toStream(); } @Override - public Stream streamKeys(final RocksDbSegmentIdentifier segmentHandle) { - final RocksIterator rocksIterator = getDB().newIterator(segmentHandle.get()); + public Stream streamKeys(final SegmentIdentifier segmentIdentifier) { + final RocksIterator rocksIterator = getDB().newIterator(safeColumnHandle(segmentIdentifier)); rocksIterator.seekToFirst(); return RocksDbIterator.create(rocksIterator).toStreamKeys(); } @Override - public boolean tryDelete(final RocksDbSegmentIdentifier segmentHandle, final byte[] key) { + public boolean tryDelete(final SegmentIdentifier segmentIdentifier, final byte[] key) { try { - getDB().delete(segmentHandle.get(), tryDeleteOptions, key); + getDB().delete(safeColumnHandle(segmentIdentifier), tryDeleteOptions, key); return true; } catch (RocksDBException e) { if (e.getStatus().getCode() == Status.Code.Incomplete) { @@ -294,8 +308,8 @@ public boolean tryDelete(final RocksDbSegmentIdentifier segmentHandle, final byt @Override public Set getAllKeysThat( - final RocksDbSegmentIdentifier segmentHandle, final Predicate returnCondition) { - return stream(segmentHandle) + final SegmentIdentifier segmentIdentifier, final Predicate returnCondition) { + return stream(segmentIdentifier) .filter(pair -> returnCondition.test(pair.getKey())) .map(Pair::getKey) .collect(toUnmodifiableSet()); @@ -303,19 +317,16 @@ public Set getAllKeysThat( @Override public Set getAllValuesFromKeysThat( - final RocksDbSegmentIdentifier segmentHandle, final Predicate returnCondition) { - return stream(segmentHandle) + final SegmentIdentifier segmentIdentifier, final Predicate returnCondition) { + return stream(segmentIdentifier) .filter(pair -> returnCondition.test(pair.getKey())) .map(Pair::getValue) .collect(toUnmodifiableSet()); } @Override - public void clear(final RocksDbSegmentIdentifier segmentHandle) { - - columnHandlesByName.values().stream() - .filter(e -> e.equals(segmentHandle)) - .findAny() + public void clear(final SegmentIdentifier segmentIdentifier) { + Optional.ofNullable(columnHandlesBySegmentIdentifier.get(segmentIdentifier)) .ifPresent(RocksDbSegmentIdentifier::reset); } @@ -325,7 +336,7 @@ public void close() { txOptions.close(); options.close(); tryDeleteOptions.close(); - columnHandlesByName.values().stream() + columnHandlesBySegmentIdentifier.values().stream() .map(RocksDbSegmentIdentifier::get) .forEach(ColumnFamilyHandle::close); getDB().close(); @@ -344,84 +355,5 @@ void throwIfClosed() { } } - class RocksDbTransaction implements Transaction { - - private final org.rocksdb.Transaction innerTx; - private final WriteOptions options; - - /** - * Instantiates a new RocksDb transaction. - * - * @param innerTx the inner tx - * @param options the write options - */ - RocksDbTransaction(final org.rocksdb.Transaction innerTx, final WriteOptions options) { - this.innerTx = innerTx; - this.options = options; - } - - @Override - public void put(final RocksDbSegmentIdentifier segment, final byte[] key, final byte[] value) { - try (final OperationTimer.TimingContext ignored = metrics.getWriteLatency().startTimer()) { - innerTx.put(segment.get(), key, value); - } catch (final RocksDBException e) { - if (e.getMessage().contains(NO_SPACE_LEFT_ON_DEVICE)) { - LOG.error(e.getMessage()); - System.exit(0); - } - throw new StorageException(e); - } - } - - @Override - public void remove(final RocksDbSegmentIdentifier segment, final byte[] key) { - try (final OperationTimer.TimingContext ignored = metrics.getRemoveLatency().startTimer()) { - innerTx.delete(segment.get(), key); - } catch (final RocksDBException e) { - if (e.getMessage().contains(NO_SPACE_LEFT_ON_DEVICE)) { - LOG.error(e.getMessage()); - System.exit(0); - } - throw new StorageException(e); - } - } - - @Override - public synchronized void commit() throws StorageException { - try (final OperationTimer.TimingContext ignored = metrics.getCommitLatency().startTimer()) { - innerTx.commit(); - } catch (final RocksDBException e) { - if (e.getMessage().contains(NO_SPACE_LEFT_ON_DEVICE)) { - LOG.error(e.getMessage()); - System.exit(0); - } - throw new StorageException(e); - } finally { - close(); - } - } - - @Override - public void rollback() { - try { - innerTx.rollback(); - metrics.getRollbackCount().inc(); - } catch (final RocksDBException e) { - if (e.getMessage().contains(NO_SPACE_LEFT_ON_DEVICE)) { - LOG.error(e.getMessage()); - System.exit(0); - } - throw new StorageException(e); - } finally { - close(); - } - } - - private void close() { - innerTx.close(); - options.close(); - } - } - abstract RocksDB getDB(); } diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBSnapshotTransaction.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBSnapshotTransaction.java index dbe460b3ffb..c1c404628d9 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBSnapshotTransaction.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBSnapshotTransaction.java @@ -17,12 +17,14 @@ import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.metrics.OperationTimer; -import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction; +import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetrics; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbIterator; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; @@ -37,12 +39,13 @@ import org.slf4j.LoggerFactory; /** The Rocks db snapshot transaction. */ -public class RocksDBSnapshotTransaction implements KeyValueStorageTransaction, AutoCloseable { +public class RocksDBSnapshotTransaction + implements SegmentedKeyValueStorageTransaction, AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(RocksDBSnapshotTransaction.class); private static final String NO_SPACE_LEFT_ON_DEVICE = "No space left on device"; private final RocksDBMetrics metrics; private final OptimisticTransactionDB db; - private final ColumnFamilyHandle columnFamilyHandle; + private final Function columnFamilyMapper; private final Transaction snapTx; private final RocksDBSnapshot snapshot; private final WriteOptions writeOptions; @@ -53,16 +56,16 @@ public class RocksDBSnapshotTransaction implements KeyValueStorageTransaction, A * Instantiates a new RocksDb snapshot transaction. * * @param db the db - * @param columnFamilyHandle the column family handle + * @param columnFamilyMapper mapper from segment identifier to column family handle * @param metrics the metrics */ RocksDBSnapshotTransaction( final OptimisticTransactionDB db, - final ColumnFamilyHandle columnFamilyHandle, + final Function columnFamilyMapper, final RocksDBMetrics metrics) { this.metrics = metrics; this.db = db; - this.columnFamilyHandle = columnFamilyHandle; + this.columnFamilyMapper = columnFamilyMapper; this.snapshot = new RocksDBSnapshot(db); this.writeOptions = new WriteOptions(); this.snapTx = db.beginTransaction(writeOptions); @@ -72,14 +75,14 @@ public class RocksDBSnapshotTransaction implements KeyValueStorageTransaction, A private RocksDBSnapshotTransaction( final OptimisticTransactionDB db, - final ColumnFamilyHandle columnFamilyHandle, + final Function columnFamilyMapper, final RocksDBMetrics metrics, final RocksDBSnapshot snapshot, final Transaction snapTx, final ReadOptions readOptions) { this.metrics = metrics; this.db = db; - this.columnFamilyHandle = columnFamilyHandle; + this.columnFamilyMapper = columnFamilyMapper; this.snapshot = snapshot; this.writeOptions = new WriteOptions(); this.readOptions = readOptions; @@ -89,25 +92,26 @@ private RocksDBSnapshotTransaction( /** * Get data against given key. * + * @param segmentId the segment id * @param key the key * @return the optional data */ - public Optional get(final byte[] key) { + public Optional get(final SegmentIdentifier segmentId, final byte[] key) { throwIfClosed(); try (final OperationTimer.TimingContext ignored = metrics.getReadLatency().startTimer()) { - return Optional.ofNullable(snapTx.get(columnFamilyHandle, readOptions, key)); + return Optional.ofNullable(snapTx.get(columnFamilyMapper.apply(segmentId), readOptions, key)); } catch (final RocksDBException e) { throw new StorageException(e); } } @Override - public void put(final byte[] key, final byte[] value) { + public void put(final SegmentIdentifier segmentId, final byte[] key, final byte[] value) { throwIfClosed(); try (final OperationTimer.TimingContext ignored = metrics.getWriteLatency().startTimer()) { - snapTx.put(columnFamilyHandle, key, value); + snapTx.put(columnFamilyMapper.apply(segmentId), key, value); } catch (final RocksDBException e) { if (e.getMessage().contains(NO_SPACE_LEFT_ON_DEVICE)) { LOG.error(e.getMessage()); @@ -118,11 +122,11 @@ public void put(final byte[] key, final byte[] value) { } @Override - public void remove(final byte[] key) { + public void remove(final SegmentIdentifier segmentId, final byte[] key) { throwIfClosed(); try (final OperationTimer.TimingContext ignored = metrics.getRemoveLatency().startTimer()) { - snapTx.delete(columnFamilyHandle, key); + snapTx.delete(columnFamilyMapper.apply(segmentId), key); } catch (final RocksDBException e) { if (e.getMessage().contains(NO_SPACE_LEFT_ON_DEVICE)) { LOG.error(e.getMessage()); @@ -135,12 +139,14 @@ public void remove(final byte[] key) { /** * Stream. * + * @param segmentId the segment id * @return the stream */ - public Stream> stream() { + public Stream> stream(final SegmentIdentifier segmentId) { throwIfClosed(); - final RocksIterator rocksIterator = db.newIterator(columnFamilyHandle, readOptions); + final RocksIterator rocksIterator = + db.newIterator(columnFamilyMapper.apply(segmentId), readOptions); rocksIterator.seekToFirst(); return RocksDbIterator.create(rocksIterator).toStream(); } @@ -148,12 +154,14 @@ public Stream> stream() { /** * Stream keys. * + * @param segmentId the segment id * @return the stream */ - public Stream streamKeys() { + public Stream streamKeys(final SegmentIdentifier segmentId) { throwIfClosed(); - final RocksIterator rocksIterator = db.newIterator(columnFamilyHandle, readOptions); + final RocksIterator rocksIterator = + db.newIterator(columnFamilyMapper.apply(segmentId), readOptions); rocksIterator.seekToFirst(); return RocksDbIterator.create(rocksIterator).toStreamKeys(); } @@ -193,7 +201,7 @@ public RocksDBSnapshotTransaction copy() { var copySnapTx = db.beginTransaction(writeOptions); copySnapTx.rebuildFromWriteBatch(snapTx.getWriteBatch().getWriteBatch()); return new RocksDBSnapshotTransaction( - db, columnFamilyHandle, metrics, snapshot, copySnapTx, copyReadOptions); + db, columnFamilyMapper, metrics, snapshot, copySnapTx, copyReadOptions); } catch (Exception ex) { LOG.error("Failed to copy snapshot transaction", ex); snapshot.unMarkSnapshot(); diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorage.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorage.java index b6433ad19e7..6825a05063a 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorage.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorage.java @@ -17,10 +17,11 @@ import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory; -import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbSegmentIdentifier; +import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBTransaction; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfiguration; -import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorageTransactionTransitionValidatorDecorator; +import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorageTransactionValidatorDecorator; import java.util.List; @@ -62,7 +63,7 @@ public TransactionDBRocksDBColumnarKeyValueStorage( columnDescriptors, columnHandles); initMetrics(); - initColumnHandler(); + initColumnHandles(); } catch (final RocksDBException e) { throw new StorageException(e); @@ -81,11 +82,13 @@ RocksDB getDB() { * @throws StorageException the storage exception */ @Override - public Transaction startTransaction() throws StorageException { + public SegmentedKeyValueStorageTransaction startTransaction() throws StorageException { throwIfClosed(); final WriteOptions writeOptions = new WriteOptions(); writeOptions.setIgnoreMissingColumnFamilies(true); - return new SegmentedKeyValueStorageTransactionTransitionValidatorDecorator<>( - new RocksDbTransaction(db.beginTransaction(writeOptions), writeOptions), this.closed::get); + return new SegmentedKeyValueStorageTransactionValidatorDecorator( + new RocksDBTransaction( + this::safeColumnHandle, db.beginTransaction(writeOptions), writeOptions, metrics), + this.closed::get); } } diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/unsegmented/RocksDBKeyValueStorage.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/unsegmented/RocksDBKeyValueStorage.java deleted file mode 100644 index 6f32bd89c19..00000000000 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/unsegmented/RocksDBKeyValueStorage.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.plugin.services.storage.rocksdb.unsegmented; - -import static java.util.stream.Collectors.toUnmodifiableSet; - -import org.hyperledger.besu.plugin.services.MetricsSystem; -import org.hyperledger.besu.plugin.services.exception.StorageException; -import org.hyperledger.besu.plugin.services.metrics.OperationTimer; -import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; -import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction; -import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetrics; -import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory; -import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbIterator; -import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbUtil; -import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfiguration; -import org.hyperledger.besu.services.kvstore.KeyValueStorageTransactionTransitionValidatorDecorator; - -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Predicate; -import java.util.stream.Stream; - -import org.apache.commons.lang3.tuple.Pair; -import org.apache.tuweni.bytes.Bytes; -import org.rocksdb.BlockBasedTableConfig; -import org.rocksdb.LRUCache; -import org.rocksdb.OptimisticTransactionDB; -import org.rocksdb.Options; -import org.rocksdb.ReadOptions; -import org.rocksdb.RocksDBException; -import org.rocksdb.RocksIterator; -import org.rocksdb.Statistics; -import org.rocksdb.Status; -import org.rocksdb.WriteOptions; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** The Rocks db key value storage. */ -public class RocksDBKeyValueStorage implements KeyValueStorage { - - static { - RocksDbUtil.loadNativeLibrary(); - } - - private static final Logger LOG = LoggerFactory.getLogger(RocksDBKeyValueStorage.class); - - private final Options options; - private final OptimisticTransactionDB db; - private final AtomicBoolean closed = new AtomicBoolean(false); - private final RocksDBMetrics rocksDBMetrics; - private final WriteOptions tryDeleteOptions = - new WriteOptions().setNoSlowdown(true).setIgnoreMissingColumnFamilies(true); - private final ReadOptions readOptions = new ReadOptions().setVerifyChecksums(false); - - /** - * Instantiates a new Rocks db key value storage. - * - * @param configuration the configuration - * @param metricsSystem the metrics system - * @param rocksDBMetricsFactory the rocks db metrics factory - */ - public RocksDBKeyValueStorage( - final RocksDBConfiguration configuration, - final MetricsSystem metricsSystem, - final RocksDBMetricsFactory rocksDBMetricsFactory) { - - try { - final Statistics stats = new Statistics(); - options = - new Options() - .setCreateIfMissing(true) - .setMaxOpenFiles(configuration.getMaxOpenFiles()) - .setTableFormatConfig(createBlockBasedTableConfig(configuration)) - .setStatistics(stats); - options.getEnv().setBackgroundThreads(configuration.getBackgroundThreadCount()); - - db = OptimisticTransactionDB.open(options, configuration.getDatabaseDir().toString()); - rocksDBMetrics = rocksDBMetricsFactory.create(metricsSystem, configuration, db, stats); - } catch (final RocksDBException e) { - throw new StorageException(e); - } - } - - @Override - public void clear() throws StorageException { - throwIfClosed(); - - try (final RocksIterator rocksIterator = db.newIterator()) { - rocksIterator.seekToFirst(); - if (rocksIterator.isValid()) { - final byte[] firstKey = rocksIterator.key(); - rocksIterator.seekToLast(); - if (rocksIterator.isValid()) { - final byte[] lastKey = rocksIterator.key(); - db.deleteRange(firstKey, lastKey); - db.delete(lastKey); - } - } - } catch (final RocksDBException e) { - throw new StorageException(e); - } - } - - @Override - public boolean containsKey(final byte[] key) throws StorageException { - return get(key).isPresent(); - } - - @Override - public Optional get(final byte[] key) throws StorageException { - throwIfClosed(); - - try (final OperationTimer.TimingContext ignored = - rocksDBMetrics.getReadLatency().startTimer()) { - return Optional.ofNullable(db.get(readOptions, key)); - } catch (final RocksDBException e) { - throw new StorageException(e); - } - } - - @Override - public Set getAllKeysThat(final Predicate returnCondition) { - return stream() - .filter(pair -> returnCondition.test(pair.getKey())) - .map(Pair::getKey) - .collect(toUnmodifiableSet()); - } - - @Override - public Stream> stream() { - throwIfClosed(); - - final RocksIterator rocksIterator = db.newIterator(); - rocksIterator.seekToFirst(); - return RocksDbIterator.create(rocksIterator).toStream(); - } - - @Override - public Stream> streamFromKey(final byte[] startKey) { - return stream().filter(e -> Bytes.wrap(startKey).compareTo(Bytes.wrap(e.getKey())) <= 0); - } - - @Override - public Stream streamKeys() { - throwIfClosed(); - - final RocksIterator rocksIterator = db.newIterator(); - rocksIterator.seekToFirst(); - return RocksDbIterator.create(rocksIterator).toStreamKeys(); - } - - @Override - public Set getAllValuesFromKeysThat(final Predicate returnCondition) { - return stream() - .filter(pair -> returnCondition.test(pair.getKey())) - .map(Pair::getValue) - .collect(toUnmodifiableSet()); - } - - @Override - public boolean tryDelete(final byte[] key) { - throwIfClosed(); - try { - db.delete(tryDeleteOptions, key); - return true; - } catch (RocksDBException e) { - if (e.getStatus().getCode() == Status.Code.Incomplete) { - return false; - } else { - throw new StorageException(e); - } - } - } - - @Override - public KeyValueStorageTransaction startTransaction() throws StorageException { - throwIfClosed(); - final WriteOptions options = new WriteOptions(); - options.setIgnoreMissingColumnFamilies(true); - return new KeyValueStorageTransactionTransitionValidatorDecorator( - new RocksDBTransaction(db.beginTransaction(options), options, rocksDBMetrics)); - } - - @Override - public boolean isClosed() { - return closed.get(); - } - - @Override - public void close() { - if (closed.compareAndSet(false, true)) { - tryDeleteOptions.close(); - options.close(); - db.close(); - } - } - - private BlockBasedTableConfig createBlockBasedTableConfig(final RocksDBConfiguration config) { - final LRUCache cache = new LRUCache(config.getCacheCapacity()); - return new BlockBasedTableConfig().setBlockCache(cache); - } - - private void throwIfClosed() { - if (closed.get()) { - LOG.error("Attempting to use a closed RocksDBKeyValueStorage"); - throw new IllegalStateException("Storage has been closed"); - } - } -} diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBCLIOptionsTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBCLIOptionsTest.java index d93d6f8e7d9..8fe1e1a0fdc 100644 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBCLIOptionsTest.java +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBCLIOptionsTest.java @@ -26,7 +26,7 @@ import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBCLIOptions; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBFactoryConfiguration; -import org.junit.Test; +import org.junit.jupiter.api.Test; import picocli.CommandLine; public class RocksDBCLIOptionsTest { diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValuePrivacyStorageFactoryTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValuePrivacyStorageFactoryTest.java index 7106b1ad4f4..e0ed3f7b396 100644 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValuePrivacyStorageFactoryTest.java +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValuePrivacyStorageFactoryTest.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.plugin.services.storage.rocksdb; import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.plugin.services.storage.rocksdb.segmented.RocksDBColumnarKeyValueStorageTest.TestSegment; import static org.mockito.Mockito.when; import org.hyperledger.besu.metrics.ObservableMetricsSystem; @@ -28,29 +29,28 @@ import java.nio.file.Path; import java.util.List; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class RocksDBKeyValuePrivacyStorageFactoryTest { private static final int DEFAULT_VERSION = 1; private static final int DEFAULT_PRIVACY_VERSION = 1; @Mock private RocksDBFactoryConfiguration rocksDbConfiguration; @Mock private BesuConfiguration commonConfiguration; - @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder(); + @TempDir private Path temporaryFolder; private final ObservableMetricsSystem metricsSystem = new NoOpMetricsSystem(); - private final List segments = List.of(); - @Mock private SegmentIdentifier segment; + private final SegmentIdentifier segment = TestSegment.BAR; + private final List segments = List.of(segment); @Test - public void shouldDetectVersion0DatabaseIfNoMetadataFileFound() throws Exception { - final Path tempDataDir = temporaryFolder.newFolder().toPath().resolve("data"); - final Path tempDatabaseDir = temporaryFolder.newFolder().toPath().resolve("db"); + public void shouldDetectVersion1DatabaseIfNoMetadataFileFound() throws Exception { + final Path tempDataDir = temporaryFolder.resolve("data"); + final Path tempDatabaseDir = temporaryFolder.resolve("db"); final Path tempPrivateDatabaseDir = tempDatabaseDir.resolve("private"); Files.createDirectories(tempPrivateDatabaseDir); Files.createDirectories(tempDataDir); @@ -69,15 +69,16 @@ public void shouldDetectVersion0DatabaseIfNoMetadataFileFound() throws Exception assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).maybePrivacyVersion()).isNotEmpty(); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersion()).isEqualTo(0); + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersion()).isEqualTo(DEFAULT_VERSION); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).maybePrivacyVersion().get()).isEqualTo(0); + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).maybePrivacyVersion().get()) + .isEqualTo(DEFAULT_VERSION); } @Test public void shouldCreateCorrectMetadataFileForLatestVersion() throws Exception { - final Path tempDataDir = temporaryFolder.newFolder().toPath().resolve("data"); - final Path tempDatabaseDir = temporaryFolder.newFolder().toPath().resolve("db"); + final Path tempDataDir = temporaryFolder.resolve("data"); + final Path tempDatabaseDir = temporaryFolder.resolve("db"); when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); when(commonConfiguration.getDataPath()).thenReturn(tempDataDir); when(commonConfiguration.getDatabaseVersion()).thenReturn(DEFAULT_VERSION); @@ -102,8 +103,8 @@ public void shouldCreateCorrectMetadataFileForLatestVersion() throws Exception { @Test public void shouldUpdateCorrectMetadataFileForLatestVersion() throws Exception { - final Path tempDataDir = temporaryFolder.newFolder().toPath().resolve("data"); - final Path tempDatabaseDir = temporaryFolder.newFolder().toPath().resolve("db"); + final Path tempDataDir = temporaryFolder.resolve("data"); + final Path tempDatabaseDir = temporaryFolder.resolve("db"); when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); when(commonConfiguration.getDataPath()).thenReturn(tempDataDir); when(commonConfiguration.getDatabaseVersion()).thenReturn(DEFAULT_VERSION); diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValueStorageFactoryTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValueStorageFactoryTest.java index 000b5079c04..c3a8c32eb27 100644 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValueStorageFactoryTest.java +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValueStorageFactoryTest.java @@ -26,20 +26,20 @@ import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.DatabaseMetadata; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBFactoryConfiguration; +import org.hyperledger.besu.plugin.services.storage.rocksdb.segmented.RocksDBColumnarKeyValueStorageTest.TestSegment; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class RocksDBKeyValueStorageFactoryTest { private static final String METADATA_FILENAME = "DATABASE_METADATA.json"; @@ -47,15 +47,15 @@ public class RocksDBKeyValueStorageFactoryTest { @Mock private RocksDBFactoryConfiguration rocksDbConfiguration; @Mock private BesuConfiguration commonConfiguration; - @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder(); + @TempDir public Path temporaryFolder; private final ObservableMetricsSystem metricsSystem = new NoOpMetricsSystem(); - private final List segments = List.of(); - @Mock private SegmentIdentifier segment; + private final SegmentIdentifier segment = TestSegment.FOO; + private final List segments = List.of(segment); @Test public void shouldCreateCorrectMetadataFileForLatestVersion() throws Exception { - final Path tempDataDir = temporaryFolder.newFolder().toPath().resolve("data"); - final Path tempDatabaseDir = temporaryFolder.newFolder().toPath().resolve("db"); + final Path tempDataDir = temporaryFolder.resolve("data"); + final Path tempDatabaseDir = temporaryFolder.resolve("db"); when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); when(commonConfiguration.getDataPath()).thenReturn(tempDataDir); when(commonConfiguration.getDatabaseVersion()).thenReturn(DEFAULT_VERSION); @@ -71,9 +71,9 @@ public void shouldCreateCorrectMetadataFileForLatestVersion() throws Exception { } @Test - public void shouldDetectVersion0DatabaseIfNoMetadataFileFound() throws Exception { - final Path tempDataDir = temporaryFolder.newFolder().toPath().resolve("data"); - final Path tempDatabaseDir = temporaryFolder.newFolder().toPath().resolve("db"); + public void shouldDetectVersion1DatabaseIfNoMetadataFileFound() throws Exception { + final Path tempDataDir = temporaryFolder.resolve("data"); + final Path tempDatabaseDir = temporaryFolder.resolve("db"); Files.createDirectories(tempDatabaseDir); Files.createDirectories(tempDataDir); when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); @@ -85,13 +85,13 @@ public void shouldDetectVersion0DatabaseIfNoMetadataFileFound() throws Exception storageFactory.create(segment, commonConfiguration, metricsSystem); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersion()).isZero(); + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersion()).isEqualTo(DEFAULT_VERSION); } @Test public void shouldDetectCorrectVersionIfMetadataFileExists() throws Exception { - final Path tempDataDir = temporaryFolder.newFolder().toPath().resolve("data"); - final Path tempDatabaseDir = temporaryFolder.newFolder().toPath().resolve("db"); + final Path tempDataDir = temporaryFolder.resolve("data"); + final Path tempDatabaseDir = temporaryFolder.resolve("db"); Files.createDirectories(tempDataDir); when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); when(commonConfiguration.getDataPath()).thenReturn(tempDataDir); @@ -109,8 +109,8 @@ public void shouldDetectCorrectVersionIfMetadataFileExists() throws Exception { @Test public void shouldDetectCorrectVersionInCaseOfRollback() throws Exception { - final Path tempDataDir = temporaryFolder.newFolder().toPath().resolve("data"); - final Path tempDatabaseDir = temporaryFolder.newFolder().toPath().resolve("db"); + final Path tempDataDir = temporaryFolder.resolve("data"); + final Path tempDatabaseDir = temporaryFolder.resolve("db"); Files.createDirectories(tempDatabaseDir); Files.createDirectories(tempDataDir); when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); @@ -118,21 +118,21 @@ public void shouldDetectCorrectVersionInCaseOfRollback() throws Exception { final RocksDBKeyValueStorageFactory storageFactory = new RocksDBKeyValueStorageFactory( - () -> rocksDbConfiguration, segments, 1, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); + () -> rocksDbConfiguration, segments, 2, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); storageFactory.create(segment, commonConfiguration, metricsSystem); storageFactory.close(); final RocksDBKeyValueStorageFactory rolledbackStorageFactory = new RocksDBKeyValueStorageFactory( - () -> rocksDbConfiguration, segments, 0, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); + () -> rocksDbConfiguration, segments, 1, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); rolledbackStorageFactory.create(segment, commonConfiguration, metricsSystem); } @Test public void shouldThrowExceptionWhenVersionNumberIsInvalid() throws Exception { - final Path tempDataDir = temporaryFolder.newFolder().toPath().resolve("data"); - final Path tempDatabaseDir = temporaryFolder.newFolder().toPath().resolve("db"); + final Path tempDataDir = temporaryFolder.resolve("data"); + final Path tempDatabaseDir = temporaryFolder.resolve("db"); Files.createDirectories(tempDatabaseDir); Files.createDirectories(tempDataDir); when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); @@ -150,8 +150,8 @@ public void shouldThrowExceptionWhenVersionNumberIsInvalid() throws Exception { @Test public void shouldSetSegmentationFieldDuringCreation() throws Exception { - final Path tempDataDir = temporaryFolder.newFolder().toPath().resolve("data"); - final Path tempDatabaseDir = temporaryFolder.newFolder().toPath().resolve("db"); + final Path tempDataDir = temporaryFolder.resolve("data"); + final Path tempDatabaseDir = temporaryFolder.resolve("db"); Files.createDirectories(tempDatabaseDir); Files.createDirectories(tempDataDir); when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); @@ -166,8 +166,8 @@ public void shouldSetSegmentationFieldDuringCreation() throws Exception { @Test public void shouldThrowExceptionWhenMetaDataFileIsCorrupted() throws Exception { - final Path tempDataDir = temporaryFolder.newFolder().toPath().resolve("data"); - final Path tempDatabaseDir = temporaryFolder.newFolder().toPath().resolve("db"); + final Path tempDataDir = temporaryFolder.resolve("data"); + final Path tempDatabaseDir = temporaryFolder.resolve("db"); Files.createDirectories(tempDatabaseDir); Files.createDirectories(tempDataDir); when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); @@ -202,12 +202,10 @@ public void shouldThrowExceptionWhenMetaDataFileIsCorrupted() throws Exception { @Test public void shouldCreateDBCorrectlyIfSymlink() throws Exception { - final Path tempRealDataDir = - Files.createDirectories(temporaryFolder.newFolder().toPath().resolve("real-data-dir")); + final Path tempRealDataDir = Files.createDirectories(temporaryFolder.resolve("real-data-dir")); final Path tempSymLinkDataDir = - Files.createSymbolicLink( - temporaryFolder.newFolder().toPath().resolve("symlink-data-dir"), tempRealDataDir); - final Path tempDatabaseDir = temporaryFolder.newFolder().toPath().resolve("db"); + Files.createSymbolicLink(temporaryFolder.resolve("symlink-data-dir"), tempRealDataDir); + final Path tempDatabaseDir = temporaryFolder.resolve("db"); when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); when(commonConfiguration.getDataPath()).thenReturn(tempSymLinkDataDir); when(commonConfiguration.getDatabaseVersion()).thenReturn(DEFAULT_VERSION); diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBMetricsTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBMetricsTest.java index 960f11c5a17..7f02aa53b29 100644 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBMetricsTest.java +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBMetricsTest.java @@ -30,19 +30,19 @@ import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfiguration; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfigurationBuilder; +import java.nio.file.Path; import java.util.function.LongSupplier; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; import org.rocksdb.OptimisticTransactionDB; import org.rocksdb.Statistics; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class RocksDBMetricsTest { @Mock private ObservableMetricsSystem metricsSystemMock; @@ -52,7 +52,7 @@ public class RocksDBMetricsTest { @Mock private OptimisticTransactionDB db; @Mock private Statistics stats; - @Rule public final TemporaryFolder folder = new TemporaryFolder(); + @TempDir public Path folder; @Test public void createStoreMustCreateMetrics() throws Exception { @@ -120,6 +120,6 @@ public void createStoreMustCreateMetrics() throws Exception { } private RocksDBConfiguration config() throws Exception { - return new RocksDBConfigurationBuilder().databaseDir(folder.newFolder().toPath()).build(); + return new RocksDBConfigurationBuilder().databaseDir(folder).build(); } } diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadataTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadataTest.java index b060b022d1a..569819f8312 100644 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadataTest.java +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadataTest.java @@ -21,22 +21,21 @@ import java.nio.file.Files; import java.nio.file.Path; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; -public class DatabaseMetadataTest { - @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder(); +class DatabaseMetadataTest { + @TempDir public Path temporaryFolder; @Test - public void getVersion() { + void getVersion() { final DatabaseMetadata databaseMetadata = new DatabaseMetadata(42); assertThat(databaseMetadata).isNotNull(); assertThat(databaseMetadata.getVersion()).isEqualTo(42); } @Test - public void metaFileShouldMayContain() throws Exception { + void metaFileShouldMayContain() throws Exception { final Path tempDataDir = createAndWrite( "data", "DATABASE_METADATA.json", "{\"version\":42 , \"privacyVersion\":55}"); @@ -49,7 +48,7 @@ public void metaFileShouldMayContain() throws Exception { } @Test - public void metaFileShouldBeSoughtIntoDataDirFirst() throws Exception { + void metaFileShouldBeSoughtIntoDataDirFirst() throws Exception { final Path tempDataDir = createAndWrite("data", "DATABASE_METADATA.json", "{\"version\":42}"); final DatabaseMetadata databaseMetadata = DatabaseMetadata.lookUpFrom(tempDataDir); assertThat(databaseMetadata).isNotNull(); @@ -62,12 +61,9 @@ private Path createAndWrite(final String dir, final String file, final String co } private Path createAndWrite( - final TemporaryFolder temporaryFolder, - final String dir, - final String file, - final String content) + final Path temporaryFolder, final String dir, final String file, final String content) throws IOException { - final Path tmpDir = temporaryFolder.newFolder().toPath().resolve(dir); + final Path tmpDir = temporaryFolder.resolve(dir); Files.createDirectories(tmpDir); createAndWrite(tmpDir.resolve(file), content); return tmpDir; diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticTransactionDBRocksDBColumnarKeyValueStorageTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticTransactionDBRocksDBColumnarKeyValueStorageTest.java index 2c9fc86df13..7e8cef52cc2 100644 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticTransactionDBRocksDBColumnarKeyValueStorageTest.java +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticTransactionDBRocksDBColumnarKeyValueStorageTest.java @@ -15,27 +15,29 @@ package org.hyperledger.besu.plugin.services.storage.rocksdb.segmented; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; +import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory; -import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbSegmentIdentifier; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfigurationBuilder; -import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorage; +import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; import java.util.List; -import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +@ExtendWith(MockitoExtension.class) public class OptimisticTransactionDBRocksDBColumnarKeyValueStorageTest extends RocksDBColumnarKeyValueStorageTest { @Override - protected SegmentedKeyValueStorage createSegmentedStore() - throws Exception { + protected SegmentedKeyValueStorage createSegmentedStore() throws Exception { return new OptimisticRocksDBColumnarKeyValueStorage( new RocksDBConfigurationBuilder() - .databaseDir(folder.resolve(Bytes.random(9).toString())) + .databaseDir(Files.createTempDirectory("segmentedStore")) .build(), Arrays.asList(TestSegment.FOO, TestSegment.BAR), List.of(), @@ -44,7 +46,7 @@ protected SegmentedKeyValueStorage createSegmentedStor } @Override - protected SegmentedKeyValueStorage createSegmentedStore( + protected SegmentedKeyValueStorage createSegmentedStore( final Path path, final List segments, final List ignorableSegments) { @@ -55,4 +57,18 @@ protected SegmentedKeyValueStorage createSegmentedStor new NoOpMetricsSystem(), RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); } + + @Override + protected SegmentedKeyValueStorage createSegmentedStore( + final Path path, + final MetricsSystem metricsSystem, + final List segments, + final List ignorableSegments) { + return new OptimisticRocksDBColumnarKeyValueStorage( + new RocksDBConfigurationBuilder().databaseDir(path).build(), + segments, + ignorableSegments, + metricsSystem, + RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); + } } diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorageTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorageTest.java index 98eaf034960..827b18eb0c1 100644 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorageTest.java +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorageTest.java @@ -16,15 +16,26 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import org.hyperledger.besu.kvstore.AbstractKeyValueStorageTest; +import org.hyperledger.besu.metrics.BesuMetricCategory; +import org.hyperledger.besu.metrics.ObservableMetricsSystem; +import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.exception.StorageException; +import org.hyperledger.besu.plugin.services.metrics.Counter; +import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; +import org.hyperledger.besu.plugin.services.metrics.OperationTimer; import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; -import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbSegmentIdentifier; -import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorage; -import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorage.Transaction; -import org.hyperledger.besu.services.kvstore.SnappableSegmentedKeyValueStorageAdapter; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction; +import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorageAdapter; import java.nio.charset.StandardCharsets; import java.nio.file.Path; @@ -33,13 +44,21 @@ import java.util.Optional; import java.util.Set; import java.util.function.Consumer; +import java.util.function.LongSupplier; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; public abstract class RocksDBColumnarKeyValueStorageTest extends AbstractKeyValueStorageTest { + @Mock private ObservableMetricsSystem metricsSystemMock; + @Mock private LabelledMetric labelledMetricOperationTimerMock; + @Mock private LabelledMetric labelledMetricCounterMock; + @Mock private OperationTimer operationTimerMock; + @TempDir public Path folder; @Test @@ -47,14 +66,14 @@ public void assertClear() throws Exception { final byte[] key = bytesFromHexString("0001"); final byte[] val1 = bytesFromHexString("0FFF"); final byte[] val2 = bytesFromHexString("1337"); - final SegmentedKeyValueStorage store = createSegmentedStore(); - RocksDbSegmentIdentifier segment = store.getSegmentIdentifierByName(TestSegment.FOO); + final SegmentedKeyValueStorage store = createSegmentedStore(); + var segment = TestSegment.FOO; KeyValueStorage duplicateSegmentRef = - new SnappableSegmentedKeyValueStorageAdapter<>(TestSegment.FOO, store); + new SegmentedKeyValueStorageAdapter(TestSegment.FOO, store); final Consumer insert = value -> { - final Transaction tx = store.startTransaction(); + final SegmentedKeyValueStorageTransaction tx = store.startTransaction(); tx.put(segment, key, value); tx.commit(); }; @@ -79,17 +98,13 @@ public void assertClear() throws Exception { @Test public void twoSegmentsAreIndependent() throws Exception { - final SegmentedKeyValueStorage store = createSegmentedStore(); + final SegmentedKeyValueStorage store = createSegmentedStore(); - final Transaction tx = store.startTransaction(); - tx.put( - store.getSegmentIdentifierByName(TestSegment.BAR), - bytesFromHexString("0001"), - bytesFromHexString("0FFF")); + final SegmentedKeyValueStorageTransaction tx = store.startTransaction(); + tx.put(TestSegment.BAR, bytesFromHexString("0001"), bytesFromHexString("0FFF")); tx.commit(); - final Optional result = - store.get(store.getSegmentIdentifierByName(TestSegment.FOO), bytesFromHexString("0001")); + final Optional result = store.get(TestSegment.FOO, bytesFromHexString("0001")); assertThat(result).isEmpty(); @@ -101,43 +116,41 @@ public void canRemoveThroughSegmentIteration() throws Exception { // we're looping this in order to catch intermittent failures when rocksdb objects are not close // properly for (int i = 0; i < 50; i++) { - final SegmentedKeyValueStorage store = createSegmentedStore(); - final RocksDbSegmentIdentifier fooSegment = store.getSegmentIdentifierByName(TestSegment.FOO); - final RocksDbSegmentIdentifier barSegment = store.getSegmentIdentifierByName(TestSegment.BAR); - - final Transaction tx = store.startTransaction(); - tx.put(fooSegment, bytesOf(1), bytesOf(1)); - tx.put(fooSegment, bytesOf(2), bytesOf(2)); - tx.put(fooSegment, bytesOf(3), bytesOf(3)); - tx.put(barSegment, bytesOf(4), bytesOf(4)); - tx.put(barSegment, bytesOf(5), bytesOf(5)); - tx.put(barSegment, bytesOf(6), bytesOf(6)); + final SegmentedKeyValueStorage store = createSegmentedStore(); + + final SegmentedKeyValueStorageTransaction tx = store.startTransaction(); + tx.put(TestSegment.FOO, bytesOf(1), bytesOf(1)); + tx.put(TestSegment.FOO, bytesOf(2), bytesOf(2)); + tx.put(TestSegment.FOO, bytesOf(3), bytesOf(3)); + tx.put(TestSegment.BAR, bytesOf(4), bytesOf(4)); + tx.put(TestSegment.BAR, bytesOf(5), bytesOf(5)); + tx.put(TestSegment.BAR, bytesOf(6), bytesOf(6)); tx.commit(); - store.stream(fooSegment) + store.stream(TestSegment.FOO) .map(Pair::getKey) .forEach( key -> { - if (!Arrays.equals(key, bytesOf(3))) store.tryDelete(fooSegment, key); + if (!Arrays.equals(key, bytesOf(3))) store.tryDelete(TestSegment.FOO, key); }); - store.stream(barSegment) + store.stream(TestSegment.BAR) .map(Pair::getKey) .forEach( key -> { - if (!Arrays.equals(key, bytesOf(4))) store.tryDelete(barSegment, key); + if (!Arrays.equals(key, bytesOf(4))) store.tryDelete(TestSegment.BAR, key); }); - for (final RocksDbSegmentIdentifier segment : Set.of(fooSegment, barSegment)) { + for (final var segment : Set.of(TestSegment.FOO, TestSegment.BAR)) { assertThat(store.stream(segment).count()).isEqualTo(1); } - assertThat(store.get(fooSegment, bytesOf(1))).isEmpty(); - assertThat(store.get(fooSegment, bytesOf(2))).isEmpty(); - assertThat(store.get(fooSegment, bytesOf(3))).contains(bytesOf(3)); + assertThat(store.get(TestSegment.FOO, bytesOf(1))).isEmpty(); + assertThat(store.get(TestSegment.FOO, bytesOf(2))).isEmpty(); + assertThat(store.get(TestSegment.FOO, bytesOf(3))).contains(bytesOf(3)); - assertThat(store.get(barSegment, bytesOf(4))).contains(bytesOf(4)); - assertThat(store.get(barSegment, bytesOf(5))).isEmpty(); - assertThat(store.get(barSegment, bytesOf(6))).isEmpty(); + assertThat(store.get(TestSegment.BAR, bytesOf(4))).contains(bytesOf(4)); + assertThat(store.get(TestSegment.BAR, bytesOf(5))).isEmpty(); + assertThat(store.get(TestSegment.BAR, bytesOf(6))).isEmpty(); store.close(); } @@ -145,26 +158,24 @@ public void canRemoveThroughSegmentIteration() throws Exception { @Test public void canGetThroughSegmentIteration() throws Exception { - final SegmentedKeyValueStorage store = createSegmentedStore(); - final RocksDbSegmentIdentifier fooSegment = store.getSegmentIdentifierByName(TestSegment.FOO); - final RocksDbSegmentIdentifier barSegment = store.getSegmentIdentifierByName(TestSegment.BAR); - - final Transaction tx = store.startTransaction(); - tx.put(fooSegment, bytesOf(1), bytesOf(1)); - tx.put(fooSegment, bytesOf(2), bytesOf(2)); - tx.put(fooSegment, bytesOf(3), bytesOf(3)); - tx.put(barSegment, bytesOf(4), bytesOf(4)); - tx.put(barSegment, bytesOf(5), bytesOf(5)); - tx.put(barSegment, bytesOf(6), bytesOf(6)); + final SegmentedKeyValueStorage store = createSegmentedStore(); + + final SegmentedKeyValueStorageTransaction tx = store.startTransaction(); + tx.put(TestSegment.FOO, bytesOf(1), bytesOf(1)); + tx.put(TestSegment.FOO, bytesOf(2), bytesOf(2)); + tx.put(TestSegment.FOO, bytesOf(3), bytesOf(3)); + tx.put(TestSegment.BAR, bytesOf(4), bytesOf(4)); + tx.put(TestSegment.BAR, bytesOf(5), bytesOf(5)); + tx.put(TestSegment.BAR, bytesOf(6), bytesOf(6)); tx.commit(); final Set gotFromFoo = - store.getAllKeysThat(fooSegment, x -> Arrays.equals(x, bytesOf(3))); + store.getAllKeysThat(TestSegment.FOO, x -> Arrays.equals(x, bytesOf(3))); final Set gotFromBar = store.getAllKeysThat( - barSegment, x -> Arrays.equals(x, bytesOf(4)) || Arrays.equals(x, bytesOf(5))); + TestSegment.BAR, x -> Arrays.equals(x, bytesOf(4)) || Arrays.equals(x, bytesOf(5))); final Set gotEmpty = - store.getAllKeysThat(fooSegment, x -> Arrays.equals(x, bytesOf(0))); + store.getAllKeysThat(TestSegment.FOO, x -> Arrays.equals(x, bytesOf(0))); assertThat(gotFromFoo.size()).isEqualTo(1); assertThat(gotFromBar.size()).isEqualTo(2); @@ -180,7 +191,7 @@ public void canGetThroughSegmentIteration() throws Exception { public void dbShouldIgnoreExperimentalSegmentsIfNotExisted(@TempDir final Path testPath) throws Exception { // Create new db should ignore experimental column family - SegmentedKeyValueStorage store = + SegmentedKeyValueStorage store = createSegmentedStore( testPath, Arrays.asList(TestSegment.FOO, TestSegment.BAR, TestSegment.EXPERIMENTAL), @@ -194,10 +205,11 @@ public void dbShouldIgnoreExperimentalSegmentsIfNotExisted(@TempDir final Path t } @Test - public void dbShouldNotIgnoreExperimentalSegmentsIfExisted(@TempDir final Path testPath) + public void dbShouldNotIgnoreExperimentalSegmentsIfExisted(@TempDir final Path tempDir) throws Exception { + final Path testPath = tempDir.resolve("testdb"); // Create new db with experimental column family - SegmentedKeyValueStorage store = + SegmentedKeyValueStorage store = createSegmentedStore( testPath, Arrays.asList(TestSegment.FOO, TestSegment.BAR, TestSegment.EXPERIMENTAL), @@ -227,7 +239,7 @@ public void dbShouldNotIgnoreExperimentalSegmentsIfExisted(@TempDir final Path t public void dbWillBeBackwardIncompatibleAfterExperimentalSegmentsAreAdded( @TempDir final Path testPath) throws Exception { // Create new db should ignore experimental column family - SegmentedKeyValueStorage store = + SegmentedKeyValueStorage store = createSegmentedStore( testPath, Arrays.asList(TestSegment.FOO, TestSegment.BAR, TestSegment.EXPERIMENTAL), @@ -257,6 +269,79 @@ public void dbWillBeBackwardIncompatibleAfterExperimentalSegmentsAreAdded( } } + @Test + public void createStoreMustCreateMetrics() throws Exception { + // Prepare mocks + when(labelledMetricOperationTimerMock.labels(any())).thenReturn(operationTimerMock); + when(metricsSystemMock.createLabelledTimer( + eq(BesuMetricCategory.KVSTORE_ROCKSDB), anyString(), anyString(), any())) + .thenReturn(labelledMetricOperationTimerMock); + when(metricsSystemMock.createLabelledCounter( + eq(BesuMetricCategory.KVSTORE_ROCKSDB), anyString(), anyString(), any())) + .thenReturn(labelledMetricCounterMock); + // Prepare argument captors + final ArgumentCaptor labelledTimersMetricsNameArgs = + ArgumentCaptor.forClass(String.class); + final ArgumentCaptor labelledTimersHelpArgs = ArgumentCaptor.forClass(String.class); + final ArgumentCaptor labelledCountersMetricsNameArgs = + ArgumentCaptor.forClass(String.class); + final ArgumentCaptor labelledCountersHelpArgs = ArgumentCaptor.forClass(String.class); + final ArgumentCaptor longGaugesMetricsNameArgs = ArgumentCaptor.forClass(String.class); + final ArgumentCaptor longGaugesHelpArgs = ArgumentCaptor.forClass(String.class); + + // Actual call + + final SegmentedKeyValueStorage store = + createSegmentedStore( + folder, metricsSystemMock, List.of(TestSegment.FOO), List.of(TestSegment.EXPERIMENTAL)); + + KeyValueStorage keyValueStorage = new SegmentedKeyValueStorageAdapter(TestSegment.FOO, store); + + // Assertions + assertThat(keyValueStorage).isNotNull(); + verify(metricsSystemMock, times(4)) + .createLabelledTimer( + eq(BesuMetricCategory.KVSTORE_ROCKSDB), + labelledTimersMetricsNameArgs.capture(), + labelledTimersHelpArgs.capture(), + any()); + assertThat(labelledTimersMetricsNameArgs.getAllValues()) + .containsExactly( + "read_latency_seconds", + "remove_latency_seconds", + "write_latency_seconds", + "commit_latency_seconds"); + assertThat(labelledTimersHelpArgs.getAllValues()) + .containsExactly( + "Latency for read from RocksDB.", + "Latency of remove requests from RocksDB.", + "Latency for write to RocksDB.", + "Latency for commits to RocksDB."); + + verify(metricsSystemMock, times(2)) + .createLongGauge( + eq(BesuMetricCategory.KVSTORE_ROCKSDB), + longGaugesMetricsNameArgs.capture(), + longGaugesHelpArgs.capture(), + any(LongSupplier.class)); + assertThat(longGaugesMetricsNameArgs.getAllValues()) + .containsExactly("rocks_db_table_readers_memory_bytes", "rocks_db_files_size_bytes"); + assertThat(longGaugesHelpArgs.getAllValues()) + .containsExactly( + "Estimated memory used for RocksDB index and filter blocks in bytes", + "Estimated database size in bytes"); + + verify(metricsSystemMock) + .createLabelledCounter( + eq(BesuMetricCategory.KVSTORE_ROCKSDB), + labelledCountersMetricsNameArgs.capture(), + labelledCountersHelpArgs.capture(), + any()); + assertThat(labelledCountersMetricsNameArgs.getValue()).isEqualTo("rollback_count"); + assertThat(labelledCountersHelpArgs.getValue()) + .isEqualTo("Number of RocksDB transactions rolled back."); + } + public enum TestSegment implements SegmentIdentifier { FOO(new byte[] {1}), BAR(new byte[] {2}), @@ -294,16 +379,21 @@ public boolean containsStaticData() { } } - protected abstract SegmentedKeyValueStorage createSegmentedStore() - throws Exception; + protected abstract SegmentedKeyValueStorage createSegmentedStore() throws Exception; + + protected abstract SegmentedKeyValueStorage createSegmentedStore( + final Path path, + final List segments, + final List ignorableSegments); - protected abstract SegmentedKeyValueStorage createSegmentedStore( + protected abstract SegmentedKeyValueStorage createSegmentedStore( final Path path, + final MetricsSystem metricsSystem, final List segments, final List ignorableSegments); @Override protected KeyValueStorage createStore() throws Exception { - return new SnappableSegmentedKeyValueStorageAdapter<>(TestSegment.FOO, createSegmentedStore()); + return new SegmentedKeyValueStorageAdapter(TestSegment.FOO, createSegmentedStore()); } } diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBKeyValueStorageTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBKeyValueStorageTest.java deleted file mode 100644 index 78968873ecf..00000000000 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBKeyValueStorageTest.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright Hyperledger Besu Contributors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.plugin.services.storage.rocksdb.segmented; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.hyperledger.besu.kvstore.AbstractKeyValueStorageTest; -import org.hyperledger.besu.metrics.BesuMetricCategory; -import org.hyperledger.besu.metrics.ObservableMetricsSystem; -import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; -import org.hyperledger.besu.plugin.services.metrics.Counter; -import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; -import org.hyperledger.besu.plugin.services.metrics.OperationTimer; -import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; -import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory; -import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfiguration; -import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfigurationBuilder; -import org.hyperledger.besu.plugin.services.storage.rocksdb.unsegmented.RocksDBKeyValueStorage; - -import java.nio.file.Path; -import java.util.function.LongSupplier; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.io.TempDir; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class RocksDBKeyValueStorageTest extends AbstractKeyValueStorageTest { - - @Mock private ObservableMetricsSystem metricsSystemMock; - @Mock private LabelledMetric labelledMetricOperationTimerMock; - @Mock private LabelledMetric labelledMetricCounterMock; - @Mock private OperationTimer operationTimerMock; - @TempDir static Path folder; - - @Override - protected KeyValueStorage createStore() throws Exception { - return new RocksDBKeyValueStorage( - config(), new NoOpMetricsSystem(), RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); - } - - @Test - public void createStoreMustCreateMetrics() throws Exception { - // Prepare mocks - when(labelledMetricOperationTimerMock.labels(any())).thenReturn(operationTimerMock); - when(metricsSystemMock.createLabelledTimer( - eq(BesuMetricCategory.KVSTORE_ROCKSDB), anyString(), anyString(), any())) - .thenReturn(labelledMetricOperationTimerMock); - when(metricsSystemMock.createLabelledCounter( - eq(BesuMetricCategory.KVSTORE_ROCKSDB), anyString(), anyString(), any())) - .thenReturn(labelledMetricCounterMock); - // Prepare argument captors - final ArgumentCaptor labelledTimersMetricsNameArgs = - ArgumentCaptor.forClass(String.class); - final ArgumentCaptor labelledTimersHelpArgs = ArgumentCaptor.forClass(String.class); - final ArgumentCaptor labelledCountersMetricsNameArgs = - ArgumentCaptor.forClass(String.class); - final ArgumentCaptor labelledCountersHelpArgs = ArgumentCaptor.forClass(String.class); - final ArgumentCaptor longGaugesMetricsNameArgs = ArgumentCaptor.forClass(String.class); - final ArgumentCaptor longGaugesHelpArgs = ArgumentCaptor.forClass(String.class); - - // Actual call - final KeyValueStorage keyValueStorage = - new RocksDBKeyValueStorage( - config(), metricsSystemMock, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); - - // Assertions - assertThat(keyValueStorage).isNotNull(); - verify(metricsSystemMock, times(4)) - .createLabelledTimer( - eq(BesuMetricCategory.KVSTORE_ROCKSDB), - labelledTimersMetricsNameArgs.capture(), - labelledTimersHelpArgs.capture(), - any()); - assertThat(labelledTimersMetricsNameArgs.getAllValues()) - .containsExactly( - "read_latency_seconds", - "remove_latency_seconds", - "write_latency_seconds", - "commit_latency_seconds"); - assertThat(labelledTimersHelpArgs.getAllValues()) - .containsExactly( - "Latency for read from RocksDB.", - "Latency of remove requests from RocksDB.", - "Latency for write to RocksDB.", - "Latency for commits to RocksDB."); - - verify(metricsSystemMock, times(2)) - .createLongGauge( - eq(BesuMetricCategory.KVSTORE_ROCKSDB), - longGaugesMetricsNameArgs.capture(), - longGaugesHelpArgs.capture(), - any(LongSupplier.class)); - assertThat(longGaugesMetricsNameArgs.getAllValues()) - .containsExactly("rocks_db_table_readers_memory_bytes", "rocks_db_files_size_bytes"); - assertThat(longGaugesHelpArgs.getAllValues()) - .containsExactly( - "Estimated memory used for RocksDB index and filter blocks in bytes", - "Estimated database size in bytes"); - - verify(metricsSystemMock) - .createLabelledCounter( - eq(BesuMetricCategory.KVSTORE_ROCKSDB), - labelledCountersMetricsNameArgs.capture(), - labelledCountersHelpArgs.capture(), - any()); - assertThat(labelledCountersMetricsNameArgs.getValue()).isEqualTo("rollback_count"); - assertThat(labelledCountersHelpArgs.getValue()) - .isEqualTo("Number of RocksDB transactions rolled back."); - } - - private RocksDBConfiguration config() throws Exception { - return new RocksDBConfigurationBuilder().databaseDir(getTempSubFolder(folder)).build(); - } -} diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorageTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorageTest.java index d7d4e12da7d..bed64f58404 100644 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorageTest.java +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorageTest.java @@ -15,22 +15,25 @@ package org.hyperledger.besu.plugin.services.storage.rocksdb.segmented; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; +import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory; -import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbSegmentIdentifier; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfigurationBuilder; -import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorage; import java.nio.file.Path; import java.util.Arrays; import java.util.List; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) public class TransactionDBRocksDBColumnarKeyValueStorageTest extends RocksDBColumnarKeyValueStorageTest { @Override - protected SegmentedKeyValueStorage createSegmentedStore() - throws Exception { + protected SegmentedKeyValueStorage createSegmentedStore() throws Exception { return new TransactionDBRocksDBColumnarKeyValueStorage( new RocksDBConfigurationBuilder().databaseDir(getTempSubFolder(folder)).build(), Arrays.asList(TestSegment.FOO, TestSegment.BAR), @@ -40,15 +43,29 @@ protected SegmentedKeyValueStorage createSegmentedStor } @Override - protected SegmentedKeyValueStorage createSegmentedStore( + protected SegmentedKeyValueStorage createSegmentedStore( final Path path, final List segments, final List ignorableSegments) { return new TransactionDBRocksDBColumnarKeyValueStorage( - new RocksDBConfigurationBuilder().databaseDir(path).build(), + new RocksDBConfigurationBuilder().databaseDir(folder).build(), segments, ignorableSegments, new NoOpMetricsSystem(), RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); } + + @Override + protected SegmentedKeyValueStorage createSegmentedStore( + final Path path, + final MetricsSystem metricsSystem, + final List segments, + final List ignorableSegments) { + return new TransactionDBRocksDBColumnarKeyValueStorage( + new RocksDBConfigurationBuilder().databaseDir(path).build(), + segments, + ignorableSegments, + metricsSystem, + RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); + } } diff --git a/privacy-contracts/build.gradle b/privacy-contracts/build.gradle index 65401fd753b..33e3176ce05 100644 --- a/privacy-contracts/build.gradle +++ b/privacy-contracts/build.gradle @@ -15,9 +15,9 @@ jar { enabled = true } dependencies { - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-io' - implementation 'org.apache.tuweni:tuweni-toml' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-io' + implementation 'io.tmio:tuweni-toml' implementation 'org.web3j:abi' implementation 'org.web3j:besu' } diff --git a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/InMemoryKeyValueStorage.java b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/InMemoryKeyValueStorage.java index 643839ed8db..28e4436fe6e 100644 --- a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/InMemoryKeyValueStorage.java +++ b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/InMemoryKeyValueStorage.java @@ -14,235 +14,84 @@ */ package org.hyperledger.besu.services.kvstore; -import static java.util.stream.Collectors.toUnmodifiableSet; - -import org.hyperledger.besu.plugin.services.exception.StorageException; -import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; -import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction; -import org.hyperledger.besu.plugin.services.storage.SnappableKeyValueStorage; -import org.hyperledger.besu.plugin.services.storage.SnappedKeyValueStorage; +import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; import java.io.PrintStream; +import java.nio.charset.StandardCharsets; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Optional; -import java.util.Set; -import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.function.Predicate; -import java.util.stream.Stream; -import com.google.common.collect.ImmutableSet; -import org.apache.commons.lang3.tuple.Pair; import org.apache.tuweni.bytes.Bytes; -/** The In memory key value storage. */ -public class InMemoryKeyValueStorage - implements SnappedKeyValueStorage, SnappableKeyValueStorage, KeyValueStorage { +/** + * InMemoryKeyValueStorage is just a wrapper around a single segment instance of + * SegmentedInMemoryKeyValueStorage. + */ +public class InMemoryKeyValueStorage extends SegmentedKeyValueStorageAdapter { + + private static final SegmentIdentifier SEGMENT_IDENTIFIER = + new SegmentIdentifier() { + private static final String NAME = "SEGMENT_IDENTIFIER"; - /** protected access for the backing hash map. */ - protected final Map> hashValueStore; + @Override + public String getName() { + return NAME; + } + + @Override + public byte[] getId() { + return NAME.getBytes(StandardCharsets.UTF_8); + } + + @Override + public boolean containsStaticData() { + return false; + } + }; + + private static Map>> asSegmentMap( + final Map> initialMap) { + final Map>> segmentMap = new HashMap<>(); + segmentMap.put(SEGMENT_IDENTIFIER, initialMap); + return segmentMap; + } /** protected access to the rw lock. */ - protected final ReadWriteLock rwLock = new ReentrantReadWriteLock(); + protected final ReadWriteLock rwLock; /** Instantiates a new In memory key value storage. */ public InMemoryKeyValueStorage() { - this(new HashMap<>()); + this(SEGMENT_IDENTIFIER); } /** - * Instantiates a new In memory key value storage. + * Instantiates a new In memory key value storage with an initial map. * - * @param hashValueStore the hash value store + * @param initialMap the initial map */ - protected InMemoryKeyValueStorage(final Map> hashValueStore) { - this.hashValueStore = hashValueStore; - } - - @Override - public void clear() { - final Lock lock = rwLock.writeLock(); - lock.lock(); - try { - hashValueStore.clear(); - } finally { - lock.unlock(); - } - } - - @Override - public boolean containsKey(final byte[] key) throws StorageException { - return get(key).isPresent(); - } - - @Override - public Optional get(final byte[] key) throws StorageException { - final Lock lock = rwLock.readLock(); - lock.lock(); - try { - return hashValueStore.getOrDefault(Bytes.wrap(key), Optional.empty()); - } finally { - lock.unlock(); - } - } - - @Override - public Set getAllKeysThat(final Predicate returnCondition) { - return stream() - .filter(pair -> returnCondition.test(pair.getKey())) - .map(Pair::getKey) - .collect(toUnmodifiableSet()); - } - - @Override - public Set getAllValuesFromKeysThat(final Predicate returnCondition) { - return stream() - .filter(pair -> returnCondition.test(pair.getKey())) - .map(Pair::getValue) - .collect(toUnmodifiableSet()); - } - - @Override - public Stream> stream() { - final Lock lock = rwLock.readLock(); - lock.lock(); - try { - return ImmutableSet.copyOf(hashValueStore.entrySet()).stream() - .filter(bytesEntry -> bytesEntry.getValue().isPresent()) - .map( - bytesEntry -> - Pair.of(bytesEntry.getKey().toArrayUnsafe(), bytesEntry.getValue().get())); - } finally { - lock.unlock(); - } - } - - @Override - public Stream> streamFromKey(final byte[] startKey) { - return stream().filter(e -> Bytes.wrap(startKey).compareTo(Bytes.wrap(e.getKey())) <= 0); - } - - @Override - public Stream streamKeys() { - final Lock lock = rwLock.readLock(); - lock.lock(); - try { - return ImmutableSet.copyOf(hashValueStore.entrySet()).stream() - .map(bytesEntry -> bytesEntry.getKey().toArrayUnsafe()); - } finally { - lock.unlock(); - } - } - - @Override - public boolean tryDelete(final byte[] key) { - final Lock lock = rwLock.writeLock(); - if (lock.tryLock()) { - try { - hashValueStore.remove(Bytes.wrap(key)); - } finally { - lock.unlock(); - } - return true; - } - return false; - } - - @Override - public void close() {} - - @Override - public KeyValueStorageTransaction startTransaction() { - return new KeyValueStorageTransactionTransitionValidatorDecorator(new InMemoryTransaction()); - } - - @Override - public boolean isClosed() { - return false; + public InMemoryKeyValueStorage(final Map> initialMap) { + super(SEGMENT_IDENTIFIER, new SegmentedInMemoryKeyValueStorage(asSegmentMap(initialMap))); + rwLock = ((SegmentedInMemoryKeyValueStorage) storage).rwLock; } /** - * Key set. + * Instantiates a new In memory key value storage with a single segment identifier. * - * @return the set of keys + * @param segmentIdentifier the segment identifier */ - public Set keySet() { - return Set.copyOf(hashValueStore.keySet()); - } - - @Override - public SnappedKeyValueStorage takeSnapshot() { - return new InMemoryKeyValueStorage(new HashMap<>(hashValueStore)); - } - - @Override - public KeyValueStorageTransaction getSnapshotTransaction() { - return startTransaction(); - } - - /** In memory transaction. */ - public class InMemoryTransaction implements KeyValueStorageTransaction { - - /** protected access to updatedValues map for the transaction. */ - protected Map> updatedValues = new HashMap<>(); - /** protected access to deletedValues set for the transaction. */ - protected Set removedKeys = new HashSet<>(); - - @Override - public void put(final byte[] key, final byte[] value) { - updatedValues.put(Bytes.wrap(key), Optional.of(value)); - removedKeys.remove(Bytes.wrap(key)); - } - - @Override - public void remove(final byte[] key) { - removedKeys.add(Bytes.wrap(key)); - updatedValues.remove(Bytes.wrap(key)); - } - - @Override - public void commit() throws StorageException { - final Lock lock = rwLock.writeLock(); - lock.lock(); - try { - hashValueStore.putAll(updatedValues); - removedKeys.forEach(hashValueStore::remove); - updatedValues = null; - removedKeys = null; - } finally { - lock.unlock(); - } - } - - @Override - public void rollback() { - updatedValues.clear(); - removedKeys.clear(); - } + public InMemoryKeyValueStorage(final SegmentIdentifier segmentIdentifier) { + super(segmentIdentifier, new SegmentedInMemoryKeyValueStorage()); + rwLock = ((SegmentedInMemoryKeyValueStorage) storage).rwLock; } /** - * Dump. + * Dump the contents of the storage to the print stream. * - * @param ps the PrintStream where to report the dump + * @param ps the print stream. */ public void dump(final PrintStream ps) { - final Lock lock = rwLock.readLock(); - lock.lock(); - try { - ImmutableSet.copyOf(hashValueStore.entrySet()).stream() - .filter(bytesEntry -> bytesEntry.getValue().isPresent()) - .forEach( - entry -> - ps.printf( - " %s : %s%n", - entry.getKey().toHexString(), - Bytes.wrap(entry.getValue().get()).toHexString())); - } finally { - lock.unlock(); - } + ((SegmentedInMemoryKeyValueStorage) storage).dump(ps); } } diff --git a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/InMemoryStoragePlugin.java b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/InMemoryStoragePlugin.java index b516f5d5c90..648de893ff4 100644 --- a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/InMemoryStoragePlugin.java +++ b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/InMemoryStoragePlugin.java @@ -23,8 +23,10 @@ import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.plugin.services.storage.KeyValueStorageFactory; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.slf4j.Logger; @@ -35,8 +37,8 @@ public class InMemoryStoragePlugin implements BesuPlugin { private static final Logger LOG = LoggerFactory.getLogger(InMemoryStoragePlugin.class); private BesuContext context; - private MemoryKeyValueStorageFactory factory; - private MemoryKeyValueStorageFactory privacyFactory; + private InMemoryKeyValueStorageFactory factory; + private InMemoryKeyValueStorageFactory privacyFactory; @Override public void register(final BesuContext context) { @@ -73,8 +75,8 @@ public void stop() { private void createAndRegister(final StorageService service) { - factory = new MemoryKeyValueStorageFactory("memory"); - privacyFactory = new MemoryKeyValueStorageFactory("memory-privacy"); + factory = new InMemoryKeyValueStorageFactory("memory"); + privacyFactory = new InMemoryKeyValueStorageFactory("memory-privacy"); service.registerKeyValueStorage(factory); service.registerKeyValueStorage(privacyFactory); @@ -89,17 +91,18 @@ private void createFactoriesAndRegisterWithStorageService() { } /** The Memory key value storage factory. */ - public static class MemoryKeyValueStorageFactory implements KeyValueStorageFactory { + public static class InMemoryKeyValueStorageFactory implements KeyValueStorageFactory { private final String name; - private final Map storageMap = new HashMap<>(); + private final Map, SegmentedInMemoryKeyValueStorage> storageMap = + new HashMap<>(); /** * Instantiates a new Memory key value storage factory. * * @param name the name */ - public MemoryKeyValueStorageFactory(final String name) { + public InMemoryKeyValueStorageFactory(final String name) { this.name = name; } @@ -114,7 +117,21 @@ public KeyValueStorage create( final BesuConfiguration configuration, final MetricsSystem metricsSystem) throws StorageException { - return storageMap.computeIfAbsent(segment, __ -> new InMemoryKeyValueStorage()); + var kvStorage = + storageMap.computeIfAbsent( + List.of(segment), seg -> new SegmentedInMemoryKeyValueStorage(seg)); + return new SegmentedKeyValueStorageAdapter(segment, kvStorage); + } + + @Override + public SegmentedKeyValueStorage create( + final List segments, + final BesuConfiguration configuration, + final MetricsSystem metricsSystem) + throws StorageException { + var kvStorage = + storageMap.computeIfAbsent(segments, __ -> new SegmentedInMemoryKeyValueStorage()); + return kvStorage; } @Override @@ -122,6 +139,11 @@ public boolean isSegmentIsolationSupported() { return true; } + @Override + public boolean isSnapshotIsolationSupported() { + return true; + } + @Override public void close() { storageMap.clear(); diff --git a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/KeyValueStorageTransactionTransitionValidatorDecorator.java b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/KeyValueStorageTransactionValidatorDecorator.java similarity index 69% rename from services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/KeyValueStorageTransactionTransitionValidatorDecorator.java rename to services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/KeyValueStorageTransactionValidatorDecorator.java index cd488737ae3..f6f223692de 100644 --- a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/KeyValueStorageTransactionTransitionValidatorDecorator.java +++ b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/KeyValueStorageTransactionValidatorDecorator.java @@ -19,38 +19,45 @@ import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction; -/** The Key value storage transaction transition validator decorator. */ -public class KeyValueStorageTransactionTransitionValidatorDecorator - implements KeyValueStorageTransaction { +import java.util.function.Supplier; + +/** The Key value storage transaction validator decorator. */ +public class KeyValueStorageTransactionValidatorDecorator implements KeyValueStorageTransaction { private final KeyValueStorageTransaction transaction; + private final Supplier isClosed; private boolean active = true; /** * Instantiates a new Key value storage transaction transition validator decorator. * * @param toDecorate the to decorate + * @param isClosed supplier function to determine if the storage is closed */ - public KeyValueStorageTransactionTransitionValidatorDecorator( - final KeyValueStorageTransaction toDecorate) { + public KeyValueStorageTransactionValidatorDecorator( + final KeyValueStorageTransaction toDecorate, final Supplier isClosed) { + this.isClosed = isClosed; this.transaction = toDecorate; } @Override public void put(final byte[] key, final byte[] value) { checkState(active, "Cannot invoke put() on a completed transaction."); + checkState(!isClosed.get(), "Cannot invoke put() on a closed storage."); transaction.put(key, value); } @Override public void remove(final byte[] key) { checkState(active, "Cannot invoke remove() on a completed transaction."); + checkState(!isClosed.get(), "Cannot invoke remove() on a closed storage."); transaction.remove(key); } @Override public final void commit() throws StorageException { checkState(active, "Cannot commit a completed transaction."); + checkState(!isClosed.get(), "Cannot invoke commit() on a closed storage."); active = false; transaction.commit(); } @@ -58,6 +65,7 @@ public final void commit() throws StorageException { @Override public final void rollback() { checkState(active, "Cannot rollback a completed transaction."); + checkState(!isClosed.get(), "Cannot invoke rollback() on a closed storage."); active = false; transaction.rollback(); } diff --git a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/LayeredKeyValueStorage.java b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/LayeredKeyValueStorage.java index db0b23a3f0a..9a028becdf8 100644 --- a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/LayeredKeyValueStorage.java +++ b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/LayeredKeyValueStorage.java @@ -16,17 +16,19 @@ package org.hyperledger.besu.services.kvstore; import org.hyperledger.besu.plugin.services.exception.StorageException; -import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; -import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction; +import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction; import org.hyperledger.besu.plugin.services.storage.SnappedKeyValueStorage; +import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.Lock; +import java.util.stream.Collectors; import java.util.stream.Stream; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.Streams; import org.apache.commons.lang3.tuple.Pair; import org.apache.tuweni.bytes.Bytes; @@ -34,19 +36,19 @@ import org.slf4j.LoggerFactory; /** Key value storage which stores in memory all updates to a parent worldstate storage. */ -public class LayeredKeyValueStorage extends InMemoryKeyValueStorage +public class LayeredKeyValueStorage extends SegmentedInMemoryKeyValueStorage implements SnappedKeyValueStorage { private static final Logger LOG = LoggerFactory.getLogger(LayeredKeyValueStorage.class); - private final KeyValueStorage parent; + private final SegmentedKeyValueStorage parent; /** * Instantiates a new Layered key value storage. * * @param parent the parent key value storage for this layered storage. */ - public LayeredKeyValueStorage(final KeyValueStorage parent) { + public LayeredKeyValueStorage(final SegmentedKeyValueStorage parent) { this(new ConcurrentHashMap<>(), parent); } @@ -57,27 +59,31 @@ public LayeredKeyValueStorage(final KeyValueStorage parent) { * @param parent the parent key value storage for this layered storage. */ public LayeredKeyValueStorage( - final Map> map, final KeyValueStorage parent) { + final Map>> map, + final SegmentedKeyValueStorage parent) { super(map); this.parent = parent; } @Override - public boolean containsKey(final byte[] key) throws StorageException { - return get(key).isPresent(); + public boolean containsKey(final SegmentIdentifier segmentId, final byte[] key) + throws StorageException { + return get(segmentId, key).isPresent(); } @Override - public Optional get(final byte[] key) throws StorageException { + public Optional get(final SegmentIdentifier segmentId, final byte[] key) + throws StorageException { throwIfClosed(); final Lock lock = rwLock.readLock(); lock.lock(); try { Bytes wrapKey = Bytes.wrap(key); - final Optional foundKey = hashValueStore.get(wrapKey); + final Optional foundKey = + hashValueStore.computeIfAbsent(segmentId, __ -> new HashMap<>()).get(wrapKey); if (foundKey == null) { - return parent.get(key); + return parent.get(segmentId, key); } else { return foundKey; } @@ -87,14 +93,17 @@ public Optional get(final byte[] key) throws StorageException { } @Override - public Stream> stream() { + public Stream> stream(final SegmentIdentifier segmentId) { throwIfClosed(); final Lock lock = rwLock.readLock(); lock.lock(); try { - // immutable copy of our in memory store to use for streaming and filtering: - Map> ourLayerState = ImmutableMap.copyOf(hashValueStore); + // copy of our in memory store to use for streaming and filtering: + var ourLayerState = + Optional.ofNullable(hashValueStore.get(segmentId)) + .map(HashMap::new) + .orElse(new HashMap<>()); return Streams.concat( ourLayerState.entrySet().stream() @@ -104,26 +113,31 @@ public Stream> stream() { Pair.of(bytesEntry.getKey().toArrayUnsafe(), bytesEntry.getValue().get())) // since we are layered, concat a parent stream filtered by our map entries: , - parent.stream().filter(e -> !ourLayerState.containsKey(Bytes.of(e.getLeft())))); + parent.stream(segmentId).filter(e -> !ourLayerState.containsKey(Bytes.of(e.getLeft())))); } finally { lock.unlock(); } } @Override - public Stream> streamFromKey(final byte[] startKey) { - return stream().filter(e -> Bytes.wrap(startKey).compareTo(Bytes.wrap(e.getKey())) <= 0); + public Stream> streamFromKey( + final SegmentIdentifier segmentId, final byte[] startKey) { + return stream(segmentId) + .filter(e -> Bytes.wrap(startKey).compareTo(Bytes.wrap(e.getKey())) <= 0); } @Override - public Stream streamKeys() { + public Stream streamKeys(final SegmentIdentifier segmentId) { throwIfClosed(); final Lock lock = rwLock.readLock(); lock.lock(); try { - // immutable copy of our in memory store to use for streaming and filtering: - Map> ourLayerState = ImmutableMap.copyOf(hashValueStore); + // copy of our in memory store to use for streaming and filtering: + var ourLayerState = + Optional.ofNullable(hashValueStore.get(segmentId)) + .map(HashMap::new) + .orElse(new HashMap<>()); return Streams.concat( ourLayerState.entrySet().stream() @@ -131,7 +145,7 @@ public Stream streamKeys() { .map(bytesEntry -> bytesEntry.getKey().toArrayUnsafe()) // since we are layered, concat a parent stream filtered by our map entries: , - parent.streamKeys().filter(e -> !ourLayerState.containsKey(Bytes.of(e)))); + parent.streamKeys(segmentId).filter(e -> !ourLayerState.containsKey(Bytes.of(e)))); } finally { lock.unlock(); @@ -139,33 +153,50 @@ public Stream streamKeys() { } @Override - public boolean tryDelete(final byte[] key) { - hashValueStore.put(Bytes.wrap(key), Optional.empty()); + public boolean tryDelete(final SegmentIdentifier segmentId, final byte[] key) { + hashValueStore + .computeIfAbsent(segmentId, __ -> new HashMap<>()) + .put(Bytes.wrap(key), Optional.empty()); return true; } @Override - public KeyValueStorageTransaction startTransaction() { + public SegmentedKeyValueStorageTransaction startTransaction() { throwIfClosed(); - return new KeyValueStorageTransactionTransitionValidatorDecorator( - new InMemoryTransaction() { + return new SegmentedKeyValueStorageTransactionValidatorDecorator( + new SegmentedInMemoryTransaction() { @Override public void commit() throws StorageException { - final Lock lock = rwLock.writeLock(); lock.lock(); try { - hashValueStore.putAll(updatedValues); - removedKeys.forEach(key -> hashValueStore.put(key, Optional.empty())); - // put empty and not removed to not ask parent in case of deletion - updatedValues = null; - removedKeys = null; + updatedValues.entrySet().stream() + .forEach( + entry -> + hashValueStore + .computeIfAbsent(entry.getKey(), __ -> new HashMap<>()) + .putAll(entry.getValue())); + + // put empty rather than remove in order to not ask parent in case of deletion + removedKeys.entrySet().stream() + .forEach( + segmentEntry -> + hashValueStore + .computeIfAbsent(segmentEntry.getKey(), __ -> new HashMap<>()) + .putAll( + segmentEntry.getValue().stream() + .collect( + Collectors.toMap(key -> key, __ -> Optional.empty())))); + + updatedValues.clear(); + removedKeys.clear(); } finally { lock.unlock(); } } - }); + }, + this::isClosed); } @Override diff --git a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/LimitedInMemoryKeyValueStorage.java b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/LimitedInMemoryKeyValueStorage.java index c521d80bd8f..7ab04ec26e8 100644 --- a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/LimitedInMemoryKeyValueStorage.java +++ b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/LimitedInMemoryKeyValueStorage.java @@ -146,7 +146,8 @@ public boolean tryDelete(final byte[] key) { @Override public KeyValueStorageTransaction startTransaction() throws StorageException { - return new KeyValueStorageTransactionTransitionValidatorDecorator(new MemoryTransaction()); + return new KeyValueStorageTransactionValidatorDecorator( + new MemoryTransaction(), this::isClosed); } @Override diff --git a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedInMemoryKeyValueStorage.java b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedInMemoryKeyValueStorage.java new file mode 100644 index 00000000000..adc9a4c71dc --- /dev/null +++ b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedInMemoryKeyValueStorage.java @@ -0,0 +1,301 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.services.kvstore; + +import static java.util.stream.Collectors.toUnmodifiableSet; + +import org.hyperledger.besu.plugin.services.exception.StorageException; +import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction; +import org.hyperledger.besu.plugin.services.storage.SnappableKeyValueStorage; +import org.hyperledger.besu.plugin.services.storage.SnappedKeyValueStorage; + +import java.io.PrintStream; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.tuweni.bytes.Bytes; + +/** Segmented in memory key value storage. */ +public class SegmentedInMemoryKeyValueStorage + implements SnappedKeyValueStorage, SnappableKeyValueStorage, SegmentedKeyValueStorage { + /** protected access for the backing hash map. */ + final Map>> hashValueStore; + + /** protected access to the rw lock. */ + protected final ReadWriteLock rwLock = new ReentrantReadWriteLock(); + + /** Instantiates a new In memory key value storage. */ + public SegmentedInMemoryKeyValueStorage() { + this(new HashMap<>()); + } + + /** + * Instantiates a new In memory key value storage. + * + * @param hashValueStore the hash value store + */ + protected SegmentedInMemoryKeyValueStorage( + final Map>> hashValueStore) { + this.hashValueStore = hashValueStore; + } + + /** + * Instantiates a new In memory key value storage with specific set of segments. + * + * @param segments the segments to be used + */ + public SegmentedInMemoryKeyValueStorage(final List segments) { + this( + segments.stream() + .collect( + Collectors + .>>toMap( + s -> s, s -> new HashMap<>()))); + } + + @Override + public void clear(final SegmentIdentifier segmentIdentifier) { + final Lock lock = rwLock.writeLock(); + lock.lock(); + try { + Optional.ofNullable(hashValueStore.get(segmentIdentifier)).ifPresent(Map::clear); + } finally { + lock.unlock(); + } + } + + @Override + public boolean containsKey(final SegmentIdentifier segmentIdentifier, final byte[] key) + throws StorageException { + return get(segmentIdentifier, key).isPresent(); + } + + @Override + public Optional get(final SegmentIdentifier segmentIdentifier, final byte[] key) + throws StorageException { + final Lock lock = rwLock.readLock(); + lock.lock(); + try { + return hashValueStore + .computeIfAbsent(segmentIdentifier, s -> new HashMap<>()) + .getOrDefault(Bytes.wrap(key), Optional.empty()); + } finally { + lock.unlock(); + } + } + + @Override + public Set getAllKeysThat( + final SegmentIdentifier segmentIdentifier, final Predicate returnCondition) { + return stream(segmentIdentifier) + .filter(pair -> returnCondition.test(pair.getKey())) + .map(Pair::getKey) + .collect(toUnmodifiableSet()); + } + + @Override + public Set getAllValuesFromKeysThat( + final SegmentIdentifier segmentIdentifier, final Predicate returnCondition) { + return stream(segmentIdentifier) + .filter(pair -> returnCondition.test(pair.getKey())) + .map(Pair::getValue) + .collect(toUnmodifiableSet()); + } + + @Override + public Stream> stream(final SegmentIdentifier segmentIdentifier) { + final Lock lock = rwLock.readLock(); + lock.lock(); + try { + return ImmutableSet.copyOf( + hashValueStore.computeIfAbsent(segmentIdentifier, s -> new HashMap<>()).entrySet()) + .stream() + .filter(bytesEntry -> bytesEntry.getValue().isPresent()) + .map( + bytesEntry -> + Pair.of(bytesEntry.getKey().toArrayUnsafe(), bytesEntry.getValue().get())); + } finally { + lock.unlock(); + } + } + + @Override + public Stream> streamFromKey( + final SegmentIdentifier segmentIdentifier, final byte[] startKey) { + return stream(segmentIdentifier) + .filter(e -> Bytes.wrap(startKey).compareTo(Bytes.wrap(e.getKey())) <= 0); + } + + @Override + public Stream streamKeys(final SegmentIdentifier segmentIdentifier) { + final Lock lock = rwLock.readLock(); + lock.lock(); + try { + return ImmutableMap.copyOf( + hashValueStore.computeIfAbsent(segmentIdentifier, s -> new HashMap<>())) + .entrySet() + .stream() + .filter(bytesEntry -> bytesEntry.getValue().isPresent()) + .map(bytesEntry -> bytesEntry.getKey().toArrayUnsafe()); + } finally { + lock.unlock(); + } + } + + @Override + public boolean tryDelete(final SegmentIdentifier segmentIdentifier, final byte[] key) { + final Lock lock = rwLock.writeLock(); + if (lock.tryLock()) { + try { + Optional.ofNullable(hashValueStore.get(segmentIdentifier)) + .ifPresent(store -> store.remove(Bytes.wrap(key))); + } finally { + lock.unlock(); + } + return true; + } + return false; + } + + @Override + public void close() {} + + @Override + public SegmentedKeyValueStorageTransaction startTransaction() { + return new SegmentedKeyValueStorageTransactionValidatorDecorator( + new SegmentedInMemoryTransaction(), this::isClosed); + } + + @Override + public boolean isClosed() { + return false; + } + + @Override + public SegmentedInMemoryKeyValueStorage takeSnapshot() { + // need to clone the submaps also: + return new SegmentedInMemoryKeyValueStorage( + hashValueStore.entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> new HashMap<>(e.getValue())))); + } + + @Override + public SegmentedKeyValueStorageTransaction getSnapshotTransaction() { + return startTransaction(); + } + + /** In memory transaction. */ + public class SegmentedInMemoryTransaction implements SegmentedKeyValueStorageTransaction { + + /** protected access to updatedValues map for the transaction. */ + protected Map>> updatedValues = new HashMap<>(); + /** protected access to deletedValues set for the transaction. */ + protected Map> removedKeys = new HashMap<>(); + + @Override + public void put( + final SegmentIdentifier segmentIdentifier, final byte[] key, final byte[] value) { + updatedValues + .computeIfAbsent(segmentIdentifier, __ -> new HashMap<>()) + .put(Bytes.wrap(key), Optional.of(value)); + removedKeys.computeIfAbsent(segmentIdentifier, __ -> new HashSet<>()).remove(Bytes.wrap(key)); + } + + @Override + public void remove(final SegmentIdentifier segmentIdentifier, final byte[] key) { + removedKeys.computeIfAbsent(segmentIdentifier, __ -> new HashSet<>()).add(Bytes.wrap(key)); + updatedValues + .computeIfAbsent(segmentIdentifier, __ -> new HashMap<>()) + .remove(Bytes.wrap(key)); + } + + @Override + public void commit() throws StorageException { + final Lock lock = rwLock.writeLock(); + lock.lock(); + try { + updatedValues.entrySet().stream() + .forEach( + entry -> + hashValueStore + .computeIfAbsent(entry.getKey(), __ -> new HashMap<>()) + .putAll(entry.getValue())); + + removedKeys.entrySet().stream() + .forEach( + entry -> { + var keyset = + hashValueStore + .computeIfAbsent(entry.getKey(), __ -> new HashMap<>()) + .keySet(); + keyset.removeAll(entry.getValue()); + }); + + updatedValues.clear(); + removedKeys.clear(); + } finally { + lock.unlock(); + } + } + + @Override + public void rollback() { + updatedValues.clear(); + removedKeys.clear(); + } + } + + /** + * Dump the content of the store to the provided PrintStream. + * + * @param ps the PrintStream to dump the content to. + */ + public void dump(final PrintStream ps) { + final Lock lock = rwLock.readLock(); + lock.lock(); + try { + ImmutableSet.copyOf(hashValueStore.entrySet()).stream() + .forEach( + map -> { + ps.println("Segment: " + map.getKey().getName()); + map.getValue().entrySet().stream() + .filter(bytesEntry -> bytesEntry.getValue().isPresent()) + .forEach( + entry -> + ps.printf( + " %s : %s%n", + entry.getKey().toHexString(), + Bytes.wrap(entry.getValue().get()).toHexString())); + }); + } finally { + lock.unlock(); + } + } +} diff --git a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageAdapter.java b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageAdapter.java index 311d287a2f1..81a492624f2 100644 --- a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageAdapter.java +++ b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageAdapter.java @@ -18,6 +18,8 @@ import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction; import java.io.IOException; import java.util.Optional; @@ -29,80 +31,77 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** - * The type Segmented key value storage adapter. - * - * @param the type parameter - */ -public class SegmentedKeyValueStorageAdapter implements KeyValueStorage { +/** This class will adapt a SegmentedKeyValueStorage to a KeyValueStorage instance. */ +public class SegmentedKeyValueStorageAdapter implements KeyValueStorage { private static final Logger LOG = LoggerFactory.getLogger(SegmentedKeyValueStorageAdapter.class); - private final S segmentHandle; - private final SegmentedKeyValueStorage storage; + private final SegmentIdentifier segmentIdentifier; + /** The storage to wrap. */ + protected final SegmentedKeyValueStorage storage; /** - * Instantiates a new Segmented key value storage adapter. + * Instantiates a new Segmented key value storage adapter for a single segment. * - * @param segment the segment + * @param segmentIdentifier the segmentIdentifier to wrap as a KeyValueStorage * @param storage the storage */ public SegmentedKeyValueStorageAdapter( - final SegmentIdentifier segment, final SegmentedKeyValueStorage storage) { - segmentHandle = storage.getSegmentIdentifierByName(segment); + final SegmentIdentifier segmentIdentifier, final SegmentedKeyValueStorage storage) { + this.segmentIdentifier = segmentIdentifier; this.storage = storage; } @Override public void clear() { throwIfClosed(); - storage.clear(segmentHandle); + storage.clear(segmentIdentifier); } @Override public boolean containsKey(final byte[] key) throws StorageException { throwIfClosed(); - return storage.containsKey(segmentHandle, key); + return storage.containsKey(segmentIdentifier, key); } @Override public Optional get(final byte[] key) throws StorageException { throwIfClosed(); - return storage.get(segmentHandle, key); + return storage.get(segmentIdentifier, key); } @Override public Set getAllKeysThat(final Predicate returnCondition) { throwIfClosed(); - return storage.getAllKeysThat(segmentHandle, returnCondition); + return storage.getAllKeysThat(segmentIdentifier, returnCondition); } @Override public Set getAllValuesFromKeysThat(final Predicate returnCondition) { throwIfClosed(); - return storage.getAllValuesFromKeysThat(segmentHandle, returnCondition); + return storage.getAllValuesFromKeysThat(segmentIdentifier, returnCondition); } @Override public Stream> stream() { throwIfClosed(); - return storage.stream(segmentHandle); + return storage.stream(segmentIdentifier); } @Override public Stream> streamFromKey(final byte[] startKey) throws StorageException { - return storage.streamFromKey(segmentHandle, startKey); + return storage.streamFromKey(segmentIdentifier, startKey); } @Override public Stream streamKeys() { throwIfClosed(); - return storage.streamKeys(segmentHandle); + return storage.streamKeys(segmentIdentifier); } @Override public boolean tryDelete(final byte[] key) { throwIfClosed(); - return storage.tryDelete(segmentHandle, key); + return storage.tryDelete(segmentIdentifier, key); } @Override @@ -112,33 +111,7 @@ public void close() throws IOException { @Override public KeyValueStorageTransaction startTransaction() throws StorageException { - final SegmentedKeyValueStorage.Transaction transaction = storage.startTransaction(); - return new KeyValueStorageTransaction() { - - @Override - public void put(final byte[] key, final byte[] value) { - throwIfClosed(); - transaction.put(segmentHandle, key, value); - } - - @Override - public void remove(final byte[] key) { - throwIfClosed(); - transaction.remove(segmentHandle, key); - } - - @Override - public void commit() throws StorageException { - throwIfClosed(); - transaction.commit(); - } - - @Override - public void rollback() { - throwIfClosed(); - transaction.rollback(); - } - }; + return new KeyValueStorageTransactionAdapter(segmentIdentifier, storage); } @Override @@ -152,4 +125,42 @@ private void throwIfClosed() { throw new StorageException("Storage has been closed"); } } + + /** This class will adapt a SegmentedKeyValueStorageTransaction to a KeyValueStorageTransaction */ + public static class KeyValueStorageTransactionAdapter implements KeyValueStorageTransaction { + private final SegmentedKeyValueStorageTransaction segmentedTransaction; + private final SegmentIdentifier segmentIdentifier; + + /** + * Instantiates a new Key value storage transaction adapter. + * + * @param segmentIdentifier the segmentIdentifier to use for the wrapped transaction + * @param storage the storage + */ + public KeyValueStorageTransactionAdapter( + final SegmentIdentifier segmentIdentifier, final SegmentedKeyValueStorage storage) { + this.segmentedTransaction = storage.startTransaction(); + this.segmentIdentifier = segmentIdentifier; + } + + @Override + public void put(final byte[] key, final byte[] value) { + segmentedTransaction.put(segmentIdentifier, key, value); + } + + @Override + public void remove(final byte[] key) { + segmentedTransaction.remove(segmentIdentifier, key); + } + + @Override + public void commit() throws StorageException { + segmentedTransaction.commit(); + } + + @Override + public void rollback() { + segmentedTransaction.rollback(); + } + } } diff --git a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageTransactionTransitionValidatorDecorator.java b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageTransactionValidatorDecorator.java similarity index 64% rename from services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageTransactionTransitionValidatorDecorator.java rename to services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageTransactionValidatorDecorator.java index 53cacb13e1b..c026cd4efd1 100644 --- a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageTransactionTransitionValidatorDecorator.java +++ b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageTransactionValidatorDecorator.java @@ -1,5 +1,5 @@ /* - * Copyright ConsenSys AG. + * Copyright Hyperledger Besu Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -12,51 +12,49 @@ * * SPDX-License-Identifier: Apache-2.0 */ + package org.hyperledger.besu.services.kvstore; import static com.google.common.base.Preconditions.checkState; import org.hyperledger.besu.plugin.services.exception.StorageException; -import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorage.Transaction; +import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; +import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction; import java.util.function.Supplier; -/** - * The Segmented key value storage transaction transition validator decorator. - * - * @param the type parameter - */ -public class SegmentedKeyValueStorageTransactionTransitionValidatorDecorator - implements Transaction { +/** The Key value storage transaction validator decorator. */ +public class SegmentedKeyValueStorageTransactionValidatorDecorator + implements SegmentedKeyValueStorageTransaction { - private final Transaction transaction; + private final SegmentedKeyValueStorageTransaction transaction; private final Supplier isClosed; private boolean active = true; /** - * Instantiates a new Segmented key value storage transaction transition validator decorator. + * Instantiates a new Key value storage transaction transition validator decorator. * * @param toDecorate the to decorate - * @param isClosed supplier that returns true if the storage is closed + * @param isClosed supplier function to determine if the storage is closed */ - public SegmentedKeyValueStorageTransactionTransitionValidatorDecorator( - final Transaction toDecorate, final Supplier isClosed) { - this.transaction = toDecorate; + public SegmentedKeyValueStorageTransactionValidatorDecorator( + final SegmentedKeyValueStorageTransaction toDecorate, final Supplier isClosed) { this.isClosed = isClosed; + this.transaction = toDecorate; } @Override - public final void put(final S segment, final byte[] key, final byte[] value) { + public void put(final SegmentIdentifier segmentId, final byte[] key, final byte[] value) { checkState(active, "Cannot invoke put() on a completed transaction."); checkState(!isClosed.get(), "Cannot invoke put() on a closed storage."); - transaction.put(segment, key, value); + transaction.put(segmentId, key, value); } @Override - public final void remove(final S segment, final byte[] key) { + public void remove(final SegmentIdentifier segmentId, final byte[] key) { checkState(active, "Cannot invoke remove() on a completed transaction."); checkState(!isClosed.get(), "Cannot invoke remove() on a closed storage."); - transaction.remove(segment, key); + transaction.remove(segmentId, key); } @Override diff --git a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SnappableSegmentedKeyValueStorageAdapter.java b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SnappableSegmentedKeyValueStorageAdapter.java deleted file mode 100644 index 941cea0ebfe..00000000000 --- a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SnappableSegmentedKeyValueStorageAdapter.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.services.kvstore; - -import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; -import org.hyperledger.besu.plugin.services.storage.SnappableKeyValueStorage; -import org.hyperledger.besu.plugin.services.storage.SnappedKeyValueStorage; - -import java.util.function.Supplier; - -/** - * The type Segmented key value storage adapter. - * - * @param the type parameter - */ -public class SnappableSegmentedKeyValueStorageAdapter extends SegmentedKeyValueStorageAdapter - implements SnappableKeyValueStorage { - private final Supplier snapshotSupplier; - - /** - * Instantiates a new Segmented key value storage adapter. - * - * @param segment the segment - * @param storage the storage - */ - public SnappableSegmentedKeyValueStorageAdapter( - final SegmentIdentifier segment, final SegmentedKeyValueStorage storage) { - this( - segment, - storage, - () -> { - throw new UnsupportedOperationException("Snapshot not supported"); - }); - } - - /** - * Instantiates a new Segmented key value storage adapter. - * - * @param segment the segment - * @param storage the storage - * @param snapshotSupplier the snapshot supplier - */ - public SnappableSegmentedKeyValueStorageAdapter( - final SegmentIdentifier segment, - final SegmentedKeyValueStorage storage, - final Supplier snapshotSupplier) { - super(segment, storage); - this.snapshotSupplier = snapshotSupplier; - } - - @Override - public SnappedKeyValueStorage takeSnapshot() { - return snapshotSupplier.get(); - } -} diff --git a/services/tasks/build.gradle b/services/tasks/build.gradle index 66784412dc8..5cfa2411f39 100644 --- a/services/tasks/build.gradle +++ b/services/tasks/build.gradle @@ -38,7 +38,7 @@ dependencies { implementation 'com.google.guava:guava' implementation 'io.vertx:vertx-core' - implementation 'org.apache.tuweni:tuweni-bytes' + implementation 'io.tmio:tuweni-bytes' testImplementation 'org.assertj:assertj-core' testImplementation 'org.junit.jupiter:junit-jupiter' diff --git a/testutil/build.gradle b/testutil/build.gradle index f235bb054f0..78cf879aca4 100644 --- a/testutil/build.gradle +++ b/testutil/build.gradle @@ -37,9 +37,9 @@ dependencies { implementation 'com.squareup.okhttp3:okhttp' implementation 'io.vertx:vertx-core' implementation 'org.junit.jupiter:junit-jupiter' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.apache.tuweni:tuweni-io' - implementation 'org.apache.tuweni:tuweni-toml' + implementation 'io.tmio:tuweni-bytes' + implementation 'io.tmio:tuweni-io' + implementation 'io.tmio:tuweni-toml' implementation 'org.assertj:assertj-core' implementation 'org.mockito:mockito-core' implementation 'org.web3j:core' diff --git a/util/src/main/java/org/hyperledger/besu/util/LogConfigurator.java b/util/src/main/java/org/hyperledger/besu/util/LogConfigurator.java index b0ca0bcd46b..9b862f6da3e 100644 --- a/util/src/main/java/org/hyperledger/besu/util/LogConfigurator.java +++ b/util/src/main/java/org/hyperledger/besu/util/LogConfigurator.java @@ -16,6 +16,8 @@ import java.util.NoSuchElementException; +import org.slf4j.LoggerFactory; + /** The library independent logger configurator util. */ @SuppressWarnings("CatchAndPrintStackTrace") public interface LogConfigurator { @@ -28,6 +30,8 @@ public interface LogConfigurator { */ static void setLevel(final String parentLogger, final String level) { try { + // ensure we have at least one log context, to load configs + LoggerFactory.getLogger(LogConfigurator.class); Log4j2ConfiguratorUtil.setAllLevels(parentLogger, level); } catch (NoClassDefFoundError | ClassCastException | NoSuchElementException e) { // This is expected when Log4j support is not in the classpath, so ignore